WordPress image optimization: the complete guide for Indian sites
10 min read · 25-Mar-2024
villagehosting.in team
25 March 2024
Images are the single largest contributor to slow page loads on Indian mobile networks. A product page with ten 2 MB JPEG images takes 20+ seconds to load on a 4G connection with 15 Mbps throughput. The same page with properly optimized WebP images takes under 3 seconds. This guide covers every image optimization technique that matters for Indian website performance.
Why images matter more in India
India's mobile internet users often experience 10–40 Mbps 4G speeds in urban areas and 2–10 Mbps in semi-urban regions. A website optimized for a 100 Mbps broadband connection will be unusable for a significant portion of your Indian audience. Image optimization is the highest-impact fix for this gap.
The Indian mobile network context
When testing website speed, most developers use Chrome's DevTools on a broadband connection. This is not representative of how most Indian visitors experience your site.
Realistic Indian network conditions:
- Tier 1 city 4G: 15–50 Mbps, 40–80ms latency
- Tier 2/3 city 4G: 5–20 Mbps, 60–120ms latency
- 3G/slow 4G: 1–5 Mbps, 100–300ms latency
Use Chrome DevTools Network tab → throttling → "Slow 4G" (1.6 Mbps / 150ms) to test what a significant portion of your Indian audience actually experiences.
Step 1: Establish your baseline
Before optimizing, measure current state. Run your site through:
PageSpeed Insights: Shows Core Web Vitals and highlights specific images causing LCP (Largest Contentful Paint) issues.
GTmetrix: Shows waterfall chart — useful for seeing the order images load and which are render-blocking.
WebPageTest: Can simulate Indian mobile connections and show real-world conditions.
Note: your LCP element is the most critical. It's usually the hero image on the homepage.
Step 2: Enable WebP conversion
WebP is Google's image format. For the same visual quality, WebP is typically:
- 25–35% smaller than JPEG
- 50–80% smaller than PNG
Since 2021, all major browsers (Chrome, Safari, Firefox, Edge) support WebP. There's no reason to serve JPEG/PNG when WebP is available.
Using a plugin
Imagify (recommended):
- Converts existing and new uploads to WebP automatically
- Serves WebP to supported browsers, falls back to JPEG/PNG for older browsers
- Free plan: 25 MB of images/month, then paid from ~₹800/month
ShortPixel:
- Converts to WebP and AVIF
- Free: 100 images/month, then credits (~₹600 for 10,000 images)
- One-time purchase option available
Smush (free tier available):
- Limited WebP conversion on free plan
- Full WebP with Smush Pro (~₹1,200/month)
Manual WebP with Nginx (VPS only)
If you're on a VPS, NGINX can serve WebP automatically without a plugin:
First, convert images (run once for existing library):
# Install cwebp
sudo apt install webp -y
# Convert all JPEGs in uploads directory to WebP
find /var/www/html/wp-content/uploads -name "*.jpg" -exec sh -c \
'cwebp -q 80 "$1" -o "${1%.jpg}.webp"' _ {} \;
find /var/www/html/wp-content/uploads -name "*.png" -exec sh -c \
'cwebp -q 80 "$1" -o "${1%.png}.webp"' _ {} \;
Add to your NGINX config:
# Serve WebP when supported and file exists
location ~* \.(jpg|jpeg|png)$ {
add_header Vary Accept;
if ($http_accept ~* "webp") {
set $webp_suffix ".webp";
}
try_files $uri$webp_suffix $uri =404;
expires 30d;
}
New uploads still need conversion — use a plugin or a cron job to convert new images automatically.
Step 3: Compress images correctly
Target file sizes:
- Hero images (full width): under 200 KB
- Blog featured images: under 100 KB
- Product images: under 80 KB
- Thumbnails: under 30 KB
- Icons and logos: under 10 KB
Compression quality settings:
- JPEG: 75–85% quality for photos (visually identical to 100% at half the size)
- WebP: 75–80% quality
- PNG: use PNGQuant or lossless WebP for screenshots and graphics
During upload, WordPress generates multiple image sizes (thumbnail, medium, large, etc.). Unoptimized uploads means unoptimized derived sizes too. Set your compression plugin to compress on upload.
Bulk compression of existing library: Most compression plugins have a "Bulk Optimize" feature. Run this after installing — your existing uploaded images won't be compressed until you do.
Set maximum upload dimensions
WordPress stores the original uploaded image. If someone uploads a 6000×4000 JPEG from their camera, WordPress stores that 10 MB file plus all the resized versions. Add this to functions.php to cap upload dimensions: add_filter('big_image_size_threshold', '__return_false'); — or better, set it to a sensible max like 2400px: add_filter('big_image_size_threshold', fn() => 2400);
Step 4: Lazy loading
Lazy loading delays loading images that are below the viewport — they only load when the user scrolls near them. This dramatically reduces initial page load time.
WordPress 5.5+ adds loading="lazy" to images automatically. Verify it's working:
Right-click any image below the fold → Inspect → look for loading="lazy" attribute.
What lazy loading does not fix: Your hero image (above the fold) should never be lazy-loaded. Google's LCP metric penalizes lazy-loaded above-the-fold images. Check your theme's hero section — if the hero image has loading="lazy", remove it.
Critical hero image optimization:
<!-- Good: hero image loads immediately -->
<img src="hero.webp" alt="Your alt text" loading="eager" fetchpriority="high">
<!-- Bad: hero image lazy loaded, hurts LCP -->
<img src="hero.webp" alt="Your alt text" loading="lazy">
In WordPress, the first image in a post is automatically given loading="eager" since WordPress 6.3. For hero images in theme templates, add fetchpriority="high" manually.
Step 5: Serve images from a CDN
A CDN (Content Delivery Network) stores copies of your images at servers worldwide. Indian visitors get images from a nearby node rather than your VPS in, say, Bengaluru.
For Indian websites, CDN benefits:
- Images served from Mumbai or Chennai edge nodes to all Indian users
- Reduced load on your VPS
- Automatic WebP serving on modern CDNs
- Image resizing/optimization on-the-fly (Cloudflare Images, BunnyCDN)
Options:
Cloudflare (free tier):
- DNS proxy gives some CDN benefit for static assets
- Cloudflare Polish (image optimization) — available on paid plans (~₹1,000/month)
- Automatic WebP conversion with Cloudflare Images
BunnyCDN (most affordable for Indian sites):
- Storage: $0.01/GB/month
- Bandwidth in Asia: $0.06/GB
- BunnyCDN's Perma-Cache stores images at the edge permanently
- Supports on-the-fly WebP conversion, resizing
Integration with WordPress: Use the BunnyCDN WordPress plugin or WP Offload Media (for S3-compatible storage). These plugins:
- Upload existing media library to CDN/object storage
- Rewrite all image URLs to CDN URLs automatically
- New uploads go directly to CDN
Step 6: Responsive images
Modern WordPress generates multiple sizes of each image and uses srcset to serve the right size for each device. Verify this is working:
Right-click any image → Inspect → look for srcset attribute:
<img srcset="image-300x200.webp 300w, image-768x512.webp 768w, image-1200x800.webp 1200w"
sizes="(max-width: 767px) 100vw, (max-width: 1199px) 50vw, 800px"
src="image-1200x800.webp"
alt="Description">
This tells the browser: on mobile (under 768px), use the 300w image; on tablets, use the 768w version; on desktop, use the 1200w version.
Custom image sizes: Register appropriate sizes in your theme. If your theme's content area is 800px wide max, you don't need WordPress generating 1920px images.
In functions.php:
// Add a custom image size matching your design
add_image_size('blog-featured', 1200, 600, true); // width, height, crop
add_image_size('product-card', 600, 600, true);
// Remove sizes you don't use to save disk space
add_filter('intermediate_image_sizes_advanced', function($sizes) {
unset($sizes['medium_large']); // 768px wide — rarely useful
return $sizes;
});
Step 7: Fix Largest Contentful Paint (LCP)
LCP is Google's Core Web Vitals metric for perceived load speed. The LCP element is usually your hero image. To diagnose:
- Open PageSpeed Insights for your homepage
- Under "Opportunities", look for "Largest Contentful Paint element"
- Click to see which element is causing slow LCP
Common LCP fixes for Indian sites:
Preload the hero image:
Add to your theme's <head>:
<link rel="preload" as="image" href="/wp-content/themes/yourtheme/images/hero.webp" type="image/webp">
In WordPress, hook into wp_head:
add_action('wp_head', function() {
if (is_front_page()) {
echo '<link rel="preload" as="image" href="' . get_template_directory_uri() . '/images/hero.webp" type="image/webp">';
}
}, 1);
Use fetchpriority="high" on the hero image:
add_filter('wp_get_attachment_image_attributes', function($attr, $attachment) {
// Add fetchpriority to the first image in content
$attr['fetchpriority'] = 'high';
return $attr;
}, 10, 2);
Reduce hero image file size: The LCP image must load fast. Target under 100 KB for above-the-fold images.
Quick checklist
| Task | Tool | Target |
|---|---|---|
| Convert to WebP | Imagify / ShortPixel | 25–35% smaller |
| Compress images | Plugin on upload | Hero < 100 KB |
| Lazy load below fold | WordPress built-in | Verify in DevTools |
| Preload hero image | <link rel="preload"> | LCP < 2.5 seconds |
| Serve from CDN | BunnyCDN / Cloudflare | Edge near visitors |
| Check srcset | DevTools HTML inspect | Responsive sizes present |
Running through this checklist typically cuts image payload by 60–80% and reduces LCP by 1–2 seconds on Indian mobile connections. For a WooCommerce site with product images, the impact is even larger — faster product pages directly improve conversion rates.