Skip to content
FeaturesPricingAffiliateBlogHelpAboutContact
Get StartedSign In
Back to Blog
guides2026-10-057 min read

QR Menu CDN Optimization: 0.8s Loading on Weak 4G in Rural Areas

A coastal restaurant in Izmir Karaburun went from 9.2s to 0.8s LCP on weak 4G using Cloudflare Workers, Brotli, HTTP/3 and AVIF. Full playbook.

th

thMenu Team

thmenu.com

A seafood restaurant on the Karaburun peninsula opened a ticket mid-season: "the menu won't load, customers walk out." Vodafone 4G measured 1.4 Mbps RTT 380 ms, and Lighthouse showed an LCP of 9.2 seconds. The target was concrete: LCP under 1 second, with the waiter-call button tappable within 1.5 s.

Edge Stack: Workers + HTTP/3 + Brotli 11

Layer one — serve rendered HTML straight from Cloudflare Workers KV cache instead of round-tripping to Next.js SSR. We hit 38 ms TTFB at the edge. HTTP/3 (QUIC) survives 4G packet loss without re-handshaking: H/2 took 1.6 s to negotiate; H/3 finishes in 240 ms.

Precompressed assets at Brotli level 11: HTML 22 KB → 6 KB, CSS 41 KB → 9 KB. Brotli ships 34% fewer bytes than gzip on average. Cloudflare Pages enables it, but verify origin responses carry content-encoding: br.

Image Pipeline: AVIF + Lazy + LQIP

Product photography was 72% of total weight. We resize via Cloudflare Image Resizing into three breakpoints — 96px, 320px, 640px — and negotiate AVIF first, WebP second, JPEG fallback. A 320 px AVIF averages 14 KB, one-sixth of the original 89 KB JPEG.

  • Above-the-fold (first six items): eager, fetchpriority="high"
  • Below-the-fold: IntersectionObserver with 200 px rootMargin
  • LQIP: 8×8 base64 blurhash placeholder, under 60 bytes

Font Subsetting and Critical CSS

Inter Variable weighed 312 KB. With glyphhanger we subset to Turkish ranges (U+0100-017F, U+011E, U+0130) producing a 28 KB WOFF2. Combined with font-display: optional, if the font misses the 100 ms budget the system fallback stays — no FOIT, no shift.

The ~4 KB of CSS needed above the fold is inlined in <head>; the rest loads async via the media="print" onload trick. Render-blocking requests dropped from seven to one, and final LCP measured 0.78 s on the same Vodafone 4G connection.

FAQ

What Cache-Control headers should I use? HTML: s-maxage=300, stale-while-revalidate=86400. Hashed assets: public, max-age=31536000, immutable.

Is a Service Worker worth it? Yes for menus. Second-visit open averages 180 ms. Use App Shell + Workbox stale-while-revalidate.

What about 2G fallback? Honor Save-Data: ship 96 px images only, emoji placeholders instead of icons, system-ui fonts. Even on 2G we measured 2.4 s LCP.

Found this helpful? Share it.