Docs/Custom events

Custom events

Pageviews tell you people came. Events tell you what they did — and where the money stops.

The call

window.kipstats.event('signup', { plan: 'pro' })

The function exists as soon as tracker.js has loaded. It is safe to call on a development machine (it does nothing) and safe to call before the tracker loads if you guard it, as the helpers below do. An event is attached to the visitor's current session; a payload is optional and stored as JSON.

Names worth using

Any name works, but these five are what the dashboard understands as a funnel. Using them means the conversion panel, the drop-off view and the friction report fill themselves in.

EventWhenPayload
cta_clickA main call to action is clicked{ cta: 'hero' }
signupAn account was created{} or { plan }
checkout_startedThe payment session is about to open{ plan, price } — price in cents
purchaseA payment succeeded{ amount, currency, plan } — amount in cents
downloadA file was delivered{ type: 'free' | 'paid', product }

An amount without a currency is a wrong amount. { amount: 9900 } on a site selling in złoty is read as 99 €. Always send currency when you don't charge in euros.

Recording a purchase, properly

Two mistakes cost the most, and both inflate revenue rather than hide it:

  • Test payments counted as sales. Only emit purchase when the payment is real — check the livemode flag of your payment session.
  • The success page reopened. A back button, a link from the receipt email, a refresh: the event fires again. Guard it on the payment session ID.
Success page
// after your payment provider confirmed the payment
const guard = 'kp_purchase_' + sessionId
if (!localStorage.getItem(guard)) {
  localStorage.setItem(guard, '1')
  window.kipstats?.event('purchase', { amount: 900, currency: 'EUR', plan: 'pro' })
}

Better still, record it from your server, where the payment is confirmed: see server-side events. A browser can be closed before it ever reaches your success page.

Helpers

// lib/kipstats.ts
type EventData = Record<string, unknown>

/** No-op on the server and before the tracker has loaded. */
export function track(name: string, data: EventData = {}) {
  if ("undefined" === 'undefined') return
  ;(window as any).kipstats?.event?.(name, data)
}

Reserved names

Names starting with $ belong to the tracker ($click, $rageclick, $deadclick, $form_abandon, $jserror). Don't reuse them for your own events — see what is captured automatically.

Reading them back

Events appear in the dashboard under Events, and through the API: GET /api/v1/sites/{site}/breakdown/events for the counts, GET /api/v1/sites/{site}/timeseries?event=signup for one event over time. See the API reference.