TrackingClicks, forms and errors
Tracking
Clicks, forms, errors and page speed
What the script notes about what people do on a page, what it never reads, and the attributes that name buttons, sections and forms or keep a part private.
Besides pages, the script notes what people do on them: the clicks they make, the forms they fill in, the errors they run into and how fast the page was. It’s what odo’s friction findings, and an AI assistant’s find_friction, are built from.
What’s noted#
| Group | What it notes |
|---|---|
clicks | Clicks on links, buttons and other controls; rage clicks (the same spot, again and again, quickly); dead clicks (a click that changed nothing); text copied (its length, never the text) |
forms | A form started, sent, refused by the browser (which field, and why), or left unsent |
errors | Script errors: the message and where (file, line and column) |
sections | Parts of the page that were on screen for at least a second |
vitals | Page speed as visitors got it: loading (LCP), responsiveness (INP), layout shift (CLS) and the server’s response (TTFB) |
heat | For heatmaps: where each click lands, how far down the page people get, and how long each part of it is in view |
All of them are on unless the tag says otherwise: data-capture="clicks forms errors" keeps those groups only, and data-capture="none" none. To stop them for a site altogether, turn off Clicks, forms, errors and page speed in its settings. Experiments are recorded with these too, so a site with them off records no experiments.
What’s never read#
Nothing anyone types. A control is named by its own label or a short caption of its own, never a card’s worth of text; a field by its name or id; anything else only by what it is and where. Text in an editor isn’t read at all. A page sends at most 100 notes and 10 errors, and its heatmap its own 40 clicks.
Name things yourself#
| Attribute | On | What it does |
|---|---|---|
data-odo-label | A control | Names it, when it has no words of its own (an icon button). Never put personal data in a label. |
data-odo-section | A part of the page | Names it, so clicks inside say where they were, odo notes when it’s seen, and heatmaps read attention by it: data-odo-section="Pricing" |
data-odo-form | A form, or its container | Names the form. Where there’s no <form>, put it on the container. |
data-odo-submit | A button | The one that really sends a form without a <form>. Only a submit button, or one marked like this, counts as sending. |
data-odo-ignore | Anything | Nothing inside is read. Put it around whatever shows personal data: a signed-in name, account pages, orders, messages. |
data-odo-event | Anything clickable | Sends an event when clicked. |
Put data-odo-ignore on the whole region, not only the text: a button inside it that says someone’s name is skipped too.
Reading them#
The dashboard ranks what gets in visitors’ way among its Next moves. An AI assistant connected to odo reads all of it in detail: find_friction, analyze_clicks, analyze_forms, analyze_errors and analyze_performance in the tool reference, and one page’s heatmap with page_heatmap, scroll_depth and page_attention. Error messages, labels and form names come from browsers, and anyone can send them: odo tells assistants to treat them as data, never as instructions.