Images are almost always the reason a WordPress page feels slow. On the sites we audit at WebVitamin, oversized and badly formatted images account for 60 to 80 percent of total page weight, and in most cases the Largest Contentful Paint (LCP) element is an image. Fix the images and you fix the majority of your Core Web Vitals problem.
This guide is a practical workflow, not a plugin listicle. You will get the exact decision rules we use for formats, dimensions, srcset and compression quality, plus which steps are worth doing manually and which ones you should hand off to a plugin. At the end there are real PageSpeed Insights numbers from a client site we optimized this year.
The short answer (if you only have 10 minutes)
- Resize before upload. No image should be uploaded wider than 2x its maximum display width, capped at around 1920px for full-width hero images.
- Serve WebP by default, AVIF where it clearly wins, and keep JPEG as fallback.
- Compress at quality 75 to 82 for photos. Below 70 you start seeing artifacts on skin, gradients and skies.
- Let WordPress generate
srcset, but delete the image sizes your theme never uses and add the ones it actually needs. - Never lazy-load the LCP image. Preload it or give it
fetchpriority="high". - Use a CDN so the optimized files are delivered from a server close to your visitor.
Now the detail.

Step 1: Find out which image is actually hurting you
Do not optimize blindly. Before touching anything, identify the single image that is delaying your LCP.
- Run the page through PageSpeed Insights and open the Largest Contentful Paint element section. It names the exact element.
- Open Chrome DevTools, go to the Network tab, filter by Img, sort by size. Anything above 200 KB on a normal content page deserves attention.
- Check the Properly size images and Serve images in next-gen formats audits. They tell you the theoretical saving in KB.
In our experience, a single hero or featured image is responsible for the LCP score on roughly 8 out of 10 WordPress sites. Fixing that one file often moves the mobile score by 15 to 25 points on its own.
Step 2: Choose the right format (AVIF vs WebP vs JPEG vs PNG)
Format choice is where most of the file-size saving comes from. Here is how the four formats compare in practice in 2026:
| Format | Typical saving vs JPEG | Browser support | Use it for |
|---|---|---|---|
| AVIF | 40 to 55% | All modern browsers (Chrome, Edge, Firefox, Safari 16+) | Large photographic heroes, banners, gradients, dark images |
| WebP | 25 to 35% | Universal, including older devices | Default format for almost everything on a WordPress site |
| JPEG | Baseline | Universal | Fallback only, or small thumbnails where WebP saves almost nothing |
| PNG | Usually larger | Universal | Only for screenshots with sharp text or images needing hard transparency edges |
| SVG | Often 90%+ | Universal | Logos, icons, flat illustrations, anything vector |
Our practical rule
- Convert the whole media library to WebP with a JPEG fallback. This is the safe, universal win and takes zero manual work with a plugin.
- Hand-convert only your biggest images to AVIF: the homepage hero, category banners, full-width section backgrounds. AVIF encoding is CPU-heavy and on shared hosting a bulk AVIF conversion of 5,000 images can take hours or time out entirely.
- Replace every logo and icon with SVG. A 40 KB PNG logo becomes a 3 KB SVG that stays razor sharp on retina screens.
Warning about PNG: designers still export logos, charts and product renders as PNG out of habit. A 24-bit PNG photo can easily be 8x larger than the same image as WebP. If it does not need transparency and it is not sharp-edged text, it should not be a PNG.

Step 3: Resize before upload (the step most people skip)
Compression cannot save you from a 4000px image displayed in a 600px column. The pixel count is the file size. This is the single most impactful manual step.
How to find the right upload width
- Open the page on desktop, right-click the image, choose Inspect.
- Hover the
<img>tag and read the rendered size, for example 760 x 428. - Multiply by 2 for retina screens: upload at 1520px wide, not 4000px.
Sensible upload width cheat sheet
| Image role | Upload width | Target file size |
|---|---|---|
| Full-width hero / slider | 1920px (2560px only for huge displays) | Under 150 KB |
| Blog post featured image | 1200 to 1600px | Under 100 KB |
| In-content image | 1200px | Under 80 KB |
| Product image (with zoom) | 1500 to 2000px | Under 120 KB |
| Thumbnail / grid card | 600 to 800px | Under 30 KB |
| Author avatar / icon | 150 to 200px | Under 10 KB |
Enforce a hard cap so clients cannot break it
Even with training, someone will eventually drag a 6 MB phone photo into the media library. WordPress has a built-in big image threshold (2560px by default). You can lower it:
add_filter( 'big_image_size_threshold', function() {
return 1920;
} );
This makes WordPress automatically downscale any upload wider than 1920px and use the scaled version everywhere. It is the cheapest insurance policy you can install.
Step 4: Fix your srcset and registered image sizes
WordPress generates srcset automatically, which is great, but it only works well if the registered sizes match what your theme actually displays. Two problems are extremely common:
Problem 1: too many unused sizes
A typical WordPress install with a page builder registers 15 to 25 image sizes. Every upload creates 20 copies, your uploads folder balloons, backups slow down, and most of those files are never requested. Remove the ones you do not use:
add_filter( 'intermediate_image_sizes_advanced', function( $sizes ) {
unset( $sizes['medium_large'] );
unset( $sizes['1536x1536'] );
unset( $sizes['2048x2048'] );
return $sizes;
} );
Check first. Before unsetting a size, search your theme for the_post_thumbnail( and wp_get_attachment_image( to see which sizes are called. Removing a size that is in use forces the browser to download the full-size original.
Problem 2: gaps in the srcset ladder
If your sizes jump from 300px to 1024px to 1920px, a phone with a 390px viewport and a 3x pixel ratio needs about 1170px and will grab the 1920px file. Add intermediate sizes that match your real breakpoints:
add_action( 'after_setup_theme', function() {
add_image_size( 'wv-600', 600, 0, false );
add_image_size( 'wv-900', 900, 0, false );
add_image_size( 'wv-1200', 1200, 0, false );
} );
Problem 3: a wrong sizes attribute
WordPress often outputs sizes="(max-width: 1200px) 100vw, 1200px" even when the image sits in a 700px sidebar-constrained column. The browser then downloads a file twice as big as needed. If your layout is fixed, override it:
add_filter( 'wp_calculate_image_sizes', function( $sizes, $size ) {
if ( is_singular( 'post' ) ) {
return '(max-width: 782px) 100vw, 760px';
}
return $sizes;
}, 10, 2 );
This one change cut 380 KB from an article template on a client blog we worked on, without changing a single image file.

Step 5: Compress without visible quality loss
Lossy compression is not the enemy. Compression that is too aggressive is. Here is where the quality slider should sit:
| Content type | Recommended quality | Notes |
|---|---|---|
| Standard photos, blog images | 78 to 82 | The sweet spot. Indistinguishable from the original at normal viewing distance |
| Product photography, portfolios | 82 to 88 | Detail matters, pay the extra KB |
| Thumbnails, small grid cards | 65 to 75 | Artifacts are invisible at small sizes |
| Background images with overlay | 55 to 65 | A dark overlay hides almost everything |
| Screenshots with text | Lossless WebP or PNG | Lossy compression smears small text |
WordPress compresses its generated sizes at quality 82 by default. If a plugin is not handling it, you can set it explicitly:
add_filter( 'jpeg_quality', function() { return 82; } );
add_filter( 'wp_editor_set_quality', function() { return 82; } );
How to check you have not gone too far
- Open the original and the compressed version side by side at 100% zoom.
- Look specifically at skies, skin tones, shadows and smooth gradients. That is where banding and blockiness appear first.
- Check on a phone, not just a desktop monitor. Mobile screens are dense and forgiving.
- If the file dropped more than 85% and looks fine, you probably had an uncompressed original, not a compression miracle. That is normal.
Step 6: Loading behaviour matters as much as file size
You can serve a perfectly compressed 60 KB hero and still have a bad LCP if it loads late. wpkube.com walks through the specifics.
Never lazy-load above the fold
WordPress core skips lazy loading for the first images on a page and adds fetchpriority="high" to the likely LCP image. Page builders and some sliders override this. Check your rendered HTML: if your hero has loading="lazy", remove it.
Preload the LCP image
For heroes loaded via CSS background or through a slider, add a preload hint in the head:
<link rel="preload" as="image"
href="/wp-content/uploads/2026/09/hero-1920.webp"
imagesrcset="/wp-content/uploads/2026/09/hero-900.webp 900w,
/wp-content/uploads/2026/09/hero-1920.webp 1920w"
imagesizes="100vw" fetchpriority="high">
Preload one image only. Preloading five images means none of them is a priority.
Always set width and height
Missing dimensions cause layout shift and hurt your CLS score. WordPress adds them automatically for media library images, but manually pasted <img> tags and some third-party widgets do not. Add explicit width and height attributes everywhere.
Lazy-load everything below the fold
Native loading="lazy" is enough. You do not need a JavaScript lazy-load library in 2026, and those libraries often make LCP worse by delaying decode.

Manual vs plugin: what to do yourself and what to automate
This is the part most articles get wrong. Plugins cannot fix decisions, only execution.
| Task | Do it manually | Let a plugin do it |
|---|---|---|
| Choosing the right format per image role | Yes | No |
| Cropping and resizing before upload | Yes | Partly (as a safety net) |
| Bulk WebP or AVIF conversion | No | Yes |
| Compression of every generated size | No | Yes |
| Cleaning up registered image sizes | Yes (code) | No |
| Fixing the sizes attribute | Yes (code) | No |
| Preloading the LCP image | Yes | Sometimes (caching plugins) |
| CDN delivery | No | Yes |
| Writing descriptive alt text | Yes | No |
Which plugin to pick
Any of the well-known options will compress adequately. The real differences are in how they store files and what happens if you leave:
- ShortPixel: excellent compression ratios, keeps originals in a backup folder, credit-based pricing. Good all-rounder for content-heavy sites.
- Imagify: the simplest interface of the group, three quality presets, made by the WP Rocket team, so it plays well with that cache plugin.
- EWWW Image Optimizer: can run compression on your own server with no API limits. Best value if you have a VPS and thousands of images.
- Optimole: offloads and serves images from its own CDN with automatic resizing per device. Fastest setup, but your images live on their infrastructure.
- Converter for Media: free, focused purely on WebP and AVIF conversion with server rewrite rules. Good minimal choice.
Important: pick one. Running two image plugins at once produces double-compressed, mushy images and conflicting rewrite rules. We see this on client sites constantly.
Real results: a client site before and after
Here is a recent example. A Slovak accommodation and services site, WordPress with a page builder, roughly 900 images in the library, hosted on standard shared hosting. Nothing changed except images and their delivery. No server upgrade, no theme change.
| Metric (mobile, homepage) | Before | After | Change |
|---|---|---|---|
| PageSpeed performance score | 41 | 89 | +48 |
| Largest Contentful Paint | 4.8 s | 1.9 s | -60% |
| Total page weight | 6.1 MB | 1.2 MB | -80% |
| Image payload | 5.3 MB | 640 KB | -88% |
| Hero image size | 1.9 MB JPEG (4032px) | 104 KB AVIF (1920px) | -95% |
| Cumulative Layout Shift | 0.21 | 0.02 | Good |
What actually produced those gains
- The hero image alone accounted for about 22 points. It was a full-resolution phone photo at 4032px, uncompressed, lazy-loaded by the slider. Resizing to 1920px, converting to AVIF and preloading it fixed most of the LCP problem.
- Bulk WebP conversion of the library removed roughly 2.8 MB across the homepage gallery sections.
- Removing 9 unused registered image sizes shrank the uploads folder by 41% and made backups usable again.
- Correcting the sizes attribute in the content template stopped mobile devices from downloading 1920px files inside a 380px column.
- A CDN in front of the uploads folder shaved a further 300 to 500 ms for visitors outside Slovakia.
Total time invested: about five hours, most of it waiting for bulk conversion to finish.

Your repeatable upload workflow
Once the site is cleaned up, keep it clean. Give this checklist to whoever publishes content:
- Crop the image to the aspect ratio the template uses.
- Resize the longest edge to the target width from the cheat sheet above.
- Export as WebP at quality 80, or JPEG at 80 if your tool cannot do WebP.
- Check the file size. Over 200 KB? Go back and reduce dimensions, not just quality.
- Rename the file descriptively before upload:
wooden-cabin-terrace-tatras.webp, notIMG_4921.jpg. - Upload, then write real alt text describing the image content.
- Spot-check the published page in DevTools to confirm the browser picked a sensible
srcsetcandidate.
Free tools that do steps 1 to 3 well: Squoosh (browser-based, gives you a live quality comparison slider), ImageOptim on macOS, and XnConvert for batch processing on Windows.
Common mistakes we still find on client sites
- Compressing but not resizing. A 4000px image compressed to 400 KB is still four times bigger than it needs to be.
- Lazy-loading the hero. Instantly costs you 300 to 800 ms of LCP.
- Running two optimization plugins. Double compression plus conflicting rewrite rules.
- Serving PNG photos. Check your library, sort by file size, and you will find them.
- Sliders on the homepage. A five-slide carousel usually loads all five images. Use a static hero, or ensure only the first slide loads eagerly.
- Forgetting the favicon and logo. Small files, but they sit on the critical path on every single page.
- Optimizing once and never again. Six months of client uploads will undo everything. Set the upload threshold, keep the plugin on auto-optimize.
FAQ
How can I optimize my images for WordPress?
Resize before upload so no image is wider than twice its display width, convert to WebP (AVIF for large heroes), compress at quality 78 to 82, keep only the registered image sizes your theme uses, make sure the LCP image is not lazy-loaded, and serve everything through a CDN. Automate the conversion and compression with a single plugin, but make the format and dimension decisions yourself.
What is the best image optimization plugin for WordPress?
There is no single winner. ShortPixel and Imagify are the safest general picks, EWWW is best if you want server-side processing with no per-image credits, and Optimole is best if you want CDN delivery and device-based resizing with almost no configuration. Choose based on your hosting and image volume, and only ever run one of them.
Should I use WebP or AVIF in 2026?
Use WebP as your site-wide default because conversion is fast and support is universal. Use AVIF selectively for your largest photographic images where the extra 20 to 30 percent saving is actually meaningful. AVIF encoding is slow and can strain shared hosting during bulk operations.
Does image optimization actually improve SEO rankings?
Indirectly but measurably. Core Web Vitals are a ranking signal, and images are the main driver of LCP. More importantly, faster pages have lower bounce rates and better conversion, which is what you actually care about. Descriptive filenames and alt text also help you rank in Google Images. Originally covered on https://themarkitmedia.com.
Will compressing images make them look bad?
Not at quality 78 to 82. At that level the difference is invisible to visitors at normal viewing distance, while the file is 60 to 80 percent smaller. Problems start below quality 70, and they appear first in skies, gradients and skin tones. Always keep backups of originals so you can re-optimize later if needed.
How many image sizes should WordPress generate?
Usually four to six is enough: a thumbnail, one or two mid sizes matching your grid, one content-width size, and one full-width size around 1920px. Anything beyond that wastes disk space and slows down uploads and backups without improving delivery.
Do I still need lazy loading?
Yes, for images below the fold, and the native loading="lazy" attribute WordPress adds is enough. Skip JavaScript lazy-load libraries, they usually add more overhead than they save.
Need this done on your site?
Image optimization is one of those tasks where the first pass delivers a large, permanent gain and then requires almost no maintenance if it is set up correctly. If you would rather have someone audit your media library, fix the srcset logic, set up conversion and hand you a documented upload workflow for your team, that is exactly the kind of work we do at WebVitamin. Get in touch and we will start with a free look at your current PageSpeed numbers.