The Web Performance Checklist Every Indian Developer Should Bookmark in 2026

calendar_today July 23, 2026
person info@softcrony.com
folder Frontend

🕮8 min read · 1,447 words

Web performance in India is a different problem than web performance in the US or Europe. When you’re optimizing for a user on a 4G connection in Bhopal on a mid-range Android phone, the numbers that matter and the fixes that help are not the same as optimizing for someone on fiber in San Francisco.

This checklist is built specifically for Indian developers building for Indian users.

Why Indian Web Performance Is Different

Three factors make India a uniquely challenging performance environment:

Network variability. Indian mobile networks are fast when they’re good (5G in metro areas can be excellent) and extremely slow when they’re not (rural 2G/3G, peak hour congestion, elevator / basement dead zones). Your site needs to work on both — not just the good case.

Device diversity. The Indian smartphone market spans from flagship iPhones in corporate offices to ₹8,000 Android phones in tier-3 cities. JavaScript-heavy sites that perform beautifully on a high-end device can be completely unusable on low-end hardware.

High latency to Western servers. If your server is in the US or Europe, Indian users are dealing with 150–400ms base latency before your application even starts. This compounds every other performance problem.

The Checklist

Section 1 — Measure First

Never optimize what you haven’t measured. Start here:

Tool What It Measures India-Specific Tip
PageSpeed Insights Core Web Vitals, opportunities Check mobile score, not just desktop
WebPageTest Waterfall, real device testing Test from Mumbai location, on mobile
GTmetrix Waterfall, filmstrip Set test location to Mumbai
Chrome DevTools Network throttling simulation Test on “Slow 4G” and “3G” presets
Lighthouse Full audit with recommendations Run in incognito, check mobile

India baseline targets:

  • LCP (Largest Contentful Paint): under 2.5 seconds on mobile
  • FID / INP (Interaction to Next Paint): under 200ms
  • CLS (Cumulative Layout Shift): under 0.1
  • Time to First Byte (TTFB): under 800ms
  • Total page weight: under 1MB for initial load

Section 2 — Server and Hosting

Use a server or CDN with an India edge node

Cloudflare (free), AWS Mumbai (ap-south-1), DigitalOcean Bangalore, or Vercel — all have India-region infrastructure. Never serve Indian users from US-East if you can help it.

Enable HTTP/2 or HTTP/3

HTTP/2 multiplexes multiple requests over one connection — critical for performance on high-latency connections. Check in Chrome DevTools → Network → Protocol column. Should show “h2” or “h3”.

Set proper cache headers on static assets

# Nginx — cache static assets for 1 year
location ~* \.(js|css|png|jpg|webp|woff2|ico)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

Enable Gzip/Brotli compression

# Nginx — enable Brotli (better than Gzip)
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/javascript application/json image/svg+xml;

Implement server-side caching

For Laravel: Redis page caching via Laravel Cache or Nginx FastCGI cache. A page that takes 800ms to generate from the database should serve in 5ms from cache.

Section 3 — Images (Biggest Win for Most Indian Sites)

Convert all images to WebP or AVIF

WebP is 30–40% smaller than JPEG at the same quality. AVIF is another 20% smaller than WebP. Both are supported on all modern browsers.

// In HTML — serve WebP with JPEG fallback
<picture>
  <source srcset="hero.avif" type="image/avif">
  <source srcset="hero.webp" type="image/webp">
  <img src="hero.jpg" alt="Hero image" loading="lazy">
</picture>
// In Laravel — auto-convert on upload
use Intervention\Image\Laravel\Facades\Image;

$image = Image::read($request->file('image'));
$image->toWebp(80)->save(storage_path('app/public/images/' . $filename . '.webp'));

Serve correctly sized images

A 2000px wide image displayed at 400px width wastes 80% of the bandwidth. Use responsive images:

<img
  srcset="hero-400.webp 400w, hero-800.webp 800w, hero-1200.webp 1200w"
  sizes="(max-width: 600px) 400px, (max-width: 900px) 800px, 1200px"
  src="hero-800.webp"
  alt="Hero"
  loading="lazy"
>

Lazy load all below-the-fold images

<img src="product.webp" loading="lazy" alt="Product">

Set explicit width and height on all images

This prevents layout shift (CLS) — one of the most common CWV failures:

<img src="product.webp" width="400" height="300" loading="lazy" alt="Product">

Compress images before upload

Target: product images under 100KB, hero images under 200KB, thumbnails under 30KB. Tools: Squoosh (browser), ImageOptim (Mac), Cloudflare Images (automated).

Section 4 — JavaScript

Audit your JavaScript bundle size

# Vite — analyze bundle
npm run build -- --analyze

# Or install the visualizer plugin
npm install --save-dev rollup-plugin-visualizer

Remove unused JavaScript

Every npm package you install adds to your bundle. Audit with:

npx depcheck  # Find unused packages
npx bundlephobia # Check package sizes before installing

Code split at the route level

Don’t load the entire application upfront. Load only the code for the current page:

// React — lazy load route components
import { lazy, Suspense } from 'react';
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Analytics = lazy(() => import('./pages/Analytics'));

// In router
<Suspense fallback={<Loading />}>
  <Dashboard />
</Suspense>

Defer non-critical JavaScript

<!-- Load after HTML parsed -->
<script src="analytics.js" defer></script>

<!-- Load when browser is idle -->
<script>
  window.addEventListener('load', () => {
    import('./chat-widget.js');
  });
</script>

Section 5 — CSS

Remove unused CSS

Tailwind CSS already purges unused classes in production. For custom CSS, use PurgeCSS.

Inline critical CSS

The CSS needed to render above-the-fold content should be inlined in the HTML head — not loaded from a separate file:

<!-- Inline critical CSS -->
<style>
  /* Only the CSS needed for above-the-fold content */
  body { margin: 0; font-family: Inter, sans-serif; }
  .hero { ... }
</style>

<!-- Load the rest asynchronously -->
<link rel="preload" href="styles.css" as="style" onload="this.rel='stylesheet'">

Section 6 — Fonts

Use font-display: swap

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter.woff2') format('woff2');
  font-display: swap; /* Show fallback immediately, swap when loaded */
}

Self-host fonts instead of Google Fonts

Google Fonts adds a DNS lookup, a connection, and a download from Google’s servers. Self-hosting eliminates this. Use Google Webfonts Helper to download and self-host any Google Font.

Preconnect to font providers if you must use CDN

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

Only load the weights you use

<!-- Don't load all weights -->
<!-- fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900 -->

<!-- Load only what you use -->
<!-- fonts.googleapis.com/css2?family=Inter:wght@400;600;700 -->

Section 7 — India-Specific Optimizations

Design for offline / poor connectivity

Use Service Workers to cache the application shell. Users on spotty connections should see content, not blank screens or spinners.

// service-worker.js — cache app shell
const CACHE_NAME = 'app-shell-v1';
const SHELL_URLS = ['/', '/css/app.css', '/js/app.js', '/offline.html'];

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME).then(cache => cache.addAll(SHELL_URLS))
  );
});

Test on real Indian network conditions

In Chrome DevTools → Network → Throttling, test on “Slow 4G” (which represents realistic Indian 4G outside metro areas). If your site is unusable on Slow 4G, a significant chunk of Indian users can’t use it.

Optimize for Android mid-range devices

Test on or emulate a device with 2GB RAM and a mid-range CPU. Heavy JavaScript will cause visible jank on these devices. Use Chrome’s CPU throttling (6x slowdown) to simulate this in DevTools.

Use Cloudflare in front of your site

Cloudflare’s free plan gives you a global CDN, DDoS protection, and Brotli compression automatically. For Indian users, Cloudflare routes traffic through its Mumbai and Chennai nodes — reducing latency significantly compared to serving from a single region VPS.

Section 8 — Monitoring

Set up Real User Monitoring (RUM)

Synthetic tests (PageSpeed, WebPageTest) show you your site’s performance in ideal conditions. RUM shows you what real users actually experience. Cloudflare Web Analytics (free), Google Search Console’s CWV report, or web-vitals.js are all good options.

// web-vitals.js — measure real user performance
import { onCLS, onFID, onLCP, onTTFB, onINP } from 'web-vitals';

function sendToAnalytics(metric) {
  // Send to your analytics endpoint
  fetch('/analytics/vitals', {
    method: 'POST',
    body: JSON.stringify(metric),
  });
}

onCLS(sendToAnalytics);
onFID(sendToAnalytics);
onLCP(sendToAnalytics);
onTTFB(sendToAnalytics);
onINP(sendToAnalytics);

Set up alerts for performance regressions

Add a Lighthouse CI check to your GitHub Actions pipeline that fails the build if Core Web Vitals drop below your thresholds:

# .github/workflows/lighthouse.yml
- name: Run Lighthouse CI
  uses: treosh/lighthouse-ci-action@v10
  with:
    urls: |
      https://yoursite.com
    budgetPath: ./lighthouse-budget.json

Performance Budget for Indian Sites

Resource Budget
Total page weight (initial) < 1MB
Images (initial load) < 500KB
JavaScript (initial) < 200KB gzipped
CSS (initial) < 50KB gzipped
Fonts < 100KB total
Third-party scripts < 100KB
Time to Interactive < 5 seconds (Slow 4G)

If you need a performance audit for your site or want help implementing these optimizations, our team at Softcrony has done this for dozens of Indian businesses.

Leave a comment