Making WordPress Fast on Indian Broadband: Caching, Images and Core Web Vitals

Making WordPress Fast on Indian Broadband: Caching, Images and Core Web Vitals

A bakery site scores in the nineties on PageSpeed Insights. On a phone in a market lane in Muzaffarpur at seven in the evening, the same site “takes forever”. Both readings are accurate. The score came from a simulated device on a simulated network; the phone was sharing a busy tower with a few hundred other people, and the homepage was pushing a four-megabyte photo of a cake that displayed at a third of that size. Neither number lies, they measure different things, and only one has a customer attached. Tuning WordPress for Indian visitors, mostly on shared hosting and small VPS boxes, comes down to changes that are unglamorous and repeatable. Very few are plugin settings. This is the order to work in, and why the order matters.

what “slow” means on a phone in a market lane

Flow: page speed depends on time to the first byte and how much must arrive after it before useful content appears on a budget phone.
A fibre line in a flat hides problems a phone in a market lane cannot.

Two things decide how a page feels: how long the first byte takes, and how much must arrive after it before something useful appears. On a fibre line in a Patna flat both look acceptable even when the site is badly built, because the connection forgives you. On a phone attached to a congested tower, every extra round trip costs real time, and a page needing thirty of them before it paints reads as broken.

Indian connections are also lopsided. Download speed is usually fine, upload is thin, and latency wanders depending on the hour. Keep an old budget Android phone for testing, because it is the worst connection available to you. If a page is usable there, it is usable everywhere.

start with where the server actually sits

Comparison: a server far from Indian readers adds distance that no WordPress setting can recover; an Indian datacentre lets tuning gains show.
Distance is physics, not a setting.

Distance is physics, not a setting. If your host’s only datacentre is in Arizona and your readers are in Bihar, every request pays for that journey twice and nothing inside WordPress refunds it. For an Indian audience I want the origin in Mumbai, with Singapore a decent second. I cover the trade-offs in my notes on web hosting for Indian sites and Indian cloud hosting options.

If the server is on the wrong continent, move it before you tune anything. Otherwise you spend a weekend shaving off gains the network hands straight back.

Moving hosts sounds worse than it is, and it is entirely doable without taking the site offline. The full sequence is in moving a WordPress site to a new host, including the DNS timing that trips most people up.

page caching does most of the work

Table of cache layers: server page cache, object cache, OPcache, browser cache and CDN edge, with what each holds and who benefits.
One page cache plugin matched to your server, not three. LiteSpeed Cache on LiteSpeed hosts.

By default WordPress rebuilds every page on every request: PHP runs, the database is queried a few dozen times, the theme assembles HTML, and the visitor waits through all of it. A page cache does that work once and serves the saved result to everyone after. On shared hosting this one change usually does more than everything else here combined.

pick one plugin, not three

Which one depends on your server, not on which has the nicest dashboard. On a LiteSpeed or OpenLiteSpeed host, use LiteSpeed Cache, because it can store pages at the server level rather than inside PHP. On Apache or nginx, W3 Total Cache or WP Super Cache both work fine, and WP Rocket is the paid option people mostly like because it hides the decisions. If you run your own box, nginx can cache FastCGI responses itself, which I touch on in my nginx setup guide. Two caching plugins at once produces stale pages and a genuinely confusing afternoon.

browser caching is a separate layer

People use “caching” to mean several different things, and conflating them wastes effort. Browser caching only helps someone who has already visited, so it does nothing for a first impression, though a repeat visitor on metered mobile data notices.

LayerWhat it holdsWho benefits
Page cache on the serverFinished HTMLEveryone, first visit included
Object cache (Redis, Memcached)Database query resultsLogged-in users, carts, search
OPcacheCompiled PHPEverything, quietly, already on
Browser cacheCSS, JS, images, fontsRepeat visitors only
CDN edgeStatic files, sometimes HTMLVisitors far from the origin

images are where small Indian sites lose most

Terminal: mogrify resizes JPEGs wider than 1600 pixels into a resized folder at quality 82, then cwebp converts each to WebP at quality 78.
A phone camera’s several megabytes in a box a few hundred pixels wide is the usual slow site.
Table of image formats: WebP as the default, AVIF for large heroes, JPEG as fallback, PNG for screenshots, and SVG for logos and icons.
Never lazy-load the first large image. Give it fetchpriority="high" instead.

Nearly every slow small site is slow because of photographs. A phone camera produces several megabytes, someone uploads that straight into a post, and the theme displays it in a box a few hundred pixels wide. WordPress does generate smaller sizes and a srcset, which helps, but whatever a theme requests as the full size, which since WordPress 5.3 is a copy capped at 2,560 pixels, is still far larger than a phone needs.

resize before you upload

Decide the widest your content area ever gets, roughly sixteen hundred pixels for most themes, and never upload anything wider. Batch them on the laptop first. Keep the originals: without -path, mogrify overwrites every file in place, and the > flag stops it enlarging photos that are already narrower than 1,600 pixels. On Windows, ImageMagick 7 runs it as magick mogrify.

# bash (macOS, Linux or WSL). Originals stay untouched; copies go to ./resized
mkdir -p resized
mogrify -path resized -resize '1600x>' -quality 82 *.jpg
cd resized
for f in *.jpg; do cwebp -q 78 "$f" -o "${f%.jpg}.webp"; done
FormatUse forCaveat
WebPPhotos and most graphicsSensible default
AVIFLarge hero photosSmaller files, slower to encode
JPEGFallback, email, anything ancientBigger at the same quality
PNGScreenshots with sharp textNever for photographs
SVGLogos, icons, diagramsDo not accept them from strangers

the one image you must not lazy load

WordPress adds loading="lazy" to images automatically, and since version 6.3 it tries to skip the first large image and mark it fetchpriority="high" instead. It is a guess, though: hero images printed by a theme, slider or page builder outside the normal content can still arrive lazy-loaded, and lazy loading your hero tells the browser to wait before fetching the very thing the visitor is waiting to see. View the page source; if the hero carries loading="lazy", mark that one loading="eager", add fetchpriority="high", and always give width and height attributes so the browser reserves the space instead of shuffling your text down when the picture lands.

the CSS and fonts holding up your first paint

HTML preload link for a self-hosted Archivo WOFF2 font and an @font-face rule with font-display: swap highlighted.
swap shows text in a fallback font immediately, then switches.

A stylesheet in the head blocks rendering until it downloads and parses. That is by design, and fine when there is one small stylesheet. It stops being fine when a page builder loads eleven of them plus an icon font you use for two arrows. Inlining the styles needed above the fold and deferring the rest is the standard fix, usually labelled “critical CSS” in caching plugins. Test it on a staging copy; it breaks layouts often enough to deserve caution.

Fonts deserve their own look. Self-host them instead of pulling from a third-party domain, serve WOFF2 only, and resist loading six weights when the design uses two. Add font-display: swap so text renders in a fallback rather than sitting invisible, and preload the one weight your heading uses.

<link rel="preload" as="font" type="font/woff2" crossorigin
      href="/wp-content/themes/mytheme/fonts/archivo-600.woff2">

@font-face { font-family: Archivo; font-weight: 600;
  src: url(/wp-content/themes/mytheme/fonts/archivo-600.woff2) format('woff2');
  font-display: swap; }

core web vitals, and what actually moves them

Table of Core Web Vitals: LCP slowed by large hero images and slow servers, INP by heavy JavaScript and widgets, CLS by images without dimensions and late-loading ads.
Attack LCP first on a content site. In India it is almost always an image or the first byte.

Google’s three metrics are a reasonable proxy for how a page feels, which is more than most numbers manage. Each one has a usual culprit, and knowing which saves you from optimising the wrong thing.

MetricWhat it measuresUsual culprit
LCPWhen the main content appearsOversized hero image, slow server, blocking CSS
INPHow fast the page answers a tapToo much JavaScript, chat widgets, trackers
CLSHow much the layout jumpsImages without dimensions, late-loading ads and fonts

LCP is the one to attack first on a content site, and in India it is almost always an image or the server’s first byte. INP punishes scripts that hold the main thread; the fastest route to a better number is usually deleting a plugin rather than tuning one. CLS is cheap to fix and the thing that makes a reader tap the wrong link.

testing without fooling yourself

Comparison: the PageSpeed score is a lab simulation useful for comparing changes; field data from real visitors is what matters.
Beyond a point you are optimising a simulation.

PageSpeed Insights shows two different kinds of information and people read the wrong one. The score at the top is a lab simulation of a mid-range phone on a throttled connection, useful for comparing before and after a change. The field data section, when your site has enough traffic to show it, comes from real Chrome users over a rolling window. That is the truth; the lab number is a rehearsal.

My routine is boring on purpose. Test the same three URLs every time, never just the homepage. Test logged out and in a private window, because caching plugins skip logged-in users and you will otherwise measure the slow path forever. Change one thing, retest, write down what happened. Then check the Core Web Vitals report in Search Console a couple of weeks later to see whether real visitors agree with you.

what I would skip

A CDN before a page cache, and chasing a perfect score. Beyond a point you are optimising a simulation. The bigger lever people ignore is the theme: a light theme with no page builder starts you near the finish line, while a heavy multipurpose theme means paying an optimisation tax on every page for years. That choice is cheaper than every plugin in this article.

common mistakes

Speed mistakes: running several optimisation plugins, testing only the homepage, not clearing the cache, and adding a CDN before a page cache.
A light theme with no page builder starts you near the finish line.
  • Running three optimisation plugins that each minify the same files. Pick one and remove the others.
  • Testing only the homepage. Visitors from search land on posts, which often carry heavier content.
  • Forgetting to clear the cache, then concluding the change did nothing.

FAQ

Do I need a paid caching plugin?

No. The free options cover page caching, cache headers, minification and lazy loading perfectly well. What a paid plugin buys is fewer decisions and a support inbox, which is legitimate if you maintain sites for clients. For one site, the free route gets you to the same place with an extra afternoon of reading.

Will a CDN help my Indian visitors?

It depends on your origin. If the server is already in Mumbai, the improvement is modest and mostly on static files. If your host is abroad, a CDN with Indian points of presence genuinely helps, though it is a bandage over a hosting decision. Set up page caching first either way, so you can tell which change did what.

How much does speed affect my search rankings?

Less than the SEO industry implies, more than nothing. Google treats page experience as one signal among many, and it will not lift a page that does not deserve to rank. The direct benefit is behavioural: a visitor who leaves before your text renders cannot convert, share or come back.

My score dropped after one new plugin. Normal?

Very. Plugins that show something on the front end usually add a stylesheet and a script to every page, whether that page uses the feature or not. Chat widgets and sliders are the repeat offenders. Audit the list once a year with the network tab open.

Speed work on Indian connections is mostly a discipline, not a purchase: right server region, one page cache, images that were resized before upload. Get those three right and you will spend far less time reading performance reports.

Update history: the image-resizing command now keeps your originals, and the lazy-loading and full-size image notes match current WordPress behaviour.

Sources