Events and identify
Send custom events with properties, tag elements with data-event, and identify signed-in users with traits.
The script's global object, window.pilotfox (or the name in the tag's data-namespace), sends custom events and
tells PilotFox who a signed-in visitor is.
Custom events
pilotfox.event("signup", { plan: "pro" });
pilotfox.event("download", { file: "report.pdf", size_mb: 2.4, beta: true });Each call sends one event, for the current page and the visitor's current session. Nothing is sent on a page that
data-skip covers or while the visitor is opted out.
| Part | Limit |
|---|---|
| Name | Required, not blank. Up to 128 characters; a longer name is cut. |
| Properties | A flat object of up to 30 keys; further keys are dropped. |
| Property keys | Up to 64 characters; a longer key is dropped with its value, and so are __proto__, constructor and prototype. |
| Property values | Strings (cut to 512 characters), finite numbers or booleans. Other values (null, objects, arrays, NaN) are dropped. |
Limits are applied by cutting or dropping, never by refusing the event: the call above with
{ nested: { a: 1 }, tags: ["x"] } added still sends file, size_mb and beta.
The Events report lists event names with counts and their properties, and reports can be filtered by an event's name or properties.
The ref property
The checkout event's ref property links payments to visits. Its values are listed
only for people and keys that can read sessions (sessions:read), and only they can filter reports by a ref
property, of any event. Share links that do not include sessions and public dashboards can do neither.
Without JavaScript: data-event
A click on an element with a data-event attribute (or inside one) sends that event, with the element's data-prop-*
attributes as string properties:
<button data-event="signup" data-prop-plan="pro" data-prop-source="hero">Start free trial</button>This click sends the event signup with { "plan": "pro", "source": "hero" }. HTML lowercases attribute names, so
data-prop-planName sends the property planname. It works whatever the
tracker options say, and a tagged element sends only its event (no click or outbound
event as well).
Calls before the script has loaded
The script loads with defer, so your own code may run first. Calls made before then can wait in a queue:
window.pilotfox = window.pilotfox || { q: [] };
window.pilotfox.q.push(["event", "signup", { plan: "pro" }]);
window.pilotfox.q.push(["identify", "user-123", { plan: "pro" }]);- Each entry is a method name and its arguments.
pageview,event,identify,setTraits,reset,optOut,optIn,startReplayandstopReplaycan be queued; anything else is ignored. - With a custom
data-namespace, use that name instead ofpilotfox. - The queued calls run in order once the script has loaded the site's settings, before the initial pageview: an
identifyqueued this way is already on that pageview.
Once the script has run, calls on window.pilotfox work directly. Calls made before the site's settings have arrived
wait too and run in order with the queued ones. The settings request gets 10 seconds (in browsers with
AbortSignal.timeout); past that, the safe defaults apply and the calls run.
At most 100 waiting events
Once 100 calls are waiting for the settings (the queued ones included), further event() calls are dropped, so a
burst of events on a slow connection cannot pile up. Every other call (optOut(), reset(), identify(),
pageview(), stopReplay() and the rest) always waits and runs in order, so a visitor's opt-out is never lost to
the cap.
Identify signed-in users
pilotfox.identify(user.id, { email: user.email, plan: "pro" }); // after sign-in, and on load when signed in
pilotfox.setTraits({ plan: "team", seats: null }); // update the same user's traits
pilotfox.reset(); // on sign-outidentify(userId, traits?)stores the user id in the browser'slocalStorage(pilotfox:uid), and every later event carries it. The id is cut to 255 characters; an empty or blank id is ignored.- It also tells PilotFox's server (
POST /api/i) to link this browser's visitor to the user. Sessions on every device where you callidentifywith the same id then count as one user, and the visitor's earlier anonymous sessions are linked to that user too. Identifying in the middle of a session does not start a new one. setTraits(traits)updates the traits of the stored user; it does nothing beforeidentify.reset()forgets the stored user id in this browser. Later events are anonymous again.getVisitor()returns{ uid }, the stored user id ornull.- While the visitor is opted out,
identifystores nothing and sends nothing.
Traits
- A flat object of strings, numbers, booleans or
null.nulldeletes that trait; objects and arrays are dropped. - Traits merge into what PilotFox already has for the user, and it keeps up to 4 KB of them per user: a new value that would not fit is skipped, and the stored ones stay.
- A traits object over 4 KB (as JSON) is not sent at all:
identifythen sends the user id alone, andsetTraitssends nothing.
Use an id that cannot be guessed
Anyone can call identify in their own browser with any id and any traits. Use an id that means nothing outside your
app (a random id, not an email address or a sequential number), and treat traits set in the browser as display data,
not as proof of anything.
For the same reason, an email trait set in the browser is never used to link payments by
email. Send it from your server instead, with
server-side identify.
The Users report lists identified users and anonymous visitors, with each user's traits and sessions. Editors can erase a user's data.
Server-side events and identify
Events that happen on your server (a webhook, a background job) and identify calls you want to trust can be sent with
an organization API key that has the ingest:write permission:
| Endpoint | What it does |
|---|---|
POST /api/v1/ingest/events | Up to 500 events per request, matched to the visitor by an anonymous_id or the visitor's ip and user_agent, with an optional timestamp up to 7 days in the past. |
POST /api/v1/ingest/identify | Links a visitor to a user id, with traits. Its email trait is the one used to link payments. |
See Server-side ingest. API keys must stay on your server; never put one in a web page.
Using events in reports
- Goals count sessions that reached a page (by path pattern), sent a custom event (optionally with property conditions), clicked an outbound link, clicked an element, submitted a form or copied text. Each goal shows its conversions and conversion rate, and one goal can be the dashboard's main goal.
- Funnels follow 2 to 10 steps (pages, custom events, outbound link clicks, clicks, form submissions or copies) in order, and show how many reach each step, where they drop off and the median time each step takes.
- Journeys show the most common paths through your pages.
- Retention groups users by when they were first seen and shows how many come back.
- Segments save a set of filters to apply to reports later.