Image Optimizer reference
The Fastly Image Optimizer (IO) manipulates and transforms images as they pass through the Fastly network, and caches optimized versions of them.
IO interacts with the fetch node in the shield POP (see clustering and shielding). IO-enabled requests that ultimately load an image from origin will transit the shield fetch node twice. This results in both the original and the transformed image being cached at the shield, while just the transformed image will be cached at the edge.
IMPORTANT: If using custom VCL, be aware that at the shield POP, VCL subroutines that normally run on a fetch node (vcl_miss
, vcl_pass
, and vcl_fetch
) will run upstream (i.e., on the origin side) of the image optimizer. As a result, these subroutines handle the request for the original image, while all other VCL subroutines on the shield POP (and all subroutines on the edge POP) are part of the request for the transformed image.
Enabling image optimization
Image optimization is an optional upgrade to Fastly service plans. If you have not yet purchased IO, contact sales.
If your Fastly account is entitled to use image optimization, it can be enabled on an individual service in the web interface or by enabling the image_optimizer
product using the product enablement API.
Once enabled, you can trigger Fastly to pass a request through the image optimizer by adding the x-fastly-imageopto-api
header in vcl_recv
. This is usually done conditionally, so that it applies only to image requests:
if (req.url.ext ~ "(?i)^(?:gif|png|jpe?g|webp)\z" || req.url.path ~ "^/images/") { set req.http.x-fastly-imageopto-api = "fastly";}
HINT: Typically requests are flagged for IO processing using a path match as above, but if you prefer you can also use the content-type of the response.
Services that use image optimization are required to enable shielding.
These steps can also be performed via the web interface.
Other options may also be specified in the x-fastly-imageopto-api
header value. See caching below.
WARNING: IO will only process requests that are eligible for caching. See limitations.
Default behavior
Enabling IO will activate a set of standard transformations and filters intended to provide 'good defaults' that will not change the image's dimensions or visual fidelity. You can modify these in the web interface. Many of these can be further overridden or customized by providing explicit configuration directives as query parameters or headers:
jpg
,pjpg
, andwebp
images will optimized automatically with default quality of 85.- All metadata (for example, EXIF, XMP, or ICC) will be removed.
- If the image contains an ICC profile, the data will be applied directly to the image to ensure color output is correct. If the image doesn't contain an ICC profile, a default profile is added. These behaviors do not apply to
png
orwebp
images. - If the source image contains orientation metadata, this orientation will be applied directly to the image data and metadata will be removed.
- The original
Vary
response header from origins will be removed by IO. See limitations.
Configuration
Often the default transformations will save a significant amount of data without any further effort, but you can customize the behavior with query parameters and headers. For example, the following query string will direct the IO processor to resize the image to 300 pixels wide and crop it to a 16:9 ratio, centered on the most important visual content, including the detection of faces:
/image.png?width=300&crop=16:9,smart
Query parameters
We recognize the following parameters in the query string of the image request:
Parameter | Description |
---|---|
auto | Enable optimization features automatically. |
bg-color | Set the background color of an image. |
blur | Set the blurriness of the output image. |
brightness | Set the brightness of the output image. |
canvas | Increase the size of the canvas around an image. |
contrast | Set the contrast of the output image. |
crop | Remove pixels from an image. |
disable | Disable functionality that is enabled by default. |
dpr | Serve correctly sized images for devices that expose a device pixel ratio. |
enable | Enable functionality that is disabled by default. |
fit | Set how the image will fit within the size bounds provided. |
format | Specify the output format to convert the image to. |
frame | Extract the first frame from an animated image sequence. |
height | Resize the height of the image. |
level | Specify the level constraints when converting to video. |
metadata | Control which metadata fields are preserved during transformation. |
optimize | Automatically apply optimal quality compression. |
orient | Change the cardinal orientation of the image. |
pad | Add pixels to the edge of an image. |
precrop | Remove pixels from an image before any other transformations occur. |
profile | Specify the profile class of application when converting to video. |
quality | Optimize the image to the given compression level for lossy file formatted images. |
resize-filter | Specify the resize filter used when resizing images. |
saturation | Set the saturation of the output image. |
sharpen | Set the sharpness of the output image. |
trim | Remove pixels from the edge of an image. |
width | Resize the width of the image. |
Header parameters
Header | Description |
---|---|
x-fastly-imageopto-montage | Combine up to four images into a single displayed image. |
x-fastly-imageopto-overlay | Overlay one image on top of another image. |
Processing order
Although the parameters can be specified in any order, we normalize the transformation sequence within our system to the following order:
precrop
trim
crop
orient
width
height
dpr
fit
resize-filter
disable
enable
pad
canvas
bg-color
brightness
contrast
saturation
sharpen
blur
x-fastly-imageopto-overlay
format
auto
optimize
quality
profile
level
metadata
If an x-fastly-imageopto-montage
header is specified, all other IO parameters and headers are ignored.
Caching
The original image is only requested and cached once, even if distinct requests might demand versions of the image that are transformed differently.
For example, a user on a desktop device triggers a request for image.png?width=1600
, while a different user on a mobile device requests image.png?width=400
. These requests are considered to be different for the purposes of caching transformed images and will result in different cache objects, but the request to origin is image.png
(with no query parameters). Each transformation is cached as a variant of the original image, and thus the total number of unique transformations is subject to the Vary objects count limit.
IMPORTANT: Image optimization will only be applied to cacheable responses, and for services created on or after May 2, 2023, a minimum cache TTL of 60 seconds is enforced on transformed images (the original image is also cached and has no minimum TTL).
A request with image optimization enabled cannot make use of cached content created by a request that did not have image optimization enabled. Activating a configuration that enables IO on a large number of images may therefore result in a temporary, sharp decrease in cache hit ratio and corresponding increase in traffic to origin. See enabling features gradually if you need to avoid this.
Query string removal
By default, all query parameters are stripped, even those that are not recognized by the image optimizer. To allow passthrough of unknown query parameters, opt-in by changing the value of the X-Fastly-Imageopto-Api
header:
set req.http.X-Fastly-Imageopto-Api = "fastly; qp=*";
With this opt-in enabled, a request for image.png?width=300&something=foo
would trigger the original image to be loaded from your origin server with a request URI of image.png?something=foo
. The known parameter has been removed, but the unknown parameter was passed through.
WARNING: Enabling the qp=*
override may reduce the image cache hit ratio and increase traffic to your origin servers.
Purging images from the Fastly cache
The query string normalization described above happens prior to the vcl_hash
subroutine and the IO query parameters are saved in a secondary hash to allow separation of the variants. This allows all variants of the same image to be purged in a single request.
To purge the original image and all variants, make a purge request without IO parameters:
$ curl -X PURGE https://example.com/image.jpg
It is not possible (and likely never desirable) to purge a single, transformed variant (because a subsequent request for that variant would produce the same result). It is also not possible to purge an original image without purging the transformed images, because subsequent requests would potentially result in caching an inconsistent set of images.
Testing and debugging
When images pass through the IO processor, it will add a header called fastly-io-info
with the following form:
fastly-io-info: ifsz=108501 idim=827x788 ifmt=jpeg ofsz=13066 odim=300x286 ofmt=jpeg
This header provides detail on the input format (ifmt
), dimensions (idim
), and size in bytes (ifsz
), and also the output format (ofmt
), dimensions (odim
), and size in bytes (ofsz
).
Click 'RUN' on the interactive demo below to create an ephemeral Fastly service and make a request through it for an image of former US president Barack Obama.
In this demo, we also show how to calculate the size ratio between the original image and the transformed image by post processing the fastly-io-info
header, dividing ofsz
by ifsz
, and multiplying by 100 to yield a percentage.
Errors and warnings
If an error occurs during image processing, a fastly-io-warning
or fastly-io-error
header is added to the response. The following error scenarios will prevent the image from being processed:
- Image exceeds maximum dimensions
- Image could not be parsed
- Not a supported image format
- Unsupported Content-Encoding
- Gzipped body exceeds maximum length
- Gzipped body could not be decoded
- Invalid status
- Response is pass
- Response is not cacheable
Authenticating IO requests
You may prefer not to expose image optimization parameters publicly. For example, allowing raw image transform parameters to be accepted on inbound client requests may allow an end users to gain access to a higher resolution of your source images than you had intended. One solution is to implement transformation classes. In this example, we map some precomposed IO queries to general labels like "large", "medium", and "small", so that the image request from the client is ?class=large
rather than ?crop=16:9,smart&width=640
.
While not essential, the demo above also includes logic to remove any query parameters that are not the custom class
param, preventing end-user customization of the IO behavior.
Using optimized images and videos in HTML
The Fastly Image Optimizer allows you to generate images to suit the way you want to lay them out on the client device, but it's up to you to prompt the client device to request the most appropriate image variant. If your client device is a web browser and you are serving HTML, then you can make use of responsive images web technologies.
Pixel density
Using the srcset
attribute, it's possible to define images to be used at different display pixel densities, which works well with the width
and dpr
parameters.
<img srcset="/io-demo/image.jpg?width=320&dpr=1.5 1.5x, /io-demo/image.jpg?width=320&dpr=2 2x" src="/io-demo/image.jpg?width=320"/>
Art direction
Use the HTML5 <picture>
element to deliver different image crops at different browser viewport sizes, a technique called art direction:
<picture> <source srcset="/io-demo/image.jpg?width=600&crop=16:9" media="(min-width: 600px)"/> <img src="/io-demo/image.jpg?width=320&crop=1:1"/></picture>
Image type
The <picture>
element can also be used to provide different formats, allowing the browser to choose a format that best suits its needs and is compatible with the formats that it supports:
<picture> <source type="image/webp" srcset="/io-demo/image.webp"/> <source type="image/png" srcset="/io-demo/image.png"/> <img src="/io-demo/image.jpg"/></picture>
Learn more about which image formats are supported in which browsers.
Replacing GIFs with inline video
The animated GIF format benefits from being universally compatible and plays inline on all major web browsers. However, with the introduction of the playsinline
attribute, the <video>
element is now usable in most of the same use cases as GIF. Video formats typically offer far better compression than GIF, and the Image Optimizer can be used to convert existing GIFs into MPEG 4 video:
<video width="300" height="224" playsinline autoplay muted loop> <source src="/io-demo/image.gif?format=mp4" type="video/mp4" /></video>
Origin failover
Sometimes you may want to have more than one origin, often for redundancy purposes (e.g., primary: Amazon S3, secondary: Google Cloud Storage). If a resource does not exist in the primary origin, or the primary is unavailable, then we can perform a restart
and try the secondary origin. We have a code example showing how to do this for normal resources, but there are some caveats to implementing this solution with IO:
- With IO enabled, query parameters will be stripped from the request URL after
vcl_hash
, so won't be present on the restarted request. This can be solved by storing the original request URL in a temporary request header invcl_recv
and reinstating it upon restart. - To ensure that IO draws from the same pre-transform image cache, it's important that shielding is enabled on the primary backend, and that the restart happens on the shield.
Here is an example of how to do this:
Limitations and constraints
- IO will only process requests that are eligible for caching. If the request passes through
vcl_pass
before reaching origin, the response image will not be transformed. - IO is incompatible with the Segmented Caching feature. If IO is enabled, Segmented Caching is disabled automatically.
- The maximum input image file size is 50 Megabytes.
- The maximum input image dimensions are 12,000 x 12,000 pixels.
- The maximum output image dimensions are 8,192 x 8,192 pixels (8K Ultra HD).
- The maximum output image area for AVIF images is 4,096 x 4,096 pixels. AVIF is a premium feature of Fastly's Image Optimizer and choosing it as an encoding format will increase your bill. Specific charges will appear on your service order.
- The maximum number of frames an animated GIF can contain is 1,000.
- We support input images in GIF, JPEG, PNG, or WEBP format.
- We can produce output images in AVIF, GIF, JPEG, MP4, PNG or WEBP format.
- The
Vary
response header is removed by the IO processor automatically aftervcl_fetch
execution at shield POPs, so the originalVary
response header from origins is not passed to downstream clients including edge POPs. This is to avoid multiple variations of the same original of transformed image being cached individually. We recommend also removing theVary
header in your service'svcl_fetch
to ensure this behavior is also applied for requests received directly by shield POPs (the relevant VCL is included in our standard VCL boilerplate).
HINT: If, in order to satisfy CORS, you need to apply an Origin
response header that matches the inbound Origin
request header, we recommend adding that header in vcl_deliver
at edge POPs. This allows one, single copy of the response to be stored in cache and then "customized" as needed for requests that come from different client origins. This advice is equally applicable to all requests, but in the case of IO, it is essential since it is not possible to cache variants for responses that pass through IO.
if (fastly.ff.visits_this_service == 0 && resp.http.Access-Control-Allow-Origin) { set resp.http.Vary:Origin = "";}