# [Agent intent](https://rebilder.com/docs/intent)

> What agents asked your store — search queries, zero-result demand, AI referrers — captured at emission, PII-screened, and rendered in Console insights and the weekly digest.

## What gets captured

Since events v0.4, `request.intent_signals` is populated at emission instead of being an empty object. The shape stays open (`Record<string, unknown>`), and these are the well-known keys every emitter uses:

| Key | Meaning |
| --- | --- |
| `query` | Free-text search sent to this store — a `?q=`-style param or a protocol search tool argument — recorded only after the screen below. |
| `query_param` | Where the query came from: `q`, `query`, `search`, `s` (WordPress), `keyword`, `term`, or a protocol tool name like `mcp.search_catalog`. |
| `referrer_platform` | AI platform classified from the Referer header (`chatgpt`, `perplexity`, `claude`, `gemini`, `copilot`, …). On a `human` event this marks a visitor an AI conversation sent. |
| `utm_source` / `utm_medium` | Sanitized campaign params — `utm_source=chatgpt.com` is a live convention on AI click-throughs. |
| `tool` | Protocol tool or operation that ran: `mcp.search_catalog`, `mcp.get_product`, `mcp.get_policies`, `ucp.discovery`, `ucp.catalog`, `ucp.checkout`, `acp.feed`. |
| `result_count` | Result count for a search-shaped request. `0` is the zero-result-demand signal: an agent asked for something the catalog could not answer. |

The shared implementation lives in `@rebilder/events` (`scrubQueryText`, `classifyReferrerPlatform`, `extractUrlIntentSignals`, `buildProtocolIntentSignals`), so the gateway, the protocol adapters, and platform apps emit identical shapes.

## The PII screen fails closed

> **A query that might identify a person is never recorded** Free-text queries pass `scrubQueryText` before they may be recorded. A string containing an `@`, a run of 7+ digits (even through phone-style separators), a token-like fragment of 24+ characters, a pasted URL, or more than 200 characters is dropped entirely — never truncated, never partially redacted, never counted. Events carry no consumer PII beyond what the merchant already lawfully processes.

Recorded URLs are unchanged by this feature: `request.url` keeps its emission-time allowlist (`page`, `variant`, `sku`, `lang`, `locale`, `currency`), so search text never rides the URL and Miss-Report grouping stays clean. Queries live only in `intent_signals.query`.

## The protocol channel

On the protocol path, the adapter is the only code that knows which tool ran and how many results came back, while the event belongs to whichever emitter mounted it. Adapters therefore stamp `x-rebilder-intent-tool`, `x-rebilder-intent-query` (URI-encoded, post-screen) and `x-rebilder-intent-results` on their responses. Mounted through `@rebilder/gateway`, those headers are folded into the gateway’s event and **stripped before the response leaves**. On a standalone protocol mount they stay on the wire — they only ever echo what the client sent plus a count visible in the body.

> The reader re-screens the query after decoding — the emitter never trusts that the writer was our package.

## Where it renders

- [Console insights](/console/insights): the answer-rate headline (answered = served on the markdown or protocol path), the query table with zero-result counts, AI-referred visitors by platform with the orders that followed (labeled inference, same 7-day product-URL evidence standard as funnel attribution), and the per-platform breakdown.
- The **unanswered searches** finding: zero-result searches surface as an attention finding with the query list and a concrete fix.
- The **weekly digest** (opt-in, [Console settings](/console/settings)): the same numbers, mailed. Setting the address turns it on; clearing it turns it off immediately; unsubscribes are honoured permanently.

> **Older traffic has no intent signals** Capture happens at emission, so events recorded before your gateway picked up events v0.4 have an empty `intent_signals`. The Console says “nothing captured yet” rather than showing zeros it cannot back.

The full feature story is at [Agent intent](/agent-intent); the event schema itself is on the [Events](/docs/events) page.