The manifest is a JSON document shaped like this:
{ "version": 1, "app": "your-site", "sdkMinVersion": "1.1.0", "screens": [ { "id": "leads.new", "path": "/leads/new", "label": { "es": "Nuevo lead", "en": "New lead", "it": "Nuovo lead" }, "anchors": [ { "id": "name", "kind": "field", "fieldType": "text", "required": true, "label": { "es": "Nombre", "en": "Name", "it": "Nome" } }, { "id": "phone", "kind": "field", "fieldType": "phone", "label": { "es": "Teléfono (sin espacios, sin +, solo dígitos)", "en": "Phone (digits only, no spaces, no +)", "it": "Telefono (solo cifre)" } }, { "id": "save", "kind": "action", "effect": "write", "label": { "es": "Guardar", "en": "Save", "it": "Salva" } } ] } ]}| Field | What it is |
|---|---|
version | Always 1 (the contract number this manual describes). |
app | A short id for your application, informational only. |
sdkMinVersion | The minimum copilot SDK version this manifest needs — at least 1.1.0 if your site uses the neutral attribute data-copilot-anchor (section 4); 1.0.0 is enough if you only use the previous attribute. |
screens | Up to 200 screens. Each one: id, path (a relative path on your own site, never an absolute or external URL), label and up to 100 anchors. |
5.1 Anchor types
Section titled “5.1 Anchor types”kind | What the copilot does with it |
|---|---|
field | It can fill it in (“let’s do it together” mode). Carries fieldType. |
action | It can tap it. Carries effect. |
region | It can only highlight it (guide) — never fills it in or taps it. Useful for selects whose options depend on your own data (they can’t be declared “closed”). |
fieldType | Note |
|---|---|
text · textarea · number · email · phone · date · datetime · select · checkbox |
Important — There is no
fieldType: "password"A manifest that tries to declare a password field is rejected on the server with the exact reason. And even if you tried to disguise it as another type, the SDK never writes to a real
<input type="password">on your page — it checks against the DOM element itself, not against what you claim in the JSON.
Action effect | Consequence |
|---|---|
navigate | Opens another screen or reveals something on the same one. No confirmation. |
read | Only reads. No confirmation. |
write | Saves a change. Always confirmed — the server requires it even if the plan doesn’t ask for it. |
send | Sends something to a third party (e.g. replying to a customer). Always confirmed. |
destructive | Deletes something. Always confirmed, with destructive wording. |
5.2 Shape rules (the server enforces them, no exceptions)
Section titled “5.2 Shape rules (the server enforces them, no exceptions)”- Screen and anchor ids:
^[a-z0-9][a-z0-9._-]{0,63}$— lowercase letters, digits, dot, hyphen and underscore. No uppercase and no spaces (the “T” inappointmentTypeis rejected;appointment-typeis fine). pathis always a relative path on your own domain (/leads/new) — never an absolute URL, neverjavascript:, never an external domain.- Labels: plain text, max 80 characters, no
<>{}[]or control characters. If your manifest is for the Platform or its internal console you need all three languages; for your own site one is enough. - A
fieldof typeselectmust declare itsoptions— a closed list. If the value depends on data that changes (a stage, an owner, a catalog specific to each customer), it isn’t aselect: useregionand let the copilot only point it out. - Overall limits: ≤ 200 screens, ≤ 100 anchors per screen, ≤ 256 KB for the whole JSON document, ≤ 30 steps per plan (this last one is decided by the server when validating each plan, not by your manifest).
Note — Phone fields: put the format in the label itself
In real tests, an assistant filled in a phone number with a leading ”+” because nothing in the label said otherwise, and the form itself rejected it (the system correctly failed closed). The way to avoid that unnecessary back-and-forth is for the anchor’s label to say so explicitly: “Phone (digits only, no spaces or prefix)” instead of just “Phone”. The assistant only has that text to know what format you expect.
5.3 Manifest: what to declare and what not to
Section titled “5.3 Manifest: what to declare and what not to”Rules learned while building the Platform’s own manifests (the one for its main panel and the ones for its two internal consoles) that are worth keeping in mind when writing yours:
- If your site can show several instances of the same kind at once (several WhatsApp channels open at once, several cards of the same integration…), don’t declare per-instance controls. The same
data-copilot-anchorwould exist repeated on the page, and the SDK would always resolve against the first one it finds — not necessarily the one the person has in front of them. Declare only what’s safe to anchor without ambiguity (a single-instance creation screen, for example) and leave the rest undeclared, or as aregionthat guides over the whole list. - A field whose options depend on data that changes (a catalog specific to each customer, an AI model that varies by plan, a funnel stage the person themselves customizes) isn’t a
select— declaring it as a closed list would be inaccurate, since it isn’t really one. Declare it as aregion: the copilot points it out, and the person chooses. - A trailing
?onpathfor screens with no route of their own: if two of your screens share the same base URL (for example, a form that lives at the same route as its listing, with no identifier of its own in the URL), add an empty?to the end of thepathof the one without its own deep link — this keeps the SDK from confusing which of the two to resolve when navigating by the current URL. - Reactive deep links: if you use a URL parameter to open a modal or a specific view (for example
?copilotOpen=new), read it reactively — reacting to URL changes within the same browsing session, not only when the component mounts — because otherwise, a second copilot plan that reuses an already-open screen won’t trigger the modal to open again.
