Loading...

Case study

Case study: an image-heavy fashion store, 3.5x faster from the edge

A Turkish fashion e-commerce site serves a homepage that references over 130 images — product shots, sliders, campaign banners. Every one of those requests used to be the origin's problem. This case study walks through the actual configuration the site runs on cdn.com.tr today — year-long image caching, one-day HTML caching with click-ID normalization, Brotli, Redis at the hosting layer, WAF in front — and the measured result: cached responses answer about 3.5 times faster than origin fetches. All numbers are real measurements from the live site; the customer is anonymized.

7 min read Beginner friendly Updated

Case study: an image-heavy fashion store, 3.5x faster from the edge

The problem: every product photo is a request

Fashion e-commerce lives on photography. This store's homepage alone references more than 130 images — sliders over 300 KB, product shots around 50-350 KB — and category and product pages repeat the pattern. Without a CDN, every visitor pulls every one of those files from the origin server: the same photos, thousands of times a day, competing for the same PHP workers and bandwidth that should be serving carts and checkouts.

The goal was not exotic: get repeat image traffic off the origin entirely, keep the HTML fresh enough for a store, and do it without touching the WordPress theme.

The image rule: cache for a year, serve for milliseconds

The heart of the setup is one delivery rule matching image extensions (jpg, jpeg, png, gif, webp, svg, ico). It caches successful responses at the edge for a full year, adds a CORS header so the images can be embedded where needed, and compresses what benefits from it with Brotli and gzip.

A year sounds aggressive until you remember how product images actually change: they do not. A photo uploaded for a product keeps its URL until the product dies; a redesign uploads new files with new names. Long TTLs mean the edge almost never has to re-ask the origin — in our sampling, every homepage image was already a HIT. And for the rare case where an image must change in place, a scoped purge clears exactly that entry.

The HTML rule: one day, with a campaign-traffic trick

HTML gets different treatment: the homepage is cached for one day — long enough that the edge absorbs nearly all anonymous traffic, short enough that merchandising changes show up same-day, and a purge handles anything urgent.

The detail worth stealing is query normalization. Traffic from social campaigns arrives with tracking parameters — every Facebook click carries a unique fbclid. Cached naively, each click would be a "different" URL, every campaign visitor a cache MISS, and the origin would take the full ad-spike load at the worst moment. The rule excludes fbclid from the cache key, so ten thousand campaign clicks are one cache entry. The parameter still reaches analytics; it just stops fragmenting the cache.

What we measured

Numbers from the live site, measured over the public internet (so they include real network distance, not lab conditions). A cached image answers with a median time-to-first-byte around 0.15 seconds. Forcing the edge to fetch the same file from the origin puts the median around 0.54 seconds — roughly 3.5 times slower. The homepage HTML, served as a cache HIT with Brotli compression, starts arriving in about 0.27 seconds.

Multiply that gap by 130+ images per page view and the effect on perceived speed is not subtle: the browser starts painting product photos while an uncached setup would still be waiting for the first ones. And every HIT is a request the origin never sees — during a campaign spike, the origin's job shrinks to serving carts.

The rest of the stack: Redis and WAF at no extra effort

Two more pieces run alongside the cache, both switched on rather than built. At the hosting layer, a Redis object cache backs WordPress, turning repeated database lookups — options, menus, product metadata — into memory reads for the requests that do reach PHP. In front, the account's WAF preset inspects incoming traffic at the same edge that serves the cache, so common attack patterns are filtered before they ever queue for the origin.

Honest footnote: this customer does not use our WebP/AVIF image optimization — the numbers above are pure caching and compression. There is measurable headroom left on the table (modern formats typically cut image weight substantially), which makes the result more transferable, not less: this is what edge caching alone does.

What to copy for your own store

The pattern transfers to any image-heavy site in four rules of thumb. Cache images by extension with a long TTL and purge on change, instead of short TTLs "to be safe" — safe is what purge is for. Cache your HTML for hours or a day, not zero, and let a deploy-time purge handle freshness. Normalize tracking parameters (fbclid, and utm_* where analytics allows) out of the cache key before your next campaign, not after it melts the origin. And verify with measurements, not vibes: one curl with a cache-buster against one without tells you exactly what the edge is worth on your own pages.

Frequently asked questions

Is a 1-year image TTL safe for e-commerce?

Yes, because product image URLs are stable: new products bring new filenames. The risk case — replacing an image at the same URL — is handled by a scoped purge, which takes effect in seconds.

Why cache the homepage for only a day when images get a year?

HTML changes with merchandising — campaigns, pricing, featured products. A day means the edge still absorbs almost all of the read traffic, while same-day changes appear without anyone thinking about it; urgent changes are one purge away.

What does excluding fbclid from the cache key actually do?

Without it, every ad click is a unique URL and therefore a cache MISS — your paid traffic, the most expensive you have, all lands on the origin. With it, all clicks share one cached entry. The parameter still reaches your analytics scripts unchanged.

Would WebP/AVIF have made this faster still?

It would cut transfer sizes further (often 30-70% on photos), which is exactly why we note this customer has it off — the 3.5x figure is caching alone. Enabling image optimization stacks on top of, not instead of, everything described here.

Do I need to change my WordPress theme for any of this?

No. Everything in this case study — cache rules, query normalization, compression, WAF, Redis — is configured at the delivery and hosting layer. The application was not modified.