# Image delivery

An image built on request still has to reach the browser in a format it reads, and be built once rather than for every reader. On an application, Image Processor builds a derived image from the source image on the origin. How a request becomes a derived image, with the diagram of that chain, is on [How Applications works](/en/documentation/platform/applications/how-it-works/#image-processor).

The sections cover how the delivered format is chosen, how the cache tells one derived image from another, and where Image Processor stops.

---

## Format negotiation

The delivered format is not always the format of the source image. Two mechanisms change it, and they behave differently.

The first is explicit. A `filters:format()` filter in the `ims` string asks for a named output format. Converting to WEBP also requires the request to carry `Accept: image/webp`, and the [Add Request Header](/en/documentation/platform/applications/rules-engine/#add-request-header) behavior adds that header when the browser does not send it.

The second is automatic and needs no `ims` parameter at all. Image Processor detects whether the browser supports WEBP and converts the image when it does. A BMP image is converted to JPEG or WEBP depending on the same support. For example, a request whose `Accept` header lists `image/webp`, with no query string, can receive `image/webp` for a source image stored as PNG.

The bytes on the origin and the bytes on the wire are therefore two different measurements, and the response says so. A processed response carries `x-ims: Enabled`, and `x-original-image-size` carries the size of the source image before the transformation. A reader who never writes a filter can still receive a format other than the one on the origin. Read these headers before you compare a response with the file on the origin. For the headers, refer to [Image Processor settings](/en/documentation/platform/applications/image-processor/settings/#response-headers).

---

## One cache entry per transformation

A derived image is worth building only once. The practice for the cache setting that serves images is to list `ims` in its query-string control: **Cache vary by Query String**, with the **Behavior** *Allowlist* and `ims` in **Fields**. Each distinct `ims` string then has a cache key of its own. That control belongs to the **Application Accelerator** section of a cache setting, `cache_vary_by_querystring` under `modules.application_accelerator`. Varying the cache on `ims` therefore requires Application Accelerator, while processing an image does not.

A cache setting created with that allowlist reads back with this `modules` object:

```json
{
  "modules": {
    "application_accelerator": {
      "cache_vary_by_querystring": {
        "behavior": "allowlist",
        "fields": ["ims"],
        "sort_enabled": false
      },
      "cache_vary_by_cookies": { "behavior": "ignore", "cookie_names": [] },
      "cache_vary_by_devices": { "behavior": "ignore", "device_group": [] },
      "cache_vary_by_method": []
    },
    "cache": {
      "behavior": "honor",
      "max_age": 60,
      "stale_cache": { "enabled": false },
      "large_file_cache": { "enabled": false, "offset": 1024 },
      "tiered_cache": { "enabled": false }
    }
  }
}
```

A derived image converted to another format also carries the format after the `@@` separator, as in `httpsstatic.example.com/static/images/image_1.jpg?ims=880x@@webp`.

That key has a cost, and the cost is cardinality. Every distinct `ims` string is a distinct stored object. A page that asks for arbitrary widths stores an object per width, while a page that asks for four fixed widths stores four. Choosing a small set of sizes is therefore a caching decision as much as a layout one.

It is also a billing decision. An image served from the cache without processing is not counted against the monthly Images meter, so a well-cached derived image costs one processed image however many readers receive it. For what each plan includes, refer to [Applications limits](/en/documentation/platform/applications/limits/#image-processor).

---

## Where Image Processor stops

Image Processor reads a source image and returns a derived one. It does not store images, and it does not accept uploads: the source stays wherever it already lives, and no derived image becomes an asset the account owns. A workflow that needs to keep a transformed file has to save the response itself.

What the `ims` string can express, and the size of the image, bound the transformation. The operations the string accepts are on [Image Processor URL parameters](/en/documentation/platform/applications/image-processor/url-parameters/), and the maximum size and dimensions are on [Applications limits](/en/documentation/platform/applications/limits/#image-processor).

One boundary is worth naming, because two surfaces share a name. **WASM Image Processor** is a WebAssembly library that processes images inside a function on [Functions](/en/documentation/platform/functions/). It is a different surface with a different interface, and nothing on this page configures it.

---

## Related resources

- [Image Processor settings](/en/documentation/platform/applications/image-processor/settings.md): The headers and behaviors of Image Processor, including the response headers of a processed image.
- [Image Processor URL parameters](/en/documentation/platform/applications/image-processor/url-parameters.md): Every operation the ims query string expresses, with the values each one accepts.
- [Configure Image Processor on an application](/en/documentation/guides/application-performance/delivery-optimization/process-images.md): The rule that sends image requests to Image Processor, step by step.
- [Application Accelerator settings](/en/documentation/platform/applications/application-accelerator/settings.md): The query-string control that gives each ims string a cache key of its own.
