تعليقات العناصر
علّق على زر أو رابط مرة واحدة باستخدام data-prodantix، فتصل كل نقرة عليه إلى تحليلاتك موصوفة بما كان الشخص يحاول فعله، لا بشيفرته.
<button data-prodantix="Upgrade to Pro">
Upgrade
</button>Every click on that button reaches Events as an $autocapture event whose $el_description is Upgrade to Pro. The annotation describes what the person is trying to accomplish, not what the element is: Invite a team member tells a product dashboard far more than Invite button, and it stays true when the CSS framework, the class names or the component change.
| What the markup says | What the annotation says |
|---|---|
| <code>button.btn-primary</code> | Upgrade to Pro |
| <code>a.nav-item</code> | Open billing settings |
| <code>button</code> | Invite a team member |
| <code>div.MuiButtonBase-root</code> | Apply discount code |
| <code>button#btn-17</code> | Start free trial |
Writing a good annotation
- Use sentence case and an action-oriented phrase: Export monthly report, not Monthly Report Export Button.
- For a button, describe the action. For a link, describe where it takes the person or what they get there.
- Keep it stable: it is the name your charts and funnels group clicks by, so change it as rarely as you would rename an event.
- Never put a name, an email address, an account id or anything else personal in it. It is sent with every click.
The rules
| Rule | Behaviour |
|---|---|
| Attribute | <code>data-prodantix</code> |
| Value | A short, human-readable description of what the person is trying to do |
| Maximum length | 300 characters, after surrounding whitespace is trimmed |
| Scope | Read from the element clicked, or from the button, link or control around it |
| Priority | Wins over the accessible label, the visible text and everything the markup says |
| Missing | The click is described the usual way |
| Empty | Treated as missing |
| Over the limit | Ignored whole and reported to <code>onError</code> once, never cut to 300 characters; the click is still recorded and described the usual way |
How a click is resolved
<button data-prodantix="Upgrade to Pro">
<span class="icon"><svg>…</svg></span>
<span>Upgrade</span>
</button>A press on the icon or the label inside that button is a click on the button, and it carries Upgrade to Pro. The web SDK works it out in four steps:
- Find the control: the nearest
button,a,input,select,textarea,label,summary,optionor element with an interactiverole(such asbutton,link,tabormenuitem) at or above the element pressed. - Read its
data-prodantix, and use it when it is present and within the rules. - Otherwise infer a description: the accessible label, then the visible text (both only when
captureElementTextis on, and only when under the limit), then a link's destination without its query, then the role, then the tag. - Record the description beside the control's markup, so a click can always be traced back to what was pressed.
An annotation is never inherited from a plain container. A pricing card can hold several buttons that do different things, so a data-prodantix on the card describes none of them: put it on each button. An element you make clickable yourself, such as a div with a click handler, needs role="button" for its annotation to be read.
Action identifiers
<button
data-prodantix="Upgrade to Pro"
data-prodantix-action="upgrade_plan"
>
Upgrade
</button>Add data-prodantix-action only when you need a stable identifier for code, a warehouse or a workflow to match on, separate from the words people read. It follows the same rules as data-prodantix and arrives as $el_action. The description is still what the console shows.
Manual events
button.addEventListener('click', event => {
prodantix.capture('plan.upgraded', { element: event.currentTarget, properties: { plan: 'pro' } });
});An event you send yourself reads the same two attributes when you name its element, so plan.upgraded above carries $el_description and $el_action from the button. A property you pass alongside wins over the element. A manual event reads only the annotation, never the inferred description, and an element inside data-prodantix-ignore or data-pdx-no-capture lends it nothing, though the event itself is still sent.
Keeping clicks out
data-prodantix-ignore on an element or any of its ancestors stops clicks there from being sent at all. data-pdx-no-capture, the pdx-no-capture class and autocaptureOptions.maskSelectors keep their meaning: the click still counts, carries no text, id, classes or link, and no annotation is read inside them. A button or link that holds such an element is masked as a whole, so a click on its unmasked part never carries the masked text. Inputs, textareas, selects and password, email and tel fields never carry what was typed, whatever the options say; their annotation is still read, because it is your words rather than the person's. An element's own text is left out of every click unless autocaptureOptions.captureElementText is on.
What a click carries
| Property | What it holds |
|---|---|
| <code>$el_description</code> | What the click was for: the annotation, or the inferred description when there is none |
| <code>$el_description_source</code> | Where the description came from: <code>annotation</code>, <code>aria_label</code>, <code>text</code>, <code>href</code>, <code>role</code> or <code>tag</code> |
| <code>$el_action</code> | The <code>data-prodantix-action</code> identifier, when the element has one |
| <code>$el_tag</code>, <code>$el_id</code>, <code>$el_classes</code>, <code>$el_href</code> | The markup of the control, kept beside the description so you can see how a click was identified |
The 300-character cap bounds one annotation; it is not a privacy policy. The page address, the link and the optional element text have their own collection rules, and an annotation is treated as untrusted text: the console draws it as words and never as HTML. Annotations need @prodantix/sdk 0.7.0 or later.