Fixing Image CDN Delivery
A well-compressed image can still arrive slowly if it travels from a single server on the other side of the world, is never cached, or is re-sent in full on every visit. That is what the CDN delivery finding is about: where images come from and how they are cached, not how they were exported.
This guide shows how to read the response headers that tell you whether a CDN is working, how to set cache lifetimes that let browsers and edge servers keep files, and how to weigh the main image CDN services against each other without committing to one blindly.
What an image CDN does and what goes wrong
A content delivery network keeps copies of your files on servers in many cities. When a visitor in Leeds asks for an image, a nearby edge server answers instead of your origin server in, say, Frankfurt or Virginia. The trip is shorter, the origin does less work, and a busy day does not slow the site down for everyone.
An image CDN goes a step further. As well as caching, it can create resized, recompressed
and reformatted versions of an image on request, usually controlled by parameters in the URL. You upload
one large original and ask for width=640 in WebP, and the service produces and caches that
variant.
The delivery finding usually traces back to one of these:
- No CDN at all. Every image comes from the origin, so visitors far from it wait longer and the server strains under traffic.
- A CDN that is not caching. Headers such as
Cache-Control: no-cacheorprivate, cookies on image responses, or query strings that change on every request make the edge fetch from origin each time. - Short browser cache lifetimes. Returning visitors re-download images they already have, or at least wait for a revalidation round trip.
- Images on a separate domain. A dedicated image domain needs its own DNS lookup and secure connection before the first image can load, which can delay the main image.
- Transformation set up but unused. A CDN capable of resizing is in place, but templates still request the full-size original.
Reading the headers
Open developer tools, select an image in the Network panel and look at its response headers. Or run a command such as the one below, which fetches only the headers.
curl -sI https://www.example.co.uk/img/fell-jacket-960.webp
HTTP/2 200
content-type: image/webp
content-length: 48213
cache-control: public, max-age=31536000, immutable
age: 5120
cf-cache-status: HIT
vary: Accept
| Header | What to look for |
|---|---|
cache-control | public with a long max-age for images
whose names change when they change. no-store, no-cache or private
on an image is almost always a mistake. |
| Cache status header | Names vary: cf-cache-status on Cloudflare, cdn-cache
on Bunny, x-cache on several others. HIT means the edge answered; MISS
on repeated requests means it is not keeping the file. |
age | How many seconds the edge has held this copy. A value that keeps resetting to zero points to caching problems. |
vary | If the same URL returns different formats depending on the browser,
the response must vary on Accept or the CDN must handle this internally, or a browser may
get a format it cannot show. |
set-cookie | Should not appear on image responses. Many CDNs refuse to cache responses that set cookies. |
content-type | Must match the real format. A WebP served as image/jpeg
can break in some clients and social previews. |
Request the same image two or three times. The first may be a MISS, which is normal because
the edge had not seen it yet. After that you should see HIT. Also look at the timing tab:
a long wait for the first byte on image requests, when the HTML is quick, points to images coming from
a distant or busy origin.
HIT from your office does not mean
a visitor in another country will get one. That is why testing from several locations is part of the
fix.The fix, step by step
Step 1
Read the headers on your current images
Pick five images from your key templates, including the main image on the home page and
a product or article image, and check their response headers with developer tools or curl -sI.
Record the cache status header, cache-control, age, vary and whether
any cookie is set. Note which domain each image comes from. This gives you a before picture and often
reveals the problem, such as a missing CDN or a no-cache rule, in minutes.
Step 2
Decide whether you need caching or transformation
If your images are already resized and converted at upload or build time, a plain caching CDN in front of the site is enough. If editors upload large originals, or you need many widths and formats per image, an image CDN that transforms on request saves a lot of manual work. Be honest about scale: a brochure site with forty images has different needs from a shop with twenty thousand product photos and several variants of each.
Step 3
Pick a service model that fits the site
Services fall into three rough groups: a whole-site CDN with image features switched on, a CDN that transforms images pulled from your existing server or storage, and a platform that stores and manages the images itself. Compare them on how URLs are written, which formats are produced automatically, how pricing is calculated and how hard it would be to leave. Check each provider's current pricing page rather than relying on old comparisons, as plans change often.
Step 4
Route image requests through the CDN
The simplest route is to put the CDN in front of the whole domain, so image URLs do not change
at all. If you use a separate image service, prefer a custom subdomain such as img.example.co.uk
over the provider's shared hostname, so you can switch provider later without rewriting URLs. Update
templates, not individual pages, and use your platform's URL filter or rewrite setting where one exists.
Redirecting old image URLs is rarely necessary if the originals stay available.
Step 5
Set long cache lifetimes with versioned names
Send Cache-Control: public, max-age=31536000, immutable on images whose file
names change whenever the content changes, for example by adding a short hash or version number. Browsers
and edges can then keep them for a year without asking again. For images that are replaced in place under
the same name, use a shorter lifetime such as a day, and purge the CDN when you replace one. Remove any
cookies from image responses.
Step 6
Enable resizing and format negotiation with limits
Turn on automatic format selection so browsers that accept AVIF or WebP receive it
while others get JPEG or PNG, and confirm the response varies on Accept or is handled by
the service. Point srcset at transformation URLs with a fixed set of widths rather than
arbitrary ones. Where the service allows it, restrict permitted widths or use named presets, so each
image only exists in a handful of cached variants and the cache hit rate stays high.
Step 7
Protect the origin and the bill
Transformation services can be abused by anyone requesting thousands of unusual sizes, each one a fresh job charged to you. Use presets, signed URLs or an allow-list of widths to stop that. Set a spending alert if the provider offers one. Configure hotlink protection with care, because it can block social media crawlers from fetching your share images. Finally, keep the origin serving images directly over HTTPS without redirects, so edge fetches are quick.
Step 8
Test from more than one location
Load key pages from at least two regions using a web page testing service with selectable locations, or ask a colleague elsewhere to share a HAR file. Confirm image responses show a cache hit after the first request, arrive in the expected format, and have a short wait before the first byte. Check the main image specifically, because a new connection to an image domain can delay it. Then re-run the Image Optimisation audit to compare with your starting point.
Comparing common image CDN options
The services below are widely used and represent different approaches. This is not a ranking, and features and prices change, so confirm details with each provider before choosing.
| Service | Approach | Transformation URL style | Suits |
|---|---|---|---|
| Cloudflare | Whole-site CDN; image transformations and a separate Cloudflare Images storage product | /cdn-cgi/image/width=640,format=auto/img/photo.jpg | Sites already behind Cloudflare that want resizing without moving files. |
| Bunny.net | Pull zone CDN with an optional optimiser add-on | /img/photo.jpg?width=640 | Small and medium sites wanting a straightforward CDN with simple image options. |
| Imgix | Transformation service in front of your own storage or web folder | /photo.jpg?w=640&auto=format,compress | Teams with images already in cloud storage and many layouts to serve. |
| Cloudinary | Full media platform: upload, storage, transformation and delivery | /image/upload/f_auto,q_auto,w_640/photo.jpg | Sites wanting a managed media library, video as well as images, and rich transformations. |
| ImageKit | Transformation and delivery over your storage or its own | /photo.jpg?tr=w-640 | Similar uses to Imgix and Cloudinary, often considered by smaller teams. |
Cost against convenience
- Pricing models differ. Some charge mainly for bandwidth, some for the number of transformations or unique variants, some use credits that combine several measures, and some charge for stored images. A site with a few popular images and one with many rarely viewed ones will see very different bills from the same provider.
- Convenience has a lock-in cost. Platforms that store your images and use their own URL syntax are the most convenient day to day, but moving away later means rewriting every image URL. A custom domain and a small URL helper in your templates make switching easier.
- Doing it yourself is an option. Generating fixed widths and formats at build or upload time, then serving them through any caching CDN, has no per-transformation cost. It needs more setup and storage, and suits sites whose images change rarely.
Same domain or separate image domain?
Years ago, sites spread images across several hostnames so browsers would open more connections at once. With HTTP/2 and HTTP/3, one connection can carry many requests in parallel, so that trick now does more harm than good: each extra hostname needs its own DNS lookup and TLS handshake before anything is downloaded.
- Best for speed: images on the same hostname as the page, served by a CDN in front of the whole site. The connection is already open when the HTML arrives.
- Acceptable: a single image subdomain. Add
<link rel="preconnect" href="https://img.example.co.uk">near the top of the head so the connection is ready early, and consider serving the main image from the page's own domain. - Avoid: several image hostnames, or a provider's shared hostname you do not control.
Some services can be mapped to a path on your main domain through a whole-site CDN or reverse proxy,
for example /media/ forwarding to the image service. That gives you the transformation features
without a second connection.
Edge cases
- Images behind a login. Private images such as customer documents should not be cached
publicly. Use
privatecaching and signed, expiring URLs. - Replacing an image under the same name. Visitors and edges may keep the old version until it expires. Change the file name or add a version parameter, then purge the CDN if needed.
- Query-string cache keys. Tracking parameters added to image URLs by some tools create separate cache entries. Configure the CDN to ignore irrelevant query strings for images.
- Social and search crawlers. Bot protection or hotlink rules at the CDN can stop Googlebot or link preview crawlers fetching images. Check your firewall events if images vanish from search or previews.
- Redirects at the origin. An origin that redirects image requests from http to https, or from a bare domain to www, adds a hop to every edge miss. Our CDN and origin redirects guide covers fixing that.
Keeping delivery fast
- Build URLs in one place. A single template helper that builds image URLs, with the width and format, makes it easy to change provider or settings later.
- Version file names. Build tools and most CMS platforms can add a hash or date to file names, which makes year-long caching safe.
- Watch the cache hit ratio. Most CDN dashboards report it. A drop after a release often means a new query string or cookie is defeating the cache.
- Review the bill monthly. Unexpected growth in transformations or bandwidth is an early sign of hotlinking, a crawler loop or an unbounded width parameter.
- Re-audit after changes. Run the Image Optimisation audit whenever you change CDN settings, themes or image templates.
1. Do I need an image CDN for a small business website?
Not always. If your site has a modest number of images that are already resized and converted before upload, and your hosting sits near most of your visitors, a general CDN in front of the whole site, or even good cache headers alone, may be enough. An image CDN earns its keep when editors upload large originals, when you sell many products with several photos each, or when visitors come from many countries.
2. How can I tell if my images are being served from a CDN?
Look at the response headers for an image in your browser's developer tools or with curl. A CDN usually adds a cache status header such as cf-cache-status on Cloudflare, cdn-cache on Bunny or x-cache on several others, along with an age header. Request the same image twice: the second response should show a hit. If there is no such header and the server header names your web host, the image is coming straight from the origin.
3. What Cache-Control header should images have?
For images whose file names change whenever the picture changes, use public with a max-age of one year and the immutable directive, so browsers and edges keep them without checking again. For images replaced in place under the same name, use a shorter max-age such as a day and purge the CDN when you change them. Avoid no-store, no-cache and private on public images, and make sure image responses do not set cookies.
4. Is it bad to host images on a separate domain?
It can slow the first image, because the browser must look up the extra hostname and open a new secure connection before downloading anything. With modern HTTP versions there is no longer a benefit from spreading images across several domains. Serving images from the page's own domain through a whole-site CDN is quickest. If you do use one image subdomain, add a preconnect hint in the head and consider serving the main image from the main domain.
5. Why does my CDN keep showing MISS for images?
The edge is not storing the file, or each request looks different to it. Common causes are cache-control headers such as no-cache or private, cookies set on image responses, query strings that change on each request, CDN rules that only cache certain file types, or a very short cache lifetime. Remember that caches are per location, so a first request from a new region is always a miss. Repeated misses from the same place point to configuration.
6. Will using an image CDN improve my search rankings?
Indirectly at most. Faster image delivery can improve Largest Contentful Paint and general loading speed, which are part of how Google assesses page experience, and a quicker page tends to keep visitors. But the content and relevance of the page matter far more. Make sure the CDN does not block Googlebot, keep image URLs stable, and keep alt text and surrounding context intact when you change how images are served.
7. Can switching image CDN break my images in Google Images?
It can cause a temporary dip. Google indexes images by their URLs, so moving every image to new addresses means they must be discovered again. Using a custom domain you control, keeping old URLs working or redirecting them, and updating image sitemaps reduces the disruption. Where possible, choose a setup that keeps image URLs unchanged, such as a CDN in front of the whole domain, so a later switch of provider does not change addresses.
The Image Optimisation audit checks every image on your page for file size, format, dimensions, alt text, lazy-loading, layout shift and CDN delivery, and ranks its recommendations by their effect on loading and bandwidth.
Open Image Optimisation Fixes โ