Guides

Monitor AI Agent Access

Check that your pages and APIs respond to AI crawlers and agents the way they respond to everyone else: agent personas, parity verdicts, sampling, alerting, and the OpenTelemetry signals they emit.

View as Markdown

A growing share of the requests reaching your site come from AI crawlers and agents: a model fetching your pricing page for a user, a search index refreshing your docs, a training crawler. These clients are often treated differently from a browser. A WAF rule blocks them, a bot challenge stops them, or a page that renders fine for a person returns an empty shell to a fetch.

None of that shows up in an ordinary HTTP monitor, because the monitor is not asking as an agent. Agent personas fix that. An HTTP monitor with personas switched on repeats its request once per persona, using that crawler's User-Agent, and compares each response with the normal one.

How a persona run works

  1. The monitor makes its normal request. This is the baseline. Its status, response time, assertions, anomaly baselines and SLOs behave exactly as they do without personas.
  2. If the baseline succeeded, Yorker repeats the request once for each selected persona, one at a time, replacing the User-Agent header with the persona's. Everything else (method, URL, other headers, auth, body) stays the same.
  3. Each persona response is compared with the baseline and given a verdict.
  4. The verdicts are stored on the run, shown on the run page, and emitted to your OpenTelemetry backend.

A run has a fixed time limit. Each persona request times out after 15 seconds or the monitor's timeout, whichever is shorter, and if a slow target uses up the run's time before every persona has gone, the remaining personas are skipped for that run and listed as not run. They are not billed.

If the baseline fails, the personas are skipped for that run. The run already tells you the URL is down for everyone, and there is nothing healthy to compare against.

Personas

PersonaOperatorWhat the real client does
claude-userAnthropicFetches a page when a Claude user asks about it
claude-searchbotAnthropicIndexes pages for search results
claudebotAnthropicCrawls for model training
chatgpt-userOpenAIFetches a page when a ChatGPT user asks about it
oai-searchbotOpenAIIndexes pages for ChatGPT search
gptbotOpenAICrawls for model training
perplexity-userPerplexityFetches a page when a Perplexity user asks about it
perplexitybotPerplexityIndexes pages for Perplexity search

If you are not sure where to start, pick the three user-triggered fetchers (claude-user, chatgpt-user, perplexity-user). A block on those is felt immediately by someone asking a question about your product. Add the search and training crawlers when you have a policy for them that you want to verify.

Verdicts

VerdictMeaning
MatchesThe persona got an equivalent response.
BlockedThe baseline got a 2xx and the persona did not.
Bot challengeThe edge answered the persona with a challenge page instead of your content.
Assertion failedAn assertion that passed for the baseline failed for the persona.
Request failedThe persona request errored or timed out.

The assertions checked against a persona response are the ones about content and access: status_code, body_contains, body_matches, body_json_path and header_value. Timing, TLS and OpenAPI assertions describe the endpoint, not who is asking, so they stay with the baseline.

This makes body_contains the most useful assertion to pair with personas. A page that returns 200 to an agent but leaves out the content is the failure a status code never shows:

assertions:
  - type: status_code
    value: 200
  - type: body_contains
    value: "Plans start at"

Response size and content type are recorded for every persona alongside the baseline so you can compare them, but a difference in size alone is not a verdict. Serving agents a smaller Markdown version of a page is a legitimate choice.

Switch personas on (Web UI)

  1. Open the monitor and click Edit.
  2. Under the assertions, switch on Agent personas.
  3. Tick the personas to run as.
  4. Choose How often: every run, or 1 in N runs.
  5. Choose what happens when a persona differs: record it on the run, or fail the run.
  6. Save. The next run includes the personas.

Personas are available on HTTP monitors. New monitors are created without them; add them from the edit page.

Switch personas on (Monitoring as Code)

monitors:
  - name: Pricing page
    type: http
    url: https://www.example.com/pricing
    frequency: 5m
    locations:
      - loc_us_east
      - loc_eu_central
    assertions:
      - type: status_code
        value: 200
      - type: body_contains
        value: "Plans start at"
    agentPersonas:
      personas:
        - claude-user
        - chatgpt-user
        - perplexity-user
      every: 6
      failOnDivergence: true

Writing the block switches personas on. To pause them and keep the settings, add enabled: false.

Use an up-to-date CLI everywhere that deploys this config, including CI. A CLI release from before agent personas does not know the block: it ignores it in the file and removes personas from the monitor on its next deploy. The full field list is in the configuration reference.

How often to run them

every (in the UI, How often) runs personas on 1 in that many runs. 1 runs them every time.

Bot rules change when someone edits a WAF policy or a CDN setting, not minute to minute, so sampling is usually enough. A monitor that runs every 5 minutes with every: 6 checks personas every half hour.

Sampling is counted separately at each location. It restarts when you change the persona settings, so the first run after an edit always includes personas and you can confirm the result straight away.

Cost

Each persona request counts as one additional HTTP run, per location. The example above adds three runs to 1 in 6 executions at each location, which averages half an extra run per execution. every is the control: raise it to spend less.

Rate limits

Yorker limits how many requests per second your monitors can send to one hostname. Persona requests count toward that limit: a monitor with three personas counts as four requests per run, whatever every is set to. If adding personas would take a hostname over the limit, the save is rejected with the same error as raising the frequency would be.

Read the results

Open any run that included personas and scroll to Agent Personas. The table shows the baseline on the first row and one row per persona with its verdict, status code, response time, body size and content type.

Runs that were not sampled for personas do not show the section.

Because every location runs its own personas, a block that only happens in one region shows up as a difference between locations. That is common with geo-specific WAF rules.

Alerting

By default a difference is recorded and the run stays successful. That is the right setting while you learn how your site treats each persona.

To be alerted, set When a persona differs to Fail the run (failOnDivergence: true). A run with a differing persona then fails, with an error message naming the persona and the reason, and your existing alert rules apply. For example, consecutive_failures fires after repeated blocks and multi_location_failure fires when the block is seen from several regions. See Set Up Alerts.

Failing the run also counts against any SLO on the monitor. If you want agent access tracked separately from human availability, create a second monitor for the same URL with personas and failOnDivergence on, and leave the original as it is.

OpenTelemetry

When your team has an OTLP endpoint configured, every persona request produces a synthetics.agent.persona.checked log event in your backend: INFO when it matched, WARN when it differed. The event carries the persona, its operator, the verdict, the persona's status code and the baseline's.

A query for blocked agents by region looks like this in most backends:

event.name = "synthetics.agent.persona.checked"
AND synthetics.agent.divergence != "none"
GROUP BY synthetics.agent.persona, synthetics.location.name

Monitors on private locations with runner-side OTLP enabled also emit per-persona metrics and a child span per persona request. The full attribute and metric list is in OpenTelemetry > Agent persona signals.

What a persona run does and does not prove

A persona request carries the crawler's user agent. It does not carry the crawler's identity.

The operators sign their real traffic and publish the IP ranges it comes from, and some CDNs use those to tell a genuine crawler from a request that only claims to be one. A persona request comes from a Yorker location and is not signed by the operator.

So a persona run tells you how your stack treats a request presenting that user agent. That covers the common cases: WAF rules, rate limits, bot walls and application code that match on the user agent string. It cannot tell you how a CDN that verifies bot identity treats the genuine crawler, and such a CDN may answer a persona request more strictly than the real thing.

Treat a block as a strong reason to look at your rules, and a match as evidence that nothing keyed on the user agent is in the way.