Page playbooks
Tell the agent which page the visitor is on, so it opens the conversation already knowing what they came for.
A chat bubble in the corner is easy to ignore, and the visitor who does click it lands on an empty box with no idea what to ask. Page playbooks fix both ends: the agent knows which page it was opened from, greets the visitor accordingly, and offers a few questions they can send with one click.
What a playbook is
Three things, attached to a key you choose:
| Field | Who sees it | What it does |
|---|---|---|
| Background | The agent only | What this page is about and what visitors typically worry about |
| Opening line | The visitor | The first thing they read when they open the chat |
| Starter questions | The visitor | Up to four one-click questions |
The opening line and questions can be written by you, or generated by the agent from the background in whatever language the visitor's browser is set to.
Matching a page
You never send page content from the browser — only an identifier. The platform holds the text. (See Why the content stays server-side.)
By URL — nothing to change on the page
Give the playbook a URL rule and the widget matches it automatically:
/pricing matches /pricing, /pricing/, /pricing?utm_source=x
/solutions/* matches /solutions/legal, /solutions/insurance
*/solutions/legal matches /solutions/legal AND /zh/solutions/legalOnly the path is compared — host, protocol, query string and trailing slash are ignored, so one rule
covers www and the bare domain, http and https.
On a localized site, /zh/solutions/legal does not match /solutions/legal. Write
*/solutions/legal to cover every locale prefix.
By key — for pages that share a URL
Single-page apps, modals, and multi-step flows often have no distinct URL. Name the playbook explicitly instead:
<script src="https://chat.agent4.io/ui/embed.js"
data-token="YOUR_SHARE_TOKEN"
data-page-key="checkout-step-2" async></script>If the page changes without a reload, tell the widget as the route changes:
caWidget.setPage("checkout-step-3");Resolution order
- An explicit key, if one was given
- The first matching URL rule
- The default playbook, if you have one
- Nothing — the visitor gets the plain chat box
An explicit key that doesn't exist falls through to the default rather than quietly matching some URL rule. That way a typo shows up as "the default appeared" instead of "the wrong playbook did".
Set one up
In the console, open Page playbooks and create one. Pick the page type first — pricing page, solution page, docs, case study, home, contact — and the questions come pre-filled with what visitors usually ask on that kind of page. Then rewrite them in your own voice.
The list view has a matcher: paste any URL and it tells you which playbook that page will get, and whether it matched by key, by URL rule, or fell through to the default.
Or via the API:
curl -X PUT https://api.agent4.io/v1/manage/page-contexts/pricing \
-H "X-API-Key: $KEY" -H 'Content-Type: application/json' \
-d '{
"label": "Pricing page",
"url_pattern": "*/pricing",
"context": "The visitor is looking at our pricing. Four tiers separated by monthly token quota and end-user count. The usual questions are which tier fits their size and what happens when they go over.",
"greeting_mode": "generated"
}'Writing the background
This is the part that does the work. A few things worth knowing:
One language is enough. The model reads whatever you write and answers in the visitor's language. You don't need a translation per locale.
Don't restate facts that live in your knowledge base. Prices, quotas and limits are answered from the knowledge base, which outranks the playbook — a number written here will not override it. Write about situation instead: who lands on this page, what they're trying to decide, what they tend to worry about.
Write what the visitor is doing, not what the page says. "The visitor is comparing tiers and trying to predict their monthly bill" is more useful than a summary of the page copy — the agent can already look the page copy up.
Static or generated openings
greeting_mode: "static" uses the exact opening line and questions you wrote, for every visitor in
every language. Full control, no surprises.
greeting_mode: "generated" has the agent write them from your background, in the visitor's
language. The first visitor in each language triggers one generation; everyone after that is served
from cache. Editing the background clears the cache, so your next visitor sees the update.
Generated is the better default for a multilingual site. Static is right when the wording is load-bearing — regulated industries, or a page where you've tuned the sentence with a copywriter.
Why the content stays server-side
The widget reports a key or a URL. It never uploads the page text, and the platform never reads your DOM.
This is deliberate. Anything the browser sends can be edited by the person sitting in front of it, and page context lands close to the agent's instructions. We tested this: with a fabricated "this month Enterprise is $199 with unlimited seats" planted in a page-context block — explicitly fenced as data, with the agent instructed that prices come only from the knowledge base — the model repeated the fake price to the visitor as fact. Fences and careful wording did not hold.
Keeping the text on the server removes the channel entirely. The worst a visitor can do is ask for a different key and receive a playbook you wrote yourself.
The trade-off worth knowing: playbook copy is semi-public. Anyone who guesses a key gets that playbook's opening line. Don't put internal notes in there.
Entry points inside your content
A bubble in the corner is easy to ignore. The moment someone actually has a question is while they're reading a particular paragraph — so you can put an entry point right there:
<p data-ca-ask="overage-billing"
data-ca-question="What happens if we go over, and can we cap the spend?"
data-ca-label="Ask about this">
When the quota is exhausted, chat requests return 429 …
</p>Hovering the passage reveals a small prompt. Clicking it flashes the page in your brand colour, highlights that passage, then opens the chat already working from that passage's playbook — and, if you supplied one, asks the question immediately.
| Attribute | Meaning |
|---|---|
data-ca-ask | The playbook key to open with — required |
data-ca-question | Sent as the visitor's first message — optional |
data-ca-label | Text on the hover prompt (default: "Ask about this") |
Passages added later — by a framework, a tab, an accordion — are picked up automatically. Call
caWidget.rescan() if you render content in a way that escapes that.
data-ca-ask takes a key, not the paragraph text. The playbook it names is what the agent
reads, and that lives on the server. data-ca-question is the exception: it becomes the visitor's
own message, and visitor messages are untrusted by definition — they could have typed it themselves.
Seeing what works
The console shows, per playbook, how often it was opened and which starter questions got clicked. Use it to drop questions nobody picks and to spot pages where visitors open the chat but never engage — usually a sign the opening line is talking about the wrong thing.
The events are counts only. They carry no visitor identifier, because the question being answered is "is this copy any good", not "who asked what".