> ## 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.

# Verify and troubleshoot

> Confirm Dynamic Bot Rendering is routing correctly, read the x-concierge-* diagnostic headers, and resolve the common setup failures.

## Test your setup

Every check below sends a `GET` request. Profound's contract covers `GET` only, so use `curl -sD - -o /dev/null` rather than `curl -I`, which sends `HEAD`. A `HEAD` response may come from your origin or from a handler that omits the body, and tells you nothing about routing.

<Steps>
  <Step title="Assistant traffic should reach Profound">
    ```bash theme={null}
    curl -sD - -o /dev/null https://www.example.com/pricing -A 'chatgpt-user'
    ```

    Look for a UUID in `x-concierge-request-id` and `x-concierge-bot-kind: chatgpt-user`. Together they prove your CDN routed the request to Profound and Profound recognized the assistant. They do not prove a rendered page was served: a `MISS` with `x-concierge-failopen: 1` means Profound returned your origin's live content.
  </Step>

  <Step title="Your published test page should be served from Profound">
    On the page you published during [setup](/dynamic-bot-rendering/overview#before-you-start), also require `x-concierge-cache: HIT` and the rendered HTML. Save the body for comparison, and let curl decompress it in case Profound served it gzip-encoded:

    ```bash theme={null}
    curl -sS --compressed -D /tmp/dbr-headers.txt -o /tmp/dbr-page.html \
      https://www.example.com/pricing -A 'chatgpt-user'
    ```

    If this request is a `MISS`, check the `x-concierge-policy` headers as described in [Reading the result](#reading-the-result). Repeating the request does not turn a `MISS` into a `HIT`; only publishing a render does.
  </Step>

  <Step title="Human traffic should be untouched">
    ```bash theme={null}
    curl -sD - -o /dev/null https://www.example.com/pricing \
      -A 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36'
    ```

    Expect no `x-concierge-*` headers and the same page content as before. Compare latency and cache hit rates with your baseline too: a Worker or a shared cache-policy change can affect them even when routing is unchanged.
  </Step>

  <Step title="Search crawlers should be untouched">
    ```bash theme={null}
    curl -sD - -o /dev/null https://www.example.com/pricing -A 'Googlebot/2.1'
    ```

    Also expect no `x-concierge-*` headers. If this request is routed, see [Common problems](#common-problems).
  </Step>

  <Step title="Excluded traffic should keep its existing behavior">
    In staging, send non-`GET` methods, requests to `/api/users`, `/graphql`, authentication, admin, framework resources, and assets, including extensionless endpoints. Use harmless fixture endpoints for methods that could modify data, and nonsecret test values for cookies and authorization headers. All of these must stay on your existing route. On Vercel, also test preview and alternate hosts.
  </Step>

  <Step title="Test failure behavior safely">
    Use staging or an isolated configuration, record the original settings, and restore them after each test.

    * **Cloudflare:** test an unreachable upstream, a response-header timeout, and one of the configured fallback statuses. Expect origin content with `x-concierge-cdn-failover: 1`. Redirects, `404`, and `429` pass through, and a response that has already started streaming cannot be replaced.
    * **CloudFront:** test primary connection and response timeouts within the configured budget and the selected status criteria. Expect the fallback origin for configured failures, but not for `401`. Send uncached requests, and expect cached fallback responses to persist until their TTL expires even after you restore the primary.
    * **Vercel:** there is no CDN-level failover. During a Profound outage or after a hard rejection, an assistant can receive an error. Do not expect transparent origin fallback.

    After restoring the configuration, wait for propagation and repeat the routing and published-page checks.
  </Step>
</Steps>

## Run setup verification from the dashboard

The Profound dashboard can test your routing for you. It sends a request with each of the nine supported assistant `User-Agent` values to a URL on your registered host, from outside your network, and reports which ones your CDN routed to Profound.

These probes carry no credentials and no loop marker, so they look like real assistant traffic to your CDN. An assistant counts as routed only when its response carries a valid request ID and the matching bot kind. A `MISS`, a paused domain, a redirect, or a non-`200` status can still confirm routing; page health is reported separately. Make sure the URL you test is on your public-page allowlist, or every assistant will correctly show as not routed.

<Note>
  Setup verification is a live observation of one URL at one moment. It confirms that your CDN rule fires for each assistant. It does not verify domain ownership, and it is not a substitute for checking your published test page by hand.
</Note>

## Response header reference

| Header                      | Meaning                                                                                                                                                                             |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `x-concierge-request-id`    | A UUID Profound assigns to every request it handles. Its absence means Profound never saw the request: the rule did not match, the CDN failed over, or a proxy stripped the header. |
| `x-concierge-cache`         | `HIT` when a published render was served, `MISS` when Profound fell back to your origin.                                                                                            |
| `x-concierge-bot-kind`      | The assistant Profound recognized, or `unknown`.                                                                                                                                    |
| `x-concierge-failopen`      | `1` when live origin content was returned instead of a stored render.                                                                                                               |
| `x-concierge-origin-status` | Your origin's HTTP status, when your origin was fetched.                                                                                                                            |
| `x-concierge-policy`        | The effective mode for this request: `serve`, `warm`, or `off`. See [policy modes](/dynamic-bot-rendering/overview#policy-modes).                                                   |
| `x-concierge-policy-source` | Which level decided that mode: `page` for a page rule, `domain` for the domain default or a paused domain, or `default` when no rule applied.                                       |
| `x-concierge-policy-rule`   | The ID of the winning rule, when there was one.                                                                                                                                     |
| `x-concierge-auth`          | On `401` only: `missing-key`, `unknown-key`, or `inactive-key`.                                                                                                                     |
| `x-concierge-cdn-failover`  | Set by the Cloudflare Worker in these guides, not by Profound, when it served your origin after a failed upstream call.                                                             |

## Reading the result

| What you see                                                  | What it means                                                                                                                                                                                                         |
| ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cache: HIT`                                                  | A published render was served. Also check the status and the body.                                                                                                                                                    |
| `MISS` + `failopen: 1` + `policy: serve`                      | Policy allows serving, but the URL has no usable publication. Render, review, and publish a candidate for this exact path and query.                                                                                  |
| `MISS` + `failopen: 1` + `policy: warm`                       | `warm` serves origin content even when a publication exists. Change the winning rule to `serve` once you are ready.                                                                                                   |
| `MISS` + `policy: off` + `policy-source: default`             | No rule covers this path, so it is not opted in. Add a domain default or a page rule.                                                                                                                                 |
| `MISS` + `policy: off` + `policy-source: domain` + no rule ID | The domain is paused. Resume it in the dashboard.                                                                                                                                                                     |
| `MISS` + `policy: off` + a rule ID                            | The winning rule is `off`, or it excludes this assistant from its allowed list. With `policy-source: domain` that rule is the domain default. Check its mode and allowed assistants.                                  |
| `bot-kind: unknown`                                           | Your CDN routed a `User-Agent` Profound doesn't recognize. The request added a round trip and got origin content. Align your rule with the [supported list](/dynamic-bot-rendering/overview#supported-ai-assistants). |
| No `x-concierge-*` headers on an assistant request            | Profound never saw the request. Check the rule's match conditions and, on Cloudflare and CloudFront, whether CDN failover fired.                                                                                      |

## Error responses

Profound only falls back to your origin after a request is authenticated and valid. Configuration errors are rejected rather than proxied. Cloudflare's Worker masks its configured rejection statuses by serving your origin, and CloudFront masks `400` and `403` but not `401`. Vercel has no retry. When an origin page appears where you expected a rejection, inspect your CDN's diagnostics.

| Status                                  | Cause                                                                                                           | Fix                                                                                                                                                                                             |
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `401` + `x-concierge-auth: missing-key` | No `x-concierge-api-key` header arrived.                                                                        | Confirm that the rule attaches the key. Never log or echo a real key while diagnosing.                                                                                                          |
| `401` + `unknown-key`                   | A value arrived but matches no key.                                                                             | Check for truncation, whitespace, or a literal `$PROFOUND_CONCIERGE_KEY` that was never expanded. On Vercel, validate variable expansion with a nonsecret test value before using the real key. |
| `401` + `inactive-key`                  | The key was revoked.                                                                                            | Create a new key and roll it out.                                                                                                                                                               |
| `403`                                   | The host isn't registered, or belongs to another organization.                                                  | Register the exact public host in the dashboard. It must match after normalization: lowercase, no trailing dot, no port.                                                                        |
| `400`                                   | A malformed host or path, an absolute URL where a path was expected, a `#` fragment, or an inbound loop marker. | Usually a rule sending a full URL instead of a path, or a broken loop-protection condition.                                                                                                     |
| `405`                                   | A non-`GET` method reached Profound.                                                                            | Route only `GET` to Profound, and test with `curl -sD - -o /dev/null` rather than `curl -I`.                                                                                                    |
| `502`                                   | Profound could not reach your origin and had no publication to serve, or a backend lookup failed.               | Check that your origin is reachable from the public internet and not blocking Profound's fetches. A CDN can also generate its own `502`, so check its diagnostics too.                          |

## Common problems

<AccordionGroup>
  <Accordion title="Googlebot or other search crawlers are being routed">
    Your `User-Agent` pattern matches something outside the supported token list. Compare it with the pattern in your setup guide and the [supported assistants](/dynamic-bot-rendering/overview#supported-ai-assistants). Search crawlers such as `Googlebot` must keep reaching your origin.
  </Accordion>

  <Accordion title="Every assistant request shows bot-kind: unknown (CloudFront)">
    CloudFront replaces the viewer `User-Agent` with `Amazon CloudFront` on origin requests unless an origin request policy forwards it. Profound then has nothing to classify. Use the narrow custom origin request policy in the [CloudFront guide](/dynamic-bot-rendering/cloudfront). Avoid **AllViewer**, which also forwards the viewer `Host` and can break the connection to Profound. Add `User-Agent` to the origin request policy, not the cache key.
  </Accordion>

  <Accordion title="One assistant gets origin content while others get the render">
    The winning rule's allowed-assistant list excludes it. The response shows `x-concierge-policy: off` together with the rule ID. Add the assistant to the list, or clear the list so the rule inherits the domain default.
  </Accordion>

  <Accordion title="Assistants get a cached human page, or humans get a rendered page">
    Some cache layer stores HTML without separating assistant and human responses, or without separating hosts, paths, and query strings.

    On CloudFront, include `x-concierge-route` in the cache key, keep Minimum TTL at `0`, and check host and query variants. On Cloudflare, verify that the Worker's upstream call bypasses cache; `User-Agent` keying alone cannot separate page identities because every page uses the same upstream URL. On Vercel, inspect the project's external-rewrite cache settings. On every provider, also check what happens to cached entries after you publish a replacement, unpublish, or pause: a CDN entry can outlive the change in Profound.
  </Accordion>

  <Accordion title="Requests loop, or return 400 with a valid-looking rule">
    Loop protection is failing. Your rule must let requests carrying `x-concierge-request` pass straight through to your origin. Profound stamps that header on its own origin fetches, and rejects any inbound request that carries it with `400`, so a broken exclusion turns into one failed request rather than a loop.

    On Vercel, this is a `missing` condition on `x-concierge-request` with the value `^1$`, the marker Profound stamps. Any other regex silently disables the exclusion, because a `missing` condition with a value only excludes requests whose header matches it.
  </Accordion>

  <Accordion title="Query-string variants serve the wrong content">
    Query strings are part of the page identity. If your CDN strips them before the origin request, `/product?id=a` and `/product?id=b` collapse to `/product`, and the wrong variant is rendered and served.

    On CloudFront, include the query strings your pages vary on, or "All", in the cache policy. An origin request policy can forward extra query strings without keying them, so verify forwarding and cache identity separately.
  </Accordion>

  <Accordion title="Nothing is ever served from cache, even after many requests">
    Read `x-concierge-policy` and `x-concierge-policy-source` on the response. No matching rule means `off`, and `warm` serves live origin content even when a publication exists. Set the winning rule to `serve`.

    Then confirm that a candidate for this exact path and query was reviewed and published. Approval alone does not publish it, and repeated requests do not publish it either. A candidate held as pending stays pending until someone approves, rejects, or publishes it. If the page is published and policy is `serve` but you still see a `MISS`, check your CDN caches and your origin's reachability.
  </Accordion>

  <Accordion title="Requests are challenged, blocked, or return login content">
    Check WAF rules, bot challenges, deployment protection, and origin allowlists for both incoming assistant traffic and Profound's origin fetches. Profound does not forward viewer cookies or authorization headers, so protected or session-sensitive pages belong outside this setup. The loop marker is spoofable and must not be used as a firewall or authentication bypass. If your origin needs a way to identify Profound's fetches, contact Profound support.
  </Accordion>
</AccordionGroup>

## Turning it off

To stop serving renders without touching your CDN, pause the domain in the Profound dashboard. Every assistant request goes to your origin while your rules, renders, and publications are preserved, and resuming restores them. A pause takes effect in Profound immediately, but responses your CDN has already cached persist until they expire. A pause is not a substitute for CDN-level failover during an outage, because the request still has to reach Profound.

To remove the integration, restore the CDN configuration you recorded before setup:

* **Cloudflare:** remove the added Worker route or restore its previous binding without removing other Worker logic.
* **CloudFront:** restore the previous viewer-request association and policies. Use **No association** only when there was none before.
* **Vercel:** remove only the added route from `vercel.json`, preserve other routing, and redeploy.

Routing changes take effect after configuration or deployment propagation. Previously cached fallback responses may persist until expiry or your normal invalidation process. Verify original routing and content after rollback. Registered domains, keys, and publications remain in Profound until you remove them.
