Documentation
Everything the image proxy does, and how to use it on your site.
URL format
Pass the address of the original image in the url parameter:
https://serveproxy.com/?url=https%3A%2F%2Fexample.com%2Fimages%2Fphoto.jpg
Encode the source URL with encodeURIComponent or your language's equivalent. Unencoded URLs work when they have no query string of their own, but encoding is always safe.
Each distinct source URL is converted and cached separately. photo.jpg and photo.jpg?v=2 are two different images.
Request lifecycle
- Check. The request is checked against the rate limit and the source domain against our blocklists.
- Fetch. On a cache miss, the image is downloaded from your server over HTTPS (http:// sources are upgraded). Requests to private and internal network addresses are refused.
- Detect. The file type is read from the image's bytes, not from its extension or the
Content-Typeyour server sent. - Convert. The image is converted according to the table below.
- Cache. The result is served with a 7-day immutable
Cache-Controlheader and cached by Cloudflare's edge network.
The first request for an image usually takes one to three seconds. Every request after that is served from cache.
Output formats
| Source | Output | Settings |
|---|---|---|
| JPEG, PNG, static GIF, BMP, TIFF, HEIC | AVIF | Quality 65, metadata stripped |
| WebP (static or animated) | WebP | Passed through unchanged |
| Animated GIF | Animated WebP | Frame timing and looping kept |
| SVG | SVG | Sanitized, served with a restrictive Content-Security-Policy |
AVIF cases with jxl=true | JPEG XL | Quality 75, effort 7, metadata stripped |
SVG sanitization removes <script> elements, <foreignObject>, on… event handlers and javascript: links. The drawing itself is left intact.
Multi-frame sources other than GIF (for example animated PNG or multi-page TIFF) are converted from their first frame.
JPEG XL
Optional output format.
Add jxl=true as the first query parameter. It has to come before url=, because everything after url= is treated as part of the source address.
https://serveproxy.com/?jxl=true&url=https%3A%2F%2Fexample.com%2Fphoto.jpg
Limited browser support. JPEG XL renders in Safari on macOS and iOS. Chrome, Edge and Firefox don't display it by default. Use it only inside a <picture> element with an AVIF fallback:
<picture>
<source type="image/jxl"
srcset="https://serveproxy.com/?jxl=true&url=https%3A%2F%2Fexample.com%2Fphoto.jpg">
<img src="https://serveproxy.com/?url=https%3A%2F%2Fexample.com%2Fphoto.jpg"
alt="Harbour at dusk" loading="lazy">
</picture>
WebP, animated GIF and SVG sources keep their normal output when jxl=true is set.
Limits
| Limit | Value |
|---|---|
| Uncached requests per IP | 5,000 every 10 minutes |
| Block after exceeding the limit | 1 hour |
| Maximum source image size | 5 MB |
| Source fetch timeout | 15 seconds |
Requests answered from Cloudflare's cache never reach our servers and don't count toward the limit. Responses from our servers include X-RateLimit-Remaining.
Integration examples
HTML
<img src="https://serveproxy.com/?url=https%3A%2F%2Fexample.com%2Fimage.jpg"
alt="Description" loading="lazy">
JavaScript
function optimized(originalUrl) {
return "https://serveproxy.com/?url=" + encodeURIComponent(originalUrl);
}
img.src = optimized("https://example.com/image.jpg");
Responsive images
<img src="https://serveproxy.com/?url=https%3A%2F%2Fexample.com%2Fimage-800.jpg"
srcset="https://serveproxy.com/?url=https%3A%2F%2Fexample.com%2Fimage-800.jpg 800w,
https://serveproxy.com/?url=https%3A%2F%2Fexample.com%2Fimage-1600.jpg 1600w"
sizes="(max-width: 800px) 100vw, 800px"
alt="Description" loading="lazy">
Serveproxy doesn't resize images, so provide each size from your own server.
WordPress
The free plugin rewrites image URLs on your pages automatically, with no theme changes.
Response headers
Use these to confirm what was served.
| Header | Meaning |
|---|---|
Content-Type | The output format: image/avif, image/webp, image/svg+xml or image/jxl |
CF-Cache-Status | HIT when Cloudflare served the image from cache |
Cache-Control | public, max-age=604800, immutable (7 days) |
ETag | Lets browsers revalidate with If-None-Match and get a 304 |
X-Serveproxy-Image-Hash | Identifier for the source URL. Include it when you contact support |
X-Serveproxy-Node | The server that converted the image |
Troubleshooting
| Response | What it means and what to do |
|---|---|
| 400 | The url parameter is missing, isn't a valid address, or points back at Serveproxy itself. Check that it's encoded. |
| 403 | The source domain is on one of our blocklists. |
| 404 and other 4xx | Your server returned this status for the source image. Open the source URL directly to check it. |
| 413 | The source image is larger than 5 MB. Resize or compress it on your server. |
| 415 | The source isn't an image we can read. Check that the URL returns the image itself, not an HTML page. |
| 429 | Your IP made more than 5,000 uncached requests in 10 minutes. Wait for the block to expire (1 hour). |
| 502 | Your server didn't respond, timed out after 15 seconds, or returned a 5xx error. Retry in a minute. |
| Image is outdated | Cached images are immutable for 7 days. Change the source URL, for example with ?v=2. |
Error responses are cached briefly by Cloudflare: 30 seconds for 502, 5 minutes for 404, 1 hour for 400, 403, 413 and 415.
Live status is at serveproxy.status.hesklo.com. For anything else, email [email protected].