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

# Proxy Guide

> How to run the embedded Corti Assistant behind a reverse proxy

When the Corti Assistant is embedded in a host application, all network traffic from the embedded app may be routed through a proxy controlled by the host application. The proxy sits between the client and the Corti backend services.

```
Host application
  └── Embedded Corti Assistant
       ├── HTTP requests  → Proxy → Corti web app
       └── WebSocket       → Proxy → Corti WebSocket backend
```

The Corti web app already proxies all third-party service traffic (analytics, feature flags) server-side through its own API routes. This means the proxy only needs to handle two types of traffic:

1. **HTTP requests** to the Corti web app
2. **WebSocket connections** to the Corti real-time backend

***

## Upstream URLs

The proxy forwards traffic to two upstream services. The exact URLs depend on your region:

| Region | Corti web app                      | WebSocket backend        |
| ------ | ---------------------------------- | ------------------------ |
| EU     | `https://assistant.eu.corti.app`   | `wss://api.eu.corti.app` |
| EU MD  | `https://assistantmd.eu.corti.app` | `wss://api.eu.corti.app` |
| US     | `https://assistant.us.corti.app`   | `wss://api.us.corti.app` |

<Note>Use the URLs that match the region your Corti tenant is provisioned in. Contact support if you are unsure which region applies.</Note>

***

## Choose a Proxy Mode

Configure your proxy in one of two ways. Use the same mode consistently for the iframe URL, HTTP routing, and WebSocket routing.

| Mode                      | Public Assistant URL                           | HTTP request sent to Corti web app | Prefix header                            | Public WebSocket URL                               |
| ------------------------- | ---------------------------------------------- | ---------------------------------- | ---------------------------------------- | -------------------------------------------------- |
| Proxy root (without path) | `https://proxy.example.com/embedded`           | `/embedded`                        | Do not set `Corti-Forwarded-Prefix`      | `wss://proxy.example.com/audio-bridge/*`           |
| Proxy subpath (with path) | `https://proxy.example.com/assistant/embedded` | `/assistant/embedded`              | Set `Corti-Forwarded-Prefix: /assistant` | `wss://proxy.example.com/assistant/audio-bridge/*` |

For subpath deployments, `/assistant` is only an example. You can choose any external path prefix, such as `/corti-assistant` or `/vendor/corti`, as long as your proxy forwards HTTP requests with that prefix intact and sends the same value in `Corti-Forwarded-Prefix`.

***

## HTTP Request Forwarding

All HTTP requests from the embedded app are forwarded to a single upstream — the Corti web app.

### Proxy root (without path)

When Corti Assistant is hosted at the proxy root, forward the request path unchanged and do not set `Corti-Forwarded-Prefix`.

```
Client → https://proxy.example.com/* → https://assistant.eu.corti.app/*
```

No path rewriting is needed. The proxy passes through the full request path, query string, method, and body unchanged.

### Proxy subpath (with path)

If you host the embedded app under a subpath (for example `https://proxy.example.com/assistant/`),
forward the public prefixed HTTP path to the Corti web app unchanged and set
`Corti-Forwarded-Prefix` to the external base path.

```
Client → https://proxy.example.com/assistant/embedded
      → https://assistant.eu.corti.app/assistant/embedded
```

Do not strip the subpath before forwarding HTTP requests to the Corti web app. The Corti Assistant
runtime base path shim strips the prefix internally and rewrites response URLs so browser requests
continue to stay under the public subpath.

<Note>
  `X-Forwarded-Prefix` is not the supported external contract for Corti Assistant subpath hosting.
  Use `Corti-Forwarded-Prefix`.
</Note>

### Required Headers

The proxy must set the following headers on every HTTP request forwarded to the Corti web app:

| Header                  | Value                                                                     | Example             |
| ----------------------- | ------------------------------------------------------------------------- | ------------------- |
| `Corti-Forwarded-For`   | The original client IP, or a trusted client IP chain maintained by proxy. | `192.168.1.100`     |
| `Corti-Forwarded-Host`  | The `Host` header as seen by the proxy (the proxy's own hostname).        | `proxy.example.com` |
| `Corti-Forwarded-Proto` | The protocol used between the client and the proxy.                       | `https`             |

If you host the embedded app under a subpath, also set:

| Header                   | Value                                            | Example      |
| ------------------------ | ------------------------------------------------ | ------------ |
| `Corti-Forwarded-Prefix` | The external base path used for subpath hosting. | `/assistant` |

<Info>
  Corti may translate these headers into standard `X-Forwarded-*` headers inside Corti-controlled
  infrastructure. Customer proxies should use the `Corti-Forwarded-*` headers documented here.
</Info>

<Note>
  In production, set `Corti-Forwarded-Host` from a normalized or fixed proxy hostname. If your
  proxy runs behind another trusted load balancer, configure your proxy's real IP handling before
  setting `Corti-Forwarded-For`.
</Note>

**Example** — forwarding a request:

Proxy root, without path:

```http theme={null}
# Original request from client
GET https://proxy.example.com/api/interactions HTTP/1.1
Host: proxy.example.com

# Forwarded to upstream
GET https://assistant.eu.corti.app/api/interactions HTTP/1.1
Host: assistant.eu.corti.app
Corti-Forwarded-For: 192.168.1.100
Corti-Forwarded-Host: proxy.example.com
Corti-Forwarded-Proto: https
```

Proxy subpath, with path:

```http theme={null}
# Original request from client
GET https://proxy.example.com/assistant/api/interactions HTTP/1.1
Host: proxy.example.com

# Forwarded to upstream
GET https://assistant.eu.corti.app/assistant/api/interactions HTTP/1.1
Host: assistant.eu.corti.app
Corti-Forwarded-For: 192.168.1.100
Corti-Forwarded-Host: proxy.example.com
Corti-Forwarded-Proto: https
Corti-Forwarded-Prefix: /assistant
```

### Response Handling

Your proxy returns the upstream response to the client as-is. No modification of status codes, headers, or body is required in your proxy.

For subpath deployments, the Corti web app runtime base path shim handles its own URL rewriting before the response reaches your proxy.

***

## WebSocket Forwarding

The Corti Assistant uses WebSocket connections for real-time audio streaming and clinical sessions. The proxy must handle the HTTP `Upgrade: websocket` handshake and bidirectionally forward all WebSocket frames.

### Routing

The Corti WebSocket backend expects the `/audio-bridge/` path prefix.

For proxy-root deployments, the public WebSocket path is forwarded unchanged:

```
wss://proxy.example.com/audio-bridge/* → wss://<websocket-backend>/audio-bridge/*
```

The path and query string are preserved when forwarding. For example:

```
wss://proxy.example.com/audio-bridge/v1/transcribe?token=Bearer%20abc123
  → wss://api.eu.corti.app/audio-bridge/v1/transcribe?token=Bearer%20abc123
```

For subpath deployments, the public WebSocket path includes the same prefix as the iframe URL. Strip that prefix before forwarding to the WebSocket backend:

```
wss://proxy.example.com/assistant/audio-bridge/v1/transcribe?token=Bearer%20abc123
  → wss://api.eu.corti.app/audio-bridge/v1/transcribe?token=Bearer%20abc123
```

<Note>
  `Corti-Forwarded-Prefix` is used by the Corti web app. The WebSocket backend still expects
  `/audio-bridge/*` paths.
</Note>

### Connection Lifecycle

1. **Upgrade** — When the proxy receives a request with `Upgrade: websocket`, it establishes a WebSocket connection to the appropriate upstream based on the path.
2. **Message forwarding** — All messages (text and binary) are forwarded bidirectionally between the client and upstream. Messages sent by the client before the upstream connection is established should be buffered and flushed once the upstream is ready.
3. **Close** — When either side closes the connection, the proxy closes the other side.
4. **Idle timeout** — WebSocket connections can be long-lived. Set the idle timeout high enough to avoid dropping active audio sessions (recommended: at least 4 minutes).

***

## Client-Side Configuration

HTTP requests do not require any client-side configuration. Because the embedded Assistant is loaded from the proxy URL (the iframe `src` points to the proxy), all HTTP requests from the app naturally route through the proxy.

WebSocket connections, however, connect to a separate backend host by default. To route them through the proxy, the host application must set `websocketBaseUrl` using `configureApp()`.

The host application sends `configureApp()` with the `network.websocketBaseUrl` property. For implementation details, see the [PostMessage API](/assistant/postmessage-api) or [Window API](/assistant/window-api) documentation.

```javascript theme={null}
// Using the PostMessage API
postMessage({
  type: "CORTI_EMBEDDED",
  version: "v1",
  action: "configureApp",
  requestId: "unique-id",
  payload: {
    network: {
      websocketBaseUrl: "wss://proxy.example.com",
    },
  },
});

// Using the Window API
await window.CortiEmbedded.v1.configureApp({
  network: {
    websocketBaseUrl: "wss://proxy.example.com",
  },
});
```

When `websocketBaseUrl` is set, the app sends WebSocket connections through the proxy.

For proxy-root deployments, set `websocketBaseUrl` to the proxy origin:

```
Original:  wss://api.eu.corti.app/audio-bridge/v1/transcribe?token=xyz
Rewritten: wss://proxy.example.com/audio-bridge/v1/transcribe?token=xyz
```

The path and query string are preserved. This is what enables the proxy to route connections based on `/audio-bridge/*`.

For subpath deployments, set `websocketBaseUrl` to the same public origin and subpath used by the iframe URL. The Corti Assistant runtime base path shim keeps same-origin WebSocket requests under that subpath, so your proxy can route them before stripping the prefix for the WebSocket backend.

```javascript theme={null}
await window.CortiEmbedded.v1.configureApp({
  network: {
    websocketBaseUrl: "wss://proxy.example.com/assistant",
  },
});
```

<Tip>Call `configureApp()` **before** the user starts an interaction. You can call it any time after the embedded app has loaded and the `ready` event has been received. The configuration persists for the duration of the session.</Tip>

***

## NGINX Example (Proxy Root)

A complete NGINX configuration for proxying the embedded Corti Assistant. Replace the upstream URLs with the values for your [region](#upstream-urls).

<Note>This example listens on port 80 for simplicity. For production, add TLS termination (`listen 443 ssl`) and certificate paths.</Note>

```nginx theme={null}
resolver 1.1.1.1 8.8.8.8 valid=30s;

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;

    # Large auth tokens / cookies can exceed the default 8k request header limit
    large_client_header_buffers 4 32k;

    # Replace with the upstream URLs for your region
    set $corti_web assistant.eu.corti.app;
    set $corti_ws  api.eu.corti.app;

    # ── WebSocket: /audio-bridge/* → Corti WebSocket backend ──

    location /audio-bridge/ {
        proxy_pass https://$corti_ws;
        proxy_ssl_server_name on;
        proxy_set_header Host $corti_ws;

        # WebSocket upgrade
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        # Long-lived connections — at least 4 minutes
        proxy_read_timeout 300s;
        proxy_send_timeout 300s;
    }

    # ── Everything else → Corti web app ──

    location / {
        proxy_pass https://$corti_web;
        proxy_ssl_server_name on;
        proxy_set_header Host $corti_web;

        # Large auth tokens require bigger buffers than the default 4k
        proxy_buffer_size 16k;
        proxy_buffers 4 16k;

        # Corti Assistant forwarding headers
        proxy_set_header Corti-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Corti-Forwarded-Host $host;
        proxy_set_header Corti-Forwarded-Proto $scheme;
    }
}
```

### NGINX Example (Subpath Hosting)

Example configuration for hosting the embedded app under `/corti-assistant/`. Replace every `/corti-assistant` occurrence with the external subpath you choose.

This setup:

* Serves all Assistant HTTP routes under `/corti-assistant/*`
* Sends the prefixed HTTP path to the Corti web upstream unchanged
* Routes WebSocket `/corti-assistant/audio-bridge/*` to the Corti WebSocket upstream after stripping the subpath prefix

```nginx theme={null}
resolver 1.1.1.1 8.8.8.8 valid=30s;

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;

    large_client_header_buffers 4 32k;

    set $corti_web assistant.eu.corti.app;
    set $corti_ws  api.eu.corti.app;

    location = /corti-assistant {
        return 308 /corti-assistant/;
    }

    # WebSocket bridge
    location ^~ /corti-assistant/audio-bridge/ {
        rewrite ^/corti-assistant(/audio-bridge/.*)$ $1 break;
        proxy_pass https://$corti_ws;
        proxy_ssl_server_name on;
        proxy_set_header Host $corti_ws;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_read_timeout 300s;
        proxy_send_timeout 300s;
    }

    # Public prefixed app routes. Keep the /corti-assistant prefix intact.
    location ^~ /corti-assistant/ {
        proxy_pass https://$corti_web;
        proxy_ssl_server_name on;
        proxy_set_header Host $corti_web;

        proxy_buffer_size 16k;
        proxy_buffers 4 16k;

        proxy_set_header Corti-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Corti-Forwarded-Host $host;
        proxy_set_header Corti-Forwarded-Proto $scheme;
        proxy_set_header Corti-Forwarded-Prefix /corti-assistant;
    }
}
```

***

## Implementation Checklist

* [ ] Forward all HTTP requests to the Corti web app upstream URL
* [ ] Set `Corti-Forwarded-For`, `Corti-Forwarded-Host`, and `Corti-Forwarded-Proto` headers on HTTP requests to the Corti web app
* [ ] If using subpath hosting, set `Corti-Forwarded-Prefix` and keep the public subpath prefix on HTTP requests to the Corti web app
* [ ] Handle WebSocket `Upgrade` requests
* [ ] Route `/audio-bridge/*` WebSocket connections to the Corti WebSocket backend
* [ ] If using subpath hosting, strip the subpath prefix before matching/forwarding WebSocket `/audio-bridge/*` routes
* [ ] Buffer client WebSocket messages until the upstream connection is established
* [ ] Send the `configureApp` action from the host application with `network.websocketBaseUrl` set to the proxy URL
