How to Build a Low-Bandwidth Web App That Works on 2G in Africa
A user in Accra opens your app on a crowded MTN network at 8 a.m. Your JavaScript bundle is 1.2 MB. Your hero image is an unoptimized 900 KB PNG. The app never finishes loading — and that user never comes back.
This is not a hypothetical. Across West Africa, a significant portion of mobile users connect at effective speeds below 1 Mbps, especially during peak hours or in peri-urban areas. If your web app was built and tested on a fiber connection in a co-working space, you have almost certainly shipped something that fails silently for a large slice of your intended audience.
The good news: building for low bandwidth is engineering discipline, not magic. Here is a practical playbook.
Set a Real Performance Budget Before You Write a Line of Code
A performance budget is a hard ceiling on what your app is allowed to cost the user in bytes and time. For a 2G target (roughly 250–400 Kbps effective throughput, with 300–1000 ms latency), reasonable starting budgets look like this:
- Total page weight on first load: under 200 KB (compressed, over the wire)
- Time to Interactive (TTI): under 8 seconds on a simulated 3G slow connection in Chrome DevTools
- JavaScript bundle (parsed + executed): under 80 KB gzipped
- Largest Contentful Paint (LCP) asset: under 50 KB
These numbers will feel aggressive if you are used to building for broadband. That is the point. Treat a budget violation the same way you treat a failing test — it blocks the merge.
Compress and Serve Assets Intelligently
Images: The Biggest Win Available
Images routinely account for 60–80% of page weight on media-heavy sites. Three changes make an outsized difference:
- Convert to WebP or AVIF. WebP is typically 30–40% smaller than JPEG at equivalent quality. AVIF is smaller still, though browser support in older Android WebViews is still catching up — serve it with a
<picture>fallback. - Implement responsive images. Use
srcsetandsizesso a 320 px screen never downloads a 1200 px image. - Lazy-load below-the-fold images. The native
loading="lazy"attribute is now supported across modern browsers and costs you nothing to add.
<picture>
<source srcset="hero.avif" type="image/avif" />
<source srcset="hero.webp" type="image/webp" />
<img
src="hero.jpg"
alt="Dashboard overview"
loading="lazy"
width="800"
height="450"
/>
</picture>
JavaScript: Ship Less, Load Later
Tree-shake your bundles rigorously. Use dynamic import() to split routes so users only download code for the screen they are actually on. Libraries like Lodash and Moment.js are notorious for bloating bundles — audit your node_modules with a tool like bundlephobia or webpack-bundle-analyzer before every significant release.
Enable Brotli compression on your server or CDN. Brotli consistently outperforms gzip by 15–25% on JavaScript and HTML payloads.
Build Offline-First with Service Workers
A standard web app on a 2G connection does not just load slowly — it fails entirely when the signal drops mid-request, which happens constantly on mobile networks in high-density urban areas. The fix is to architect for offline from the start, not as an afterthought.
Service Workers act as a programmable network proxy sitting between your app and the network. A well-designed caching strategy means returning users load your app shell instantly from cache, even with zero connectivity.
Recommended Caching Strategy by Asset Type
| Asset Type | Strategy | Rationale |
|---|---|---|
| App shell (HTML, CSS, core JS) | Cache-first | Never changes between deploys |
| API responses | Stale-while-revalidate | Show cached data, refresh in background |
| User-uploaded images | Network-first with cache fallback | Freshness matters, but fallback beats blank |
| Large static assets (fonts) | Cache-first with long TTL | Fonts never change |
Use Workbox (by Google) to generate your Service Worker rather than writing raw cache logic by hand. It handles edge cases — like cache invalidation on deploy — that are easy to get wrong manually.
One critical UX detail: always surface an offline indicator to the user. A silent failure feels like a broken app. A clear "You are offline — showing cached data" message feels like a thoughtful one.
Design UX for Intermittent Connectivity
Performance optimization is not purely a back-end concern. The way you design interactions directly affects perceived performance on slow networks.
- Optimistic UI updates. When a user submits a form, update the interface immediately and sync to the server in the background. Do not make them wait for a round-trip confirmation on every tap.
- Skeleton screens over spinners. Skeleton loaders communicate structure and progress. Spinners communicate nothing except "waiting," which feels longer.
- Paginate and virtualize long lists. Rendering 500 rows of data at once on a low-end Android device will freeze the UI thread. Load 20 rows, then fetch more on scroll.
- Inline critical CSS. Render-blocking stylesheets delay paint. Inline the CSS needed for above-the-fold content directly in
<head>and load the rest asynchronously.
Test on the Actual Network, Not a Simulation
Chrome DevTools network throttling is a starting point, not a finish line. Real 2G connections have asymmetric latency spikes, packet loss, and reconnection delays that a clean throttle setting does not capture.
The most reliable approach: keep an inexpensive Android device (a Tecno or Infinix entry-level model, both widely used across Ghana and Nigeria) on a physical SIM card with a data bundle. Test on it. What feels fast on your MacBook and "simulated 3G" will often still feel broken on that device at 9 a.m. in a busy market.
Use Lighthouse in CI to enforce your performance budget automatically. A score below your threshold should block a production deploy.
Why This Matters for Your Project
If you are building a SaaS product, fintech app, or consumer platform targeting users in Ghana, Nigeria, Kenya, or anywhere across the continent, low-bandwidth performance is a direct revenue variable — not a nice-to-have. Every second of load time you eliminate is a percentage point of bounce rate you recover. Building offline-first with Service Workers, compressing aggressively, and designing for intermittent connectivity is how you build software that actually works for the market you are claiming to serve. The techniques above are not exotic — they are just engineering priorities applied to the right constraints.





