A custom event is anything you name — a sign-up, a checkout, a plan change, an export. Tag an element, or call the tracker's API.
Tag an element
Add data-sg-event to a button, link, element, or form.
<button data-sg-event="signup_clicked" data-sg-prop-plan="growth"> Start trial</button>
Each data-sg-prop-* attribute becomes an event property. The suffix becomes the property name.
The click detector checks the selected element and three ancestors. Property values from attributes use at most 200 characters.
A tagged element always wins over autocapture: the click sends your named event, never both.
Call the API
Use the JavaScript API for events that do not map to an element.
window.sightglass.track("signup_completed", { plan: "growth" });
The call returns immediately; the event is sent with the next batch.
Naming events
Event names match [a-z][a-z0-9_]{0,63} — lowercase letters, digits and underscores, at most 64 characters. A name that fails the shape is refused with bad_event_name.
Names beginning sg_ belong to the platform and are refused with reserved_event_name. The platform's own vocabulary is sg_page_view, sg_screen_view, sg_app_launch, sg_session_start, sg_identify, sg_click, sg_submit, sg_vitals and sg_purchase.
Two habits worth keeping:
- Name what happened, in the past tense, rather than the button that was clicked.
- Keep one name per meaning. Two names for one moment split every chart in two.
Properties
| Rule | Limit | Why |
|---|---|---|
| Keys per event | 32 | Beyond it the event is refused with bad_properties. |
| Nesting | depth 2 | A deeper object is refused rather than flattened silently. |
| String value length | 1 KB | Long values are a document, not a dimension. |
| Whole event | 32 KB | Past it the event is refused with event_too_large. |
| Key names | the event-name charset | So filters behave the same everywhere. |
Property keys are also what the dashboard offers as breakdowns. A project's property allowlist decides which keys appear there — it narrows the screen, not the storage: everything else you send is kept, after the scrub described below.
Custom events are a plan feature. Where the workspace's plan does not include them, the custom event alone is refused with custom_events_not_in_plan — the page view sent in the same batch is still recorded.
What never to send
Do not put personal data in an event name or a property. The ingest defends this, but it is your obligation and not ours:
- A property key that looks secret-bearing —
password,secret,token,auth,cookie,session,credit,card,cvv,ssn,iban,api_key— is dropped whole, wherever the fragment appears in the key. - A string value that looks like an email address, or like a long opaque token, is replaced with
[redacted], whatever its key. - A page path loses its query string, a referrer is reduced to its host, the user agent is classified and then discarded, and no raw IP address ever reaches storage.
Identify a person
Traits are facts about your own user, sent by you, under identified consent only.
window.sightglass.identify("user_000000042", { email: "[email protected]", plan: "growth", seats: 5,});
- A user id matches
^[A-Za-z0-9_-]{8,64}$. - Traits are flat: keys
[a-z][a-z0-9_]{0,39}, values string, number, boolean ornull, at most 24 per call. Anulldeletes a trait; the merge is last-write-wins. - A secret-shaped key refuses the whole object.
- Traits travel on one
sg_identifyevent in its own batch. The tracker de-duplicates by value: an unchanged identity re-sends nothing across reloads. - Identify from a browser key that is locked to an origin is refused with
origin_locked_key; send traits from a server key instead.
Call identify only after identified consent — see Cookieless by default. A person identified this way is also the one you can erase: Data removal.