Choose who's in an experiment
By default an A/B experiment includes everyone: each new conversation joins on its own and gets the control or the variant at random. The optional Audience step in the setup wizard changes that. You can test the variant on your own phone before anyone else sees it, run the experiment for one city or a list of customers, or keep every conversation from the same customer on the same version.
Most experiments don't need any of this. Skip the step and everyone takes part.
How audience rules work
Three settings live on the Audience step. Docana checks them in this order for every new conversation:
- Group by context field decides what gets assigned. Off, every conversation is assigned on its own. On, every conversation that shares a value, such as the same customer ID, lands on the same version and is measured as one group.
- Audience eligibility decides who joins. Conversations that match join the experiment. Everyone else gets the published version and stays out of the results.
- Routing rules send matching conversations straight to the control or the variant. Rules are checked in order and the first match wins. Routed conversations skip the random split, so they never count in the comparison. That's what makes them safe for testing.
Eligibility and routing rules need grouping turned on. A routing rule pins a whole group to an arm, so Docana needs to know what a group is.
Rules are frozen when the experiment starts. To change them, stop the experiment and start a new one. The experiment's result page shows the exact rules under Settings.
Which fields you can match
A rule compares one field against a list of values. Matches are exact and case-sensitive, so Recife doesn't match recife. Which fields a conversation has depends on how its messages reach Docana:
| Field | Where it comes from | Available for |
|---|---|---|
| User ID | The Docana user who sent the message | Every conversation |
| WhatsApp phone | The sender's number, as verified by Meta or Twilio | WhatsApp numbers connected to Docana directly |
| WhatsApp user ID | The ID WhatsApp sends when a contact hides their number behind a username | WhatsApp numbers connected to Docana directly |
| Context field | Any value in the context object your server sends, such as customer.plan or company.city | Runs your server starts through the Agents API, or WhatsApp messages it forwards through the WhatsApp proxy, with an API key |
Docana only trusts values a person can't forge. A browser, the chat widget, or a WhatsApp message can't choose their own context, so context rules never match them. An API key can, because only your server holds it.
If a CRM forwards WhatsApp messages to Docana through the WhatsApp proxy endpoint (/api/plugins/whatsapp/proxy/agent/...), call it with an API key (Authorization: ApiKey ...) so the context it sends can match context rules. Calls made with a logged-in session don't count.
Docana doesn't verify the sender's number on the proxy, so WhatsApp phone rules don't match these conversations. Send the number in the context instead, for example as user.phone, and match it as a context field.
Grouping is different from rules. It reads the context field even when it isn't trusted, because a forged value only changes which group a conversation lands in. It can't pick the version.
Tutorial: test the variant on your own phone
Before real customers see a variant, send only your own conversations to it. They skip the random split, so your tests never affect the results.
You need a running agent with a candidate variant, and conversations that carry your phone number in their context, for example as user.phone.
- In the agent's Experiments tab, choose Start experiment, pick the variant, and set a low traffic share such as
1%. - On the Audience step, choose Customize and turn on Group by context field. Enter the field that identifies one customer or one attendance, such as
customerthenid. - Turn on Routing rules. In the first row, choose Context field, enter
userthenphone, paste your number in Values exactly as your system sends it, and keep Send to on Variant. - Under Test a user, paste the context your server sends for you, such as
{"user": {"phone": "+5581999990000"}}. Docana should answer Routed to Variant by rule 1. Then finish the wizard and start.
To test with more people, add their numbers to the same row. To keep someone on the published version during the test, add a second rule that sends their number to Control.
If your WhatsApp number is connected to Docana directly, use the WhatsApp phone field instead of a context field. Write numbers in E.164 format, with + and the country code.
Tutorial: run the experiment only for one city
Run a change in one region before rolling it out everywhere. Customers in that city join the experiment and get the control or the variant at random. Everyone else keeps the published version.
- Start an experiment and set the traffic share you want inside that city, such as
50%. - On the Audience step, choose Customize, turn on Group by context field, and enter the field that identifies one customer.
- Turn on Audience eligibility. In the Let in row, choose Context field, enter
companythencity, and enterRecifein Values. - Under Test a user, paste a context with
"city": "Recife"and one with another city, and check that only the first one joins.
Values match exactly. If your system sends both Recife and RECIFE, add both.
The same pattern works for any list you already keep in your system. Paste a list of CNPJs into a company.cnpj row to run the experiment only for those companies. Paste customer IDs into a customer.id row for a hand-picked beta group.
Tutorial: measure per attendance, not per conversation
Some metrics only make sense per customer or per attendance. A transfer rate is one: if a single attendance spans several conversations, you want the whole attendance on one version and counted once.
- On the Audience step, choose Customize and turn on Group by context field.
- Enter the field that identifies one attendance or one customer, such as
chatAttendanceIdorcustomerthenid. Choose the type the field has, usually Text. - Leave eligibility and routing off if everyone should take part, and finish the wizard.
From then on, the first conversation in an attendance picks the version and every later conversation in that attendance follows it. The result page counts groups instead of conversations. Runs without a value for that field get a normal reply but stay out of the experiment.
Combine rules
You can combine everything above. A few examples:
- Only your team, and your phone always on the variant. Eligibility lets in your team's user IDs. A routing rule sends your number to Variant. Your teammates get a random version.
- Two cities. One eligibility row lists both cities:
RecifeandOlinda. Rows inside a list match any value. - Premium customers in Recife. Switch eligibility to Advanced rules and put both conditions in one match group:
company.cityisRecifeANDcustomer.planispremium. A second match group adds an OR.
Test a user runs the same check Docana runs when a conversation arrives, so use it before starting.
Check who got which version
- The experiment's result page shows the frozen grouping and rules under Settings.
- The agent's Logs tab shows every run's origin: A · Control, B · Candidate, Directed test · Variant for routed conversations, or Outside experiment.
API
The REST API takes the same settings as the wizard on startAgentExperiment. Add groupingConfiguration and audiencePolicy to the request body:
{
"groupingConfiguration": {
"version": 1,
"path": ["customer", "id"],
"scalarType": "string",
"missingKeyPolicy": "exclude",
"reducer": "latest"
},
"audiencePolicy": {
"version": 1,
"eligible": [
[{ "source": "context", "path": ["company", "city"], "values": ["Recife"] }]
],
"forcedRules": [
{
"id": "my-phone",
"when": [[{ "source": "context", "path": ["user", "phone"], "values": ["+5581999990000"] }]],
"arm": "VARIANT"
}
]
}
}
eligible is a list of match groups: a conversation joins when it matches every condition in any one group. forcedRules are checked in order. Identity conditions use "source": "identity" with "field": "userId", "whatsappPhone", or "whatsappSenderId".
The docana agents experiments start command doesn't take these fields yet. Send them with the API escape hatch:
docana api POST /api/v1/agents/your_agent_id/experiments/ -d @start-body.json
Next steps
- A/B testing: the rest of the setup, guardrails, and reading the result
- Run agents from code: send
contextwith an API key so context rules can match