Wsrv.nl (formerly known as images.weserv.nl) is a free image resizing proxy and CDN: hand it any public image URL plus a few query parameters, and it returns a resized, converted, and optimized version served from Cloudflare’s global edge cache.
No account, no API key, no build step, the entire API is the URL.
https://wsrv.nl/?url=example.com/photo.jpg&w=600&output=webp
I run every content image on this site through it, and I’ve deployed it on client projects serving millions of pageviews. This article covers how it works, the features I actually reach for, and the full parameter reference.
How It Works
Wsrv.nl is an origin-pull proxy. The first time a URL is requested it fetches the source image, transforms it according to your query parameters, and caches the result on Cloudflare’s CDN. Every subsequent request for that exact URL is served straight from the edge, so your origin server is hit once per variant rather than once per visitor. Cached images are kept and re-validated automatically, and you can control browser caching yourself with the maxage parameter.
The service has been running continuously since 2007, it predates most commercial image CDNs, and now serves billions of images per month for millions of websites. Uptime has been remarkably good for a free service (they publish a public status page at status.wsrv.nl); the one notable rough patch was a Cloudflare terms-of-service change in late 2022 that rate-limited the old images.weserv.nl hostname, which is why the canonical domain is now wsrv.nl, I wrote up the fix in Images.weserv.nl Slow Loading at the time.
Full documentation lives at wsrv.nl/docs.
Useful Features
Resize
Pass w, h, or both. With only one dimension the aspect ratio is preserved automatically, this is the workhorse for responsive images:
# 600px wide, height follows the aspect ratio
https://wsrv.nl/?url=example.com/photo.jpg&w=600
# 400px tall, width follows
https://wsrv.nl/?url=example.com/photo.jpg&h=400
# Both: fits inside a 600x400 box, ratio preserved
https://wsrv.nl/?url=example.com/photo.jpg&w=600&h=400
Convert to WebP
output=webp converts any source format on the fly, typically 25-35% smaller than the equivalent JPEG with no visible difference. This one parameter is the fastest Core Web Vitals win available:
https://wsrv.nl/?url=example.com/photo.jpg&output=webp&q=80
Smart Cropping: Entropy & Attention
When cropping to a fixed shape, a=entropy centers the crop on the busiest region of the image and a=attention on the area most likely to draw the eye (faces, high-contrast zones). Far better than blind center-cropping for cards and thumbnails:
https://wsrv.nl/?url=example.com/photo.jpg&w=400&h=400&fit=cover&a=attention
Tint / Colorize
filt=greyscale plus tint re-colors an image to a single hue. I use this on puck.news to pull editorial photography into their brand palette without touching Photoshop, every image on a listing page tinted consistently, from one URL parameter:
https://wsrv.nl/?url=example.com/photo.jpg&filt=greyscale&tint=79589f
DPR for Retina/High-Res Screens
dpr=2 doubles the output density for the same layout size, so a 300px-wide image ships 600 physical pixels for high-DPI phones and laptops. Pair it with a lower q, dense pixels hide compression artifacts:
https://wsrv.nl/?url=example.com/photo.jpg&w=300&dpr=2&q=70
PDF Preview Images
Point it at a PDF and it renders a page as an image, an on-the-fly document thumbnail with no ImageMagick server setup. page selects which page (zero-based):
https://wsrv.nl/?url=example.com/whitepaper.pdf&w=400&page=0&output=jpg
Sharpen
sharp runs an unsharp mask after resizing. Downscaled headshots and product photos often come out slightly soft; a mild sharpen restores the crispness:
https://wsrv.nl/?url=example.com/headshot.jpg&w=240&h=240&fit=cover&sharp=2
Cover Fit for Featured Image Grids
fit=cover fills the exact target dimensions and crops the overflow, the right behavior for blog listing cards where every featured image must be the same shape regardless of what editors upload:
https://wsrv.nl/?url=example.com/featured.jpg&w=720&h=405&fit=cover&a=entropy&output=webp
Quality
q sets the lossy compression level (1-100, default 80). For content photography 70-80 is visually transparent; go lower for large hero backgrounds where fine detail doesn’t matter:
https://wsrv.nl/?url=example.com/hero.jpg&w=1600&q=60&output=webp
Under the Hood: libvips
The image processing engine behind wsrv.nl is libvips, a demand-driven, horizontally-threaded image library that’s dramatically faster and lighter on memory than ImageMagick, it streams images through the pipeline instead of decompressing the whole file into RAM. It’s the same engine behind sharp (Node.js) and many commercial image services.
The wsrv.nl server itself is open source too: weserv/images is an nginx module wrapping libvips, published under a BSD 3-Clause license. If a free third-party service in your critical rendering path makes you nervous, you can self-host the exact same stack on your own infrastructure and keep the identical URL API, the free public service and full control are the same software, just a different host.
All Available Query Parameters
| Name | GET | Description | |
|---|---|---|---|
| Width | w |
Set the output width in pixels, or as a percentage of the source with a trailing %. |
info |
| Height | h |
Set the output height in pixels, or as a percentage of the source with a trailing %. |
info |
| Device pixel ratio | dpr |
Multiply the output dimensions for high-DPI screens (e.g. dpr=2 doubles the pixel density at the same layout size). |
info |
| Fit | fit |
How the image fills the target box when both dimensions are set: inside, outside, cover (crop overflow), contain (letterbox), or fill (stretch). |
info |
| Contain background | cbg |
Background color for the letterbox bars added by fit=contain. |
info |
| Without enlargement | we |
Never scale the image beyond its source dimensions, small originals stay small instead of upscaling blurry. | info |
| Alignment position | a |
Where a fit=cover crop anchors: an edge or corner (top, bottom-left, …), a focal point, or the smart modes entropy and attention. |
info |
| Rectangle crop | crop |
Cut an exact rectangle from the image as width,height,x,y, applied after any resize. |
info |
| Pre-resize crop | precrop |
Apply the rectangle crop to the original image before resizing, instead of after, coordinates refer to source pixels. | info |
| Trim | trim |
Automatically remove near-uniform borders (whitespace) from all four edges; the value sets the color-difference tolerance. | info |
| Trim background | tbg |
The border color trim should look for, instead of detecting it from the top-left pixel. | info |
| Masking | mask |
Clip the image to a predefined shape: circle, ellipse, triangle, pentagon, hexagon, star, heart, and more. |
info |
| Mask trim | mtrim |
Crop away the transparent whitespace left around the masked shape. | info |
| Mask background | mbg |
Fill the area outside the mask with a color instead of transparency. | info |
| Flip | flip |
Mirror the image vertically (top becomes bottom). | info |
| Flop | flop |
Mirror the image horizontally (left becomes right). | info |
| Rotation | ro |
Rotate the image by any angle in degrees; multiples of 90 are lossless. | info |
| Rotation background | rbg |
Background color revealed in the corners when rotating by a non-right angle. | info |
| Background | bg |
Flatten transparent areas of the image onto a solid color. | info |
| Blur | blur |
Apply a Gaussian blur; the value (0.3-1000) is the sigma, higher = blurrier. | info |
| Contrast | con |
Increase or decrease contrast, from -100 (flat) to +100 (harsh). | info |
| Filter | filt |
Apply a color filter: greyscale, sepia, duotone, or negate. |
info |
| Gamma | gam |
Gamma-correct the image to lighten or darken midtones without clipping highlights or shadows. | info |
| Modulate | mod |
Adjust brightness, saturation, and hue rotation together as comma-separated multipliers. | info |
| Saturation | sat |
Multiply color saturation: 0 is greyscale, 1 unchanged, higher values more vivid. | info |
| Hue rotation | hue |
Rotate every color’s hue around the color wheel by the given number of degrees. | info |
| Sharpen | sharp |
Apply an unsharp mask after resizing, restores crispness lost when downscaling. | info |
| Tint | tint |
Re-color the image’s luminance with the given hex color; combine with filt=greyscale for a clean single-hue result. |
info |
| Adaptive filter | af |
Apply an adaptive row filter before PNG compression, which can shrink PNGs with gradients. | info |
| Base64 (data URL) | encoding |
Return the image as a base64 data URL for inlining directly into an <img src=> attribute. |
info |
| Cache-Control | maxage |
How long browsers (and the CDN) should cache the result, e.g. maxage=31d or maxage=1y. |
info |
| Compression level | l |
PNG zlib compression level from 0-9: higher is smaller but slower to encode (default 6). | info |
| Lossless compression | ll |
Use lossless WebP encoding instead of lossy, pixel-perfect output at larger file sizes. | info |
| Default image | default |
Fallback image URL to redirect to when the source image fails to load, no more broken image icons. | info |
| Filename | filename |
Filename to send in the Content-Disposition header, controlling what a downloaded copy is saved as. |
info |
| Interlace / progressive | il |
Encode PNG/GIF as interlaced and JPEG as progressive, so images render in increasing detail while loading. | info |
| Number of pages | n |
How many pages or frames to render from multi-page sources (PDF, animated GIF/WebP, multi-page TIFF). | info |
| Output | output |
Force the output format: jpg, png, webp, gif, tiff, or json (image metadata). |
info |
| Page | page |
Which page or frame to load from a multi-page source, zero-based (e.g. page=0 is a PDF’s first page). |
info |
| Quality | q |
Lossy compression quality from 1-100 for JPEG, WebP, and TIFF (default 80). | info |