If you store images in Amazon S3, you're probably paying more than you need to for bandwidth. Every time a visitor requests an image, S3 serves the original file — full resolution, uncompressed, in whatever format you uploaded it. No resizing, no format conversion, no optimization.
Multiply that by thousands of daily requests and it adds up fast.
There's a straightforward fix: put an image-optimizing CDN between S3 and your users. The CDN fetches the original once, optimizes it (resize, compress, convert to WebP/AVIF), caches it globally, and serves the lighter version from the nearest edge server. Your originals stay untouched in S3.
In this article, I'll walk through how this works using ShortPixel CDN as the optimization layer, but the concept applies broadly to any URL-based image CDN.
The Problem With Serving Raw S3 Images
S3 is excellent for storage. Reliable, cheap per GB, scalable. But it's not an image delivery service. When you serve images directly from S3 (or even through CloudFront without transformation), you're dealing with:
- No compression — that 4MB DSLR photo gets served as-is
- No format negotiation — visitors get JPEG even when their browser handles AVIF at a fraction of the size
- No resizing — mobile users download the same 3000px image as desktop
- Bandwidth costs — AWS charges for every byte of data transfer out
You could build your own optimization pipeline with Lambda + Sharp + CloudFront. It works, but it's infrastructure you need to maintain, and the cold start latency on Lambda can be noticeable for the first request.
The alternative: offload optimization entirely to a service that does it through URL parameters.
How URL-Based Image Optimization Works
The idea is simple. Instead of pointing your <img> tag at the raw S3 URL, you point it at a CDN URL that includes the original image path plus optimization instructions.
Raw S3 URL (no optimization):
https://my-bucket.s3.eu-central-1.amazonaws.com/uploads/hero.jpg
Through an optimizing CDN (resized, compressed, auto-format):
https://cdn.shortpixel.ai/xcf/w_1200+q_lossy+ret_img+to_auto/my-bucket.s3.eu-central-1.amazonaws.com/uploads/hero.jpg
xcfis the API identifier assigned to your ShortPixel account — yours will be different.
The CDN reads the parameters from the URL, fetches the original from S3 via HTTPS, applies the transformations, caches the result, and serves it. Subsequent requests hit the cache directly. No direct AWS API integration is required on your side — ShortPixel handles the connection to your bucket through the credentials you provide in the dashboard.
Available Parameters
| Parameter | Effect |
|---|---|
w_800 |
Resize width to 800px (proportional) |
h_600 |
Resize height to 600px (proportional) |
q_lossy |
Lossy compression (smallest size) |
q_glossy |
Near-lossless (good balance) |
q_lossless |
No quality loss |
to_auto |
Serve AVIF/WebP based on browser support |
ret_img |
Return the image directly |
ret_wait |
Wait for processing before returning |
Chain them with +:
w_1200+q_glossy+ret_img+to_auto
This alone typically cuts image payloads by 40–80%, depending on the originals.
Setting It Up With ShortPixel
1. Connect Your S3 Bucket
In the ShortPixel dashboard, go to Associate Domains → Settings → Amazon S3 and provide:
- Bucket name
- AWS region
- Access key + secret key (from an IAM user with read access to the bucket — only required if your bucket is private)
ShortPixel generates a base CDN URL for your bucket, something like:
https://cdn.shortpixel.ai/xcf
Your identifier will be specific to your account, you'll see it in the dashboard after setup.
2. Construct Your Image URLs
Append optimization parameters and the original S3 path to the base URL:
https://cdn.shortpixel.ai/xcf/w_1200+q_lossy+ret_img+to_auto/my-bucket.s3.eu-central-1.amazonaws.com/uploads/photo.jpg
Use it anywhere — HTML, CSS, JS, API responses:
<img
src="https://cdn.shortpixel.ai/xcf/w_1200+q_lossy+ret_img+to_auto/my-bucket.s3.eu-central-1.amazonaws.com/uploads/photo.jpg"
alt="Optimized product image"
/>
.hero {
background-image: url('https://cdn.shortpixel.ai/xcf/w_1920+q_glossy+ret_img+to_auto/my-bucket.s3.eu-central-1.amazonaws.com/assets/bg.jpg');
}
If you're on WordPress, you can use the ShortPixel Adaptive Images plugin which will do all this automatically if you follow the steps in this article.
3. Private Buckets
If your bucket isn't public, no problem. The AWS credentials you entered in the dashboard handle authentication. ShortPixel fetches the image server-side, and the S3 hostname gets stripped from the final CDN URL, so your bucket details aren't exposed to end users.
A Note on URL Structure
One interesting technical detail: ShortPixel uses a different URL path format for S3 images compared to regular website images. Regular images use /spai/ in the path, while S3 images use a different identifier (e.g., /xcf/). This tells the CDN that the source is an S3 bucket, so it adjusts the path internally to ensure correct delivery and caching.
If You're on WordPress
The ShortPixel Adaptive Images (SPAI) plugin automates this entirely. After connecting your bucket in the dashboard, you configure three things in the plugin:
- Enable Amazon S3 — turns on S3-specific URL handling
-
Storage URL — the base CDN path (e.g.,
https://cdn.shortpixel.ai/xf). Important: just the base, not the full S3 URL. -
Host Removal — your S3 hostname (e.g.,
my-bucket.s3.eu-central-1.amazonaws.com). SPAI strips this from image URLs to build clean CDN paths.
After that, SPAI rewrites image URLs on your pages automatically. No manual URL construction.
For a step by step article on how to configure this, please see this article.
When This Makes Sense (and When It Doesn't)
Good fit:
- You serve user-uploaded images from S3 (marketplaces, SaaS, media sites)
- You have a media-heavy site with images that don't change often
- You want optimization without building/maintaining a Lambda pipeline
- You're on WordPress with S3-hosted media
Maybe not ideal:
- You need heavy custom transformations (watermarking, face detection, complex crops)
- Your images change every few seconds (real-time dashboards, live feeds) — CDN caching won't help much
- You only have a handful of static images — manual optimization with a tool like Squoosh might be simpler
Wrapping Up
The core idea here is simple: don't serve raw images from S3 when a CDN can optimize them on the fly. Whether you use ShortPixel, Cloudinary, ImageKit, or roll your own with CloudFront + Lambda, the principle is the same, transform at the edge, cache aggressively, and let the browser negotiate the best format.
ShortPixel's approach is particularly low-friction because it's entirely URL-based, no SDKs, no build steps, no Lambda functions to maintain. You swap the URL and you're done.

Top comments (0)