Custom events

What gets captured for free, and how to record the events only your app knows about.

Autocapture sees interactions. Your code sees meaning. The gap between "a button was clicked" and "a subscription was created" is what customEvent closes.

Free from the install

With enableAutomaticTracking on (the default), the SDK records page views and navigation, clicks on buttons and links, form submissions, and the friction signals derived from that behaviour — rage clicks and unresponsive controls.

Tune what that includes:

HumanBehaviorTracker.init(apiKey, {
  automaticTrackingOptions: {
    trackButtons: true,
    trackLinks: true,
    trackForms: true,
    includeText: false,   // don't record the element's text
    includeClasses: false,
  },
});

includeText: false is worth considering if your button labels can contain customer data.

Your own events

await tracker.customEvent("subscription_created", {
  plan: "pro",
  seats: 12,
  mrr: 240,
});

An event needs a name; properties are optional and are what make it useful later. plan is why you can ask which plan converts, rather than only how many conversions there were.

Two rules that decide whether this pays off

One spelling per event. subscription_created everywhere, not SubscriptionCreated in one component. Nothing downstream merges two spellings, so you get two half-counts and no warning.

Name the outcome, not the widget. checkout_submitted still means something after the button moves; blue_button_clicked does not.

Timing

Events raised in the first few seconds of a session are held until the session passes minimumDurationMilliseconds (default 5000), then flushed together. An event fired immediately on page load is not lost — it is queued.

Events with an empty or invalid name are skipped with a warning rather than sent.

Where they show up

On Dashboard's event breakdown, as funnel steps, on a person's timeline in Visitors, and to anything asking questions through Home or MCP.

Excluding a property everywhere is propertyDenylist on init.