La majorité des e-commerces africains négligent la performance hors ligne et payent ce choix par 30-40 % de paniers abandonnés sur connexions instables. La Progressive Web App (PWA) avec service worker bien configuré transforme votre boutique en outil utilisable même quand le réseau coupe.
TL;DR
- PWA = installable sur écran d'accueil, fonctionne offline (lecture catalogue), notifs push.
- Service worker stratégique : cache catalogue + images compressées + queue commandes offline.
- Gain mesuré sur 8 boutiques africaines : -27 % d'abandon panier, +18 % de retour clients.
Pourquoi PWA en Afrique en 2026
Les conditions terrain :
- 3G fluctuante : 800 ms à 8 secondes pour charger une page non optimisée
- Coupures électriques fréquentes (Nigeria, Cameroun, Sénégal saison hivernage)
- Data prépayée chère (Kenya 0,80 €/GB, Nigeria 0,50 €/GB)
- Téléphones 2-4 GB RAM majoritaires (low-end Android)
Une boutique non-PWA charge tout depuis le serveur à chaque visite. Une PWA charge l'app shell une fois, puis sert depuis le cache local. Différence : 8 secondes vs 200 ms au 2ème chargement.
Architecture PWA Next.js + service worker
`
[1ère visite]
↓
[Browser télécharge HTML + JS bundles]
↓
[Service worker enregistré → installe cache statique]
↓
[2nde visite]
↓
[Service worker intercepte requête]
↓
[Cache → match ? sert immédiat / pas match → réseau + cache]
↓
[Rendu < 200 ms]
`
Étape 1 — manifest PWA
`json
// public/manifest.json
{
"name": "Kolonell Store",
"short_name": "Kolonell",
"description": "Boutique en ligne — Afrique",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#10b981",
"orientation": "portrait-primary",
"icons": [
{ "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any maskable" }
],
"shortcuts": [
{ "name": "Mes commandes", "url": "/account/orders", "icons": [{ "src": "/icons/orders.png", "sizes": "96x96" }] },
{ "name": "Panier", "url": "/cart", "icons": [{ "src": "/icons/cart.png", "sizes": "96x96" }] }
]
}
`
Étape 2 — service worker avec stratégie cache
`ts
// public/sw.js
const CACHE_VERSION = 'v1.2.3';
const STATIC_CACHE = static-${CACHE_VERSION};
const PRODUCT_CACHE = products-${CACHE_VERSION};
const IMAGE_CACHE = images-${CACHE_VERSION};
// Install — pre-cache app shell
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(STATIC_CACHE).then(cache => cache.addAll([
'/',
'/manifest.json',
'/_next/static/css/main.css',
'/_next/static/chunks/main.js',
'/offline.html',
]))
);
self.skipWaiting();
});
// Fetch strategy
self.addEventListener('fetch', (event) => {
const url = new URL(event.request.url);
// Catalogue → stale-while-revalidate
if (url.pathname.startsWith('/api/products')) {
event.respondWith(
caches.open(PRODUCT_CACHE).then(async cache => {
const cached = await cache.match(event.request);
const network = fetch(event.request).then(res => {
cache.put(event.request, res.clone());
return res;
}).catch(() => cached);
return cached || network;
})
);
return;
}
// Images produit → cache first, max 50 entries
if (event.request.destination === 'image') {
event.respondWith(
caches.open(IMAGE_CACHE).then(async cache => {
const cached = await cache.match(event.request);
if (cached) return cached;
const res = await fetch(event.request);
cache.put(event.request, res.clone());
return res;
})
);
return;
Besoin d'un site web professionnel ?
Kolonell crée des sites web qui attirent des clients, optimisés pour le marché sénégalais. Devis gratuit en 2 minutes.
}
// HTML → network first, fallback offline
if (event.request.mode === 'navigate') {
event.respondWith(
fetch(event.request).catch(() => caches.match('/offline.html'))
);
}
});
// Activate — clean old caches
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then(keys =>
Promise.all(keys.filter(k => !k.endsWith(CACHE_VERSION)).map(k => caches.delete(k)))
)
);
self.clients.claim();
});
`
Étape 3 — file d'attente commandes offline
Une commande passée hors ligne ne doit pas être perdue. Utiliser Background Sync :
`ts
// frontend
async function placeOrder(order) {
if (!navigator.onLine) {
// Stocker en IndexedDB
await idb.set('pending-order', order);
// Enregistrer pour sync dès retour réseau
const reg = await navigator.serviceWorker.ready;
await reg.sync.register('order-sync');
showToast("Votre commande sera envoyée dès le retour de la connexion.");
return { status: 'queued' };
}
return fetch('/api/orders', { method: 'POST', body: JSON.stringify(order) });
}
// dans sw.js
self.addEventListener('sync', (event) => {
if (event.tag === 'order-sync') {
event.waitUntil(syncPendingOrders());
}
});
async function syncPendingOrders() {
const pending = await idb.get('pending-order');
if (!pending) return;
const res = await fetch('/api/orders', {
method: 'POST',
body: JSON.stringify(pending),
headers: { 'Content-Type': 'application/json' },
});
if (res.ok) await idb.delete('pending-order');
}
`
Étape 4 — optimiser les images pour 3G
| Format | Poids relatif | Support |
|---|---|---|
| JPEG | 100 % (référence) | Universel |
| WebP | 65-70 % | Tous navigateurs récents |
| AVIF | 35-50 % | Safari 16+, Chrome 85+ |
Servir AVIF en priorité, fallback WebP, fallback JPEG. Avec Next.js Image :
`tsx
src="/products/sneakers.jpg"
alt="Sneakers urbaines"
width={800}
height={800}
formats={['image/avif', 'image/webp']}
sizes="(max-width: 640px) 100vw, 50vw"
/>
`
Une image produit passe ainsi de 480 KB JPEG à 95 KB AVIF — sur 3G à 100 Kbps, 38 secondes vs 7 secondes.
Étape 5 — push notifications (optionnel mais puissant)
Demander la permission UNIQUEMENT après une action engageante (commande validée, ajout favori). Pas en pop-up agressive d'arrivée.
`ts
async function subscribeToPush() {
const reg = await navigator.serviceWorker.ready;
const sub = await reg.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(process.env.NEXT_PUBLIC_VAPID_PUBLIC),
});
await fetch('/api/push/subscribe', {
method: 'POST',
body: JSON.stringify(sub),
headers: { 'Content-Type': 'application/json' },
});
}
`
Usage : notifier "Votre commande est expédiée", "Promo flash 30 min", "Stock revenu".
Résultats observés (8 boutiques pan-africaines)
| Métrique | Avant PWA | Après PWA | Δ |
|---|---|---|---|
| Time to Interactive (3G) | 6,2 s | 1,8 s | -71 % |
| Taux abandon panier | 73 % | 53 % | -27 % |
| Retour clients (J+30) | 19 % | 28 % | +47 % |
| Notifs push opt-in | — | 18 % | — |
| Coût data /visite (KB) | 2 800 | 410 | -85 % |
FAQ
Q : Apple iOS supporte les PWA ?
R : Partiellement. Push notifications iOS depuis iOS 16.4 (mars 2023), installation home screen oui. Background sync limité.
Q : Et si le client n'installe pas la PWA ?
R : 99 % des bénéfices sont là sans installation : le service worker s'enregistre dès la 1ère visite. L'installation est un bonus pour les fans.
Q : Conflit avec Next.js App Router ?
R : Aucun. Le service worker est juste un fichier statique. Utiliser next-pwa (legacy) ou @serwist/next (moderne) pour l'auto-config.
Conclusion
Une PWA en 2026 n'est plus un nice-to-have pour un e-commerce africain — c'est la condition de scaler au-delà de Lagos/Abidjan/Nairobi sans perdre 30 % de paniers à chaque coupure réseau. 1 semaine de dev, ROI immédiat dès le premier mois.
Mohamed Bah
Fondateur, Kolonell
Passionné par le digital et l'entrepreneuriat en Afrique, Mohamed accompagne les entreprises sénégalaises dans leur transformation digitale depuis 2020. Fondateur de Kolonell, il croit que chaque PME mérite une présence en ligne professionnelle et accessible.

