Websites12 min read

Core Web Vitals + INP 2026: optimizing for African 3G (Lagos, Dakar, Abidjan)

Mohamed Bah·Fondateur, Kolonell
May 9, 2026
Share:
Core Web Vitals + INP 2026: optimizing for African 3G (Lagos, Dakar, Abidjan)

Core Web Vitals + INP 2026: optimizing for African 3G (Lagos, Dakar, Abidjan)

Websites

Google replaced FID (First Input Delay) with INP (Interaction to Next Paint) in March 2024. On fiber PC, INP <200ms is trivial. On 3G + low-end Android (Itel, Tecno, Infinix popular in West Africa), it's the #1 web performance challenge of 2026.

TL;DR

- 2026 Core Web Vitals: LCP <2.5s, INP <200ms, CLS <0.1.

- On African 3G + Itel A57: non-optimized sites yield INP 600-1200ms.

- 5 levers: aggressive code-splitting, partial hydration, JS-free transitions, input debouncing, web workers for compute.

African context

Field conditions May 2026:

  • 35-50% visitors on 3G (Senegal, CI, CM, NG outside Lagos)
  • 60-70% Android <4GB RAM
  • Itel A57, Tecno Spark 8, Infinix Smart 6 = reference devices
  • But: 25-30% visits on urban 4G + fixed WiFi

Optimizing for the median = unacceptable in this context. Optimize for P75 (3G + low-end) = real quality.

Measuring INP

In prod via Web Vitals

`tsx

'use client';

import { useEffect } from 'react';

import { onINP, onLCP, onCLS } from 'web-vitals/attribution';

export function WebVitals() {

useEffect(() => {

onINP(({ value, attribution, id }) => {

sendToAnalytics({ name: 'INP', value, id, attribution });

});

onLCP(({ value, attribution }) => {

sendToAnalytics({ name: 'LCP', value, attribution });

});

onCLS(({ value, attribution }) => {

sendToAnalytics({ name: 'CLS', value, attribution });

});

}, []);

return null;

}

`

In CI via Lighthouse + WebPageTest

`yaml

  • name: Run Lighthouse mobile

uses: treosh/lighthouse-ci-action@v10

with:

urls: |

https://staging.kolonell.com/

https://staging.kolonell.com/services

configPath: .lighthouserc.json

uploadArtifacts: true

`

.lighthouserc.json set to mobile with 3G Slow throttling.

The 5 concrete levers

Lever 1 — Aggressive code-splitting

Initial bundle <100KB JS gzipped for 3G.

`tsx

// BAD: load everything at once

import { Charts } from 'big-charts-lib';

import { PdfViewer } from 'pdf-viewer';

// GOOD: dynamic imports

import dynamic from 'next/dynamic';

const Charts = dynamic(() => import('big-charts-lib').then(m => m.Charts), {

ssr: false,

loading: () => ,

});

const PdfViewer = dynamic(() => import('pdf-viewer'), { ssr: false });

`

Use @next/bundle-analyzer.

Lever 2 — Reduce main-thread blocking

On Itel A57, a 10,000-item for loop blocks the UI 800ms+.

`ts

// BAD: blocks main thread

function processOrders(orders: Order[]) {

return orders.map(o => expensiveCompute(o));

}

// GOOD: Web Worker

// app/workers/order-processor.ts

self.onmessage = (e: MessageEvent) => {

const result = e.data.map(o => expensiveCompute(o));

self.postMessage(result);

};

const worker = new Worker(new URL('./workers/order-processor.ts', import.meta.url));

worker.postMessage(orders);

worker.onmessage = (e) => setProcessed(e.data);

`

Lever 3 — Selective hydration

With Next.js 14 + React Server Components, most of the component stays server. Only interactive code hydrates.

`tsx

// Server Component (default in app/)

export default function ServiceCard({ service }) {

return (

{service.name}

{service.description}

{/* Client */}

);

}

Need a professional website?

Kolonell builds websites that attract clients, optimized for the Sénégalese market. Free quote in 2 minutes.

// Client Component (limited interactivity)

'use client';

export function BookingButton({ serviceId }) {

return ;

}

`

Lever 4 — Input debouncing

A live search querying every keystroke kills INP.

`tsx

// BAD

fetchResults(e.target.value)} />

// GOOD

import { useDebouncedCallback } from 'use-debounce';

const debounced = useDebouncedCallback(fetchResults, 300);

debounced(e.target.value)} />

`

Lever 5 — CSS-only transitions

Prefer CSS transitions to JS for animations.

`css

.menu {

transform: translateX(-100%);

transition: transform 200ms ease-out;

}

.menu.open {

transform: translateX(0);

}

`

`ts

// BAD: framerate-dependent JS anim

function animate(el, targetX) {

let x = -300;

const id = setInterval(() => {

x += 5;

el.style.transform = translateX(${x}px);

if (x >= targetX) clearInterval(id);

}, 16);

}

`

LCP: optimize the main image

LCP is typically the hero image or title. Optimize:

`tsx

import Image from 'next/image';

import hero from '@/public/hero.webp';

src={hero}

alt="Welcome"

priority

sizes="100vw"

placeholder="blur"

/>

`

priority on the first ATF image only. Not on all, otherwise counterproductive preloading.

CLS: avoid shifts

CLS comes from sizeless images, late fonts, async ads.

`tsx

// BAD

// GOOD

// Or Next/Image which reserves space

...

`

Font:

`ts

import { Inter } from 'next/font/google';

const inter = Inter({

subsets: ['latin'],

display: 'swap', // no FOUT

});

`

Real case — Senegal Presidency site (2026 redesign)

Before optimization (3G Slow, Itel A57):

  • LCP: 7.2s
  • INP: 980ms
  • CLS: 0.18
  • Lighthouse Mobile score: 31

After (3 weeks of work):

  • LCP: 2.1s
  • INP: 178ms
  • CLS: 0.05
  • Lighthouse Mobile score: 94

Traffic: +28% over 6 months thanks to Core Web Vitals SEO boost.

FAQ

Q: Should I aim for INP <100ms?

A: 200ms is Google's "Good" threshold. <100ms is exceptional and expensive on 3G Africa. Targeting 200ms is rational.

Q: Do Server Components reduce INP?

A: Yes significantly, by reducing client JS. Combined with SSR streaming, it changes everything.

Q: Cloudflare Workers or Vercel Edge help?

A: Yes for LCP/TTFB (lower latency). For INP which is main-thread-bound, edge doesn't help — code-splitting and Workers do.

Conclusion

Core Web Vitals 2026 are no longer SEO nice-to-haves. On 3G Africa, they're the difference between a used site and one abandoned mid-load. 3 weeks of targeted optimization push a site from "31/100" Lighthouse to "94/100" — immediate ROI on traffic, conversions, and Search Console scoring.

Tags:#Core Web Vitals#INP#Performance#3G#Africa#Lighthouse
Share:

Mohamed Bah

Fondateur, Kolonell

Passionate about digital and entrepreneurship in Africa, Mohamed has been helping Sénégalese businesses with their digital transformation since 2020. Founder of Kolonell, he believes every SME deserves a professional and accessible online présence.