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

# Vercel setup

> Route AI assistant traffic to Profound Dynamic Bot Rendering with a single routing rule in vercel.json, with no changes to your application code.

This guide adds one routing rule to your Vercel project. The rule matches requests by `User-Agent`, excludes Profound's own loop-protected fetches, and rewrites matching requests to Profound with your API key and public host attached as request headers.

Nothing in your application changes. Vercel's edge network evaluates the rule before your functions run, and requests from anything other than a supported assistant never match it.

Requests are rewritten to `https://concierge.tryprofound.com/v1/concierge/vercel/{path}`. Profound reconstructs the original path and query from the rewritten URL, so there is no `x-concierge-url` header to maintain. Which paths are rendered is decided by your [policy](/dynamic-bot-rendering/overview#how-rendering-and-serving-are-controlled) in Profound, not by the rule: an assistant request for a path you have not opted in is passed straight through to your deployment.

<Warning>
  **Define the rule in `vercel.json` or `vercel.config.ts`, not in the dashboard.** Confirm that the deployed transform expands the environment variable rather than sending `$PROFOUND_CONCIERGE_KEY` as literal text. A literal value is rejected with `401` and `x-concierge-auth: unknown-key`.

  Before production, validate environment expansion and route precedence in an isolated deployment using a nonsecret test variable and a diagnostic endpoint you control. Do not send your API key to a diagnostic endpoint or log it. Confirm that existing dashboard and framework routes do not override the tested rule.
</Warning>

<Warning>
  **Vercel's routing integration does not provide CDN-level failover.** Profound falls back to your origin only after a request is authenticated and valid. A Profound outage or a hard rejection can reach the assistant as an error, because this external rewrite has no secondary origin to retry.
</Warning>

## Prerequisites

* A Vercel project you can deploy
* Your Dynamic Bot Rendering API key, a registered domain, a policy that opts your public pages in, and a known published test page. See [Before you start](/dynamic-bot-rendering/overview#before-you-start).
* Confirm that deployment protection, firewall rules, and bot challenges permit assistant traffic and Profound's origin fetches without weakening access controls.

## Setup

<Steps>
  <Step title="Add the API key to your project environment">
    In the Vercel dashboard, open **Project → Settings → Environment Variables** and add:

    | Name                     | Value                              | Environments    |
    | ------------------------ | ---------------------------------- | --------------- |
    | `PROFOUND_CONCIERGE_KEY` | Your Dynamic Bot Rendering API key | Production only |

    Keep the key in the environment, never in the rule file. The rule file is committed to your repository.
  </Step>

  <Step title="Add the routing rule">
    Add the following route to your project configuration, replacing `www.example.com` with your registered public host. Use whichever file your project already has.

    <CodeGroup>
      ```json vercel.json theme={null}
      {
        "routes": [
          {
            "src": "^/(.*)$",
            "has": [
              {
                "type": "header",
                "key": "User-Agent",
                "value": "(?i).*(?:duckassistbot|chatgpt-user|gemini-deep-research|perplexity-user|amzn-user|mistralai-user|claude-user|claude-code|codex).*"
              }
            ],
            "missing": [
              {
                "type": "header",
                "key": "x-concierge-request",
                "value": "^1$"
              }
            ],
            "dest": "https://concierge.tryprofound.com/v1/concierge/vercel/$1",
            "transforms": [
              {
                "type": "request.headers",
                "op": "set",
                "target": {
                  "key": "x-concierge-api-key"
                },
                "args": "$PROFOUND_CONCIERGE_KEY",
                "env": [
                  "PROFOUND_CONCIERGE_KEY"
                ]
              },
              {
                "type": "request.headers",
                "op": "set",
                "target": {
                  "key": "x-concierge-host"
                },
                "args": "www.example.com"
              }
            ]
          }
        ]
      }
      ```

      ```ts vercel.config.ts theme={null}
      import type { VercelConfig } from '@vercel/config/v1';

      export const config: VercelConfig = {
        routes: [
          // Route recognized assistants to Profound unless x-concierge-request is set to 1
          {
            src: '^/(.*)$',
            has: [
              {
                type: 'header',
                key: 'User-Agent',
                value:
                  '(?i).*(?:duckassistbot|chatgpt-user|gemini-deep-research|perplexity-user|amzn-user|mistralai-user|claude-user|claude-code|codex).*',
              },
            ],
            missing: [
              {
                type: 'header',
                key: 'x-concierge-request',
                value: '^1$',
              },
            ],
            dest: 'https://concierge.tryprofound.com/v1/concierge/vercel/$1',
            transforms: [
              {
                type: 'request.headers',
                op: 'set',
                target: {
                  key: 'x-concierge-api-key',
                },
                args: '$PROFOUND_CONCIERGE_KEY',
                env: ['PROFOUND_CONCIERGE_KEY'],
              },
              {
                type: 'request.headers',
                op: 'set',
                target: {
                  key: 'x-concierge-host',
                },
                args: 'www.example.com',
              },
            ],
          },
        ],
      };
      ```
    </CodeGroup>

    <Warning>
      Preserve existing routing, redirects, authentication, and framework behavior. Check configuration validation and generated build output for route order and compatibility with existing properties. Current [Vercel routing documentation](https://vercel.com/docs/project-configuration/vercel-json#routes-vs-higher-level-properties) describes coexistence with higher-level properties; do not automatically convert your routing configuration. If integration requires a routing redesign, stop and review that separately.
    </Warning>
  </Step>

  <Step title="Deploy and verify">
    Deploy the project, then:

    ```bash theme={null}
    curl -sD - -o /dev/null https://www.example.com/pricing -A 'chatgpt-user'
    ```

    Check the HTTP status, a valid `x-concierge-request-id`, and the expected `x-concierge-bot-kind`. On your known published page, also require `x-concierge-cache: HIT` and the expected rendered body. Verify that browser requests and search crawlers keep their existing behavior, and that a request carrying `x-concierge-request: 1` reaches your deployment directly.

    Send a `GET` request. Profound's contract covers `GET` only, so use `curl -sD - -o /dev/null` rather than `curl -I`. Full checks are in [Verify and troubleshoot](/dynamic-bot-rendering/verify-and-troubleshoot).
  </Step>
</Steps>

## What each part of the rule does

| Part                               | Purpose                                                                                                                                                                                                           |
| ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `src` + `dest`                     | Captures the whole path as `$1` and rewrites it onto Profound's Vercel endpoint, preserving the query string. Profound decides per path whether to serve a render or pass the request through to your deployment. |
| `has` on `User-Agent`              | Matches the [supported assistants](/dynamic-bot-rendering/overview#supported-ai-assistants), case-insensitively. Browsers and search crawlers never match, so they never leave your existing route.               |
| `missing` on `x-concierge-request` | Loop protection. Profound stamps `x-concierge-request: 1` on its own origin fetches. Excluding that value lets those fetches bypass the rule and reach your deployment directly.                                  |
| `x-concierge-api-key` transform    | Injects the key from the project environment at request time.                                                                                                                                                     |
| `x-concierge-host` transform       | The public host, hard-coded per route. It must match a domain registered in Profound.                                                                                                                             |

<Warning>
  Keep the `missing` condition's `value` exactly `^1$`, or omit `value` to test for the header's absence. Any other regular expression that doesn't match the stamped value silently makes the exclusion a no-op. Profound's own fail-open fetches are then rewritten back to Profound and rejected with `400`.
</Warning>

Non-`GET` requests from a matching `User-Agent` are also rewritten and receive `405` from Profound. Supported assistants fetch pages with `GET`, so this does not affect normal traffic. Add `"methods": ["GET"]` to the route if you want other methods to stay on your deployment.

## Multiple domains

The `x-concierge-host` transform is a fixed string, so one rule serves one public host. If a single Vercel project serves several registered domains, add one route per host and narrow each with a `has` condition on the `host` header:

```json theme={null}
{
  "type": "header",
  "key": "host",
  "value": "^www\\.example\\.com$"
}
```

Place these routes before any catch-all route.

## Preview deployments

The rule above fires on every hostname the project serves, including preview deployments. Because `x-concierge-host` is fixed, a preview request would be identified to Profound as production. Scoping `PROFOUND_CONCIERGE_KEY` to Production only, as in step 1, means preview requests carry an unexpanded literal key and Profound rejects them with `401`, so they can never serve or render production content.

If you want assistant requests on preview hosts to reach your preview deployment normally instead, add the `host` condition from [Multiple domains](#multiple-domains) so the rule only matches your production hostname. See [environment variables in routes](https://vercel.com/docs/project-configuration/vercel-json#using-environment-variables-in-routes) for how unset variables are handled.

## Cache and content checks

Confirm deployed rewrite cache behavior before enabling traffic. [Vercel honors upstream cache headers](https://vercel.com/docs/routing/rewrites#caching-rewrites-to-external-origins) by default for projects created on or after April 6, 2026. Older projects can opt in through project settings or `x-vercel-enable-rewrite-caching`; that header set to `0` opts out. Check project age, the current setting, and route overrides rather than assuming a default. Do not assume a rendered response has `Cache-Control: no-store`: the Vercel adapter does not guarantee it. If your cache rules make these responses cacheable, verify separation between assistant and human responses and between host, path, and query variants. If caching is enabled, verify expiration and invalidation after publishing a replacement, unpublishing, or pausing serving: a CDN entry can outlive the change in Profound.

Profound does not forward viewer cookies or authorization to your origin, and stored pages are not personalized by session, language, or geography. Review same-URL locale and header variants before opting a page in.

## Security notes

* **The loop marker is client-spoofable by design.** Anyone sending `x-concierge-request: 1` skips the rewrite and gets your live origin page, the same content a non-assistant `User-Agent` receives. It skips rendering and telemetry for that request. Never use this marker to bypass authentication or firewall checks.
* **The key stays out of the repository.** It's referenced from the project environment, never written into the rule file.
* **Profound re-derives the assistant itself.** It never trusts a caller-supplied identity header, only the forwarded `User-Agent`.
* **Credentials never reach your origin through Profound.** The rule forwards whatever headers the assistant sent, but Profound drops cookies and authorization headers when it fetches your origin, and only opted-in public pages are rendered.
