> ## Documentation Index
> Fetch the complete documentation index at: https://ngrok.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Compress Response Action

> Compress HTTP response bodies before they are returned to the client.

export const ConfigEnumOption = ({children}) => {
  return <div className="space-y-2 px-4 py-2 list-none">{children}</div>;
};

export const ConfigEnum = ({label, children}) => {
  return <div className="m-0 flex flex-shrink-0 list-none flex-col divide-y divide-gray-200 self-start rounded-md border border-gray-200 p-0 dark:divide-gray-800 dark:border-gray-800 [&_li+li]:mt-0 [&_li]:py-2 list-none">
      <div className="px-4 py-2 font-semibold list-none">
        {label ? label : "Possible enum values"}
      </div>
      {children}
    </div>;
};

export const ConfigField = ({title, type, cel = false, defaultValue = false, required = false, children}) => {
  const id = `config-${title.replace(/\.|\s|\*/g, "_")}`;
  return <div className="field pt-2.5 pb-5 my-2.5 border-gray-50 dark:border-gray-800/50 border-b" style={{
    scrollMarginTop: '120px'
  }} id={id}>
      <div className="flex font-mono group/param-head param-head break-all relative">
        <div className="flex-1 flex content-start py-0.5 mr-5">
          <div className="flex items-center flex-wrap gap-2">
            <div class="absolute -top-1.5">
              <a href={`#${id}`} className="-ml-10 flex items-center opacity-0 border-0 group-hover/param-head:opacity-100 py-2 [.expandable-content_&]:-ml-[2.1rem]" aria-label="Navigate to header">
                ​<div className="w-6 h-6 rounded-md flex items-center justify-center shadow-sm text-gray-400 dark:text-white/50 dark:bg-background-dark dark:brightness-[1.35] dark:ring-1 dark:hover::rightness-150 bg-white ring-1 ring-gray-400/30 dark:ring-gray-700/25 hover:ring-gray-400/60 dark:hover:ring-white/20">
                  <svg xmlns="http://www.w3.org/2000/svg" fill="gray" height="12px" viewBox="0 0 576 512"><path d="M0 256C0 167.6 71.6 96 160 96h72c13.3 0 24 10.7 24 24s-10.7 24-24 24H160C98.1 144 48 194.1 48 256s50.1 112 112 112h72c13.3 0 24 10.7 24 24s-10.7 24-24 24H160C71.6 416 0 344.4 0 256zm576 0c0 88.4-71.6 160-160 160H344c-13.3 0-24-10.7-24-24s10.7-24 24-24h72c61.9 0 112-50.1 112-112s-50.1-112-112-112H344c-13.3 0-24-10.7-24-24s10.7-24 24-24h72c88.4 0 160 71.6 160 160zM184 232H392c13.3 0 24 10.7 24 24s-10.7 24-24 24H184c-13.3 0-24-10.7-24-24s10.7-24 24-24z"></path></svg>
                </div>
              </a>
            </div>
            <div className="font-semibold text-primary dark:text-primary-light overflow-wrap-anywhere">{title}</div>
            <div className="inline items-center gap-2 text-xs font-medium [&_div]:inline [&_div]:mr-2 [&_div]:leading-5 [&_a]:inline [&_a]:mr-2 [&_a]:leading-5">
              {type && <div className="flex items-center px-2 py-0.5 rounded-md bg-gray-100/50 dark:bg-white/5 break-all">
                <span className="text-gray-600 dark:text-gray-200 !font-medium">{type}</span>
              </div>}
              {defaultValue && <div className="flex items-center px-2 py-0.5 rounded-md bg-gray-100/50 dark:bg-white/5 break-all">
                  <span class="text-gray-400 dark:text-gray-500">default:</span>
                  <span className="text-gray-600 dark:text-gray-200 !font-medium">{defaultValue}</span>
                </div>}
              {required && <div className="px-2 py-0.5 rounded-md bg-red-100/50 dark:bg-red-400/10 whitespace-nowrap">
                <span className="text-red-600 dark:text-red-300 !font-medium">Required</span>
              </div>}
              {cel && <a className="px-2 py-0.5 rounded-md !border-none bg-blue-100/50 dark:bg-blue-400/10 whitespace-nowrap" href="/traffic-policy/concepts/cel-interpolation">
                <span className="text-blue-600 dark:text-blue-300 !font-medium">Supports CEL</span>
              </a>}
            </div>
          </div>
        </div>
      </div>
      <div className="mt-4 prose-sm prose-gray dark:prose-invert [&_.prose>p:first-child]:mt-0 [&_.prose>p:last-child]:mb-0">
        {children}
      </div>
    </div>;
};

The Compress Response Traffic Policy action enables you to improve the
performance of your web applications by compressing HTTP response bodies returned
by your upstream service.

## Configuration reference

The [Traffic Policy](/traffic-policy/) configuration
reference for this action.

### Supported phases

`on_http_response`

### Type

`compress-response`

### Configuration fields

<ConfigField title="algorithms" type="array of strings" defaultValue="['gzip', 'deflate', 'br', 'compress']">
  A list of allowed compression algorithms to be considered during encoding
  type negotiation. Each element must be unique.

  <ConfigEnum label="Supported algorithms">
    <ConfigEnumOption>`br`</ConfigEnumOption>
    <ConfigEnumOption>`compress`</ConfigEnumOption>
    <ConfigEnumOption>`deflate`</ConfigEnumOption>
    <ConfigEnumOption>`gzip`</ConfigEnumOption>
  </ConfigEnum>
</ConfigField>

## Behavior

When an HTTP request includes an `Accept-Encoding` header, HTTP responses are
automatically compressed, and a Content-Encoding header is added to the
response.

If the response is already compressed by your upstream service,
no additional compression will be applied.

### Streaming compression

When compression is applied, the response body is not buffered; it is
compressed in real-time as it streams through the ngrok endpoint.

### Algorithm choice

If a request specifies `Accept-Encoding` but none of the requested algorithms
are supported, no compression is applied, and the upstream response is returned
unmodified.

### Quality values

Compression is negotiated based on the `Accept-Encoding` header as defined by
the [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-accept-encoding),
respecting q-values and selecting the supported algorithm with the highest
q-value.

For example:

```bash theme={null}
Accept-Encoding: gzip;q=1.0, br; q=0.5, *;q=0
```

The algorithm `gzip` would be selected because it has the highest q-value of `1.0`.

### Response headers

When this action performs compression, the following changes are made to the
HTTP response headers:

* The `Content-Length` header is removed.
* A `Content-Encoding` header is added, specifying the negotiated algorithm.
* A `Vary: Accept-Encoding` header is added to indicate that the response varies
  based on the `Accept-Encoding` request header.

### Non-terminating action

This is a **Non-terminating action**. It does not return a response, and will allow Traffic Policy processing to continue to the next Action in the chain. All **Cloud Endpoint** Traffic Policies must end with a terminating action. This requirement does not apply to **Agent Endpoints**.

## Examples

### Compressing API responses based on URL path

The following [Traffic Policy](/traffic-policy/)
configuration demonstrates how to set this up using the `compress-response`
action with an expression to compress traffic on specific URL paths.

#### Example Traffic Policy document

<CodeGroup>
  ```yaml policy.yml highlight={3} theme={null}
  on_http_response:
    - expressions:
        - "req.url.path.startsWith('/api/')"
      actions:
        - type: "compress-response"
          config:
            algorithms:
              - "gzip"
              - "br"
              - "deflate"
              - "compress"
  ```

  ```json policy.json highlight={5} theme={null}
  {
    "on_http_response": [
      {
        "expressions": [
          "req.url.path.startsWith('/api/')"
        ],
        "actions": [
          {
            "type": "compress-response",
            "config": {
              "algorithms": [
                "gzip",
                "br",
                "deflate",
                "compress"
              ]
            }
          }
        ]
      }
    ]
  }
  ```
</CodeGroup>

For this example, assume that an ngrok agent is pointing at the
upstream service [https://jsonplaceholder.typicode.com](https://jsonplaceholder.typicode.com).

#### Example request

```bash theme={null}
$ curl -i https://jsonplaceholder.ngrok.app/api/posts
```

```http theme={null}
HTTP/2 200 OK
content-encoding: gzip
content-type: application/json; charset=utf-8

<compressed-body-here>
```

In this example, when a request is made to `/api/posts`,
ngrok compresses the response using one of the specified algorithms
(for example, `gzip`). The response includes the `content-encoding: gzip` header, and
the body is compressed accordingly.

This setup ensures that only API responses
for paths starting with `/api/` are compressed, enhancing performance and
responsiveness for only those endpoints.

## Action result variables

The following variables are made available for use in subsequent expressions and
CEL interpolations after the action has run. Variable values will only apply
to the last action execution, results are not concatenated.

<ConfigField title="actions.ngrok.compress.already_compressed" type="boolean">
  Indicates whether the body was already compressed before the action was
  applied. Returns <code>true</code> if no further compression was
  performed.
</ConfigField>

<ConfigField title="actions.ngrok.compress.negotiated_algorithm" type="string">
  The compression algorithm selected and applied by the action, based on the
  client's request and action configuration.
</ConfigField>
