Docs/Goals & events/Custom events

Custom events

Track signups, purchases and refunds from your site with dzati.track().

Beyond pageviews, Dzati can record your most important conversion events so you can tie signups and revenue back to the traffic that earned them.

In this first release we support three custom events:

  • signup — someone creates an account or becomes a lead
  • purchase — a completed sale (records revenue)
  • refund — money returned for an order (reduces revenue)
Note: You need the Dzati tracker installed first. See Install the script.

Setup — add this snippet to send events

To send custom events you need one small snippet in addition to your install script tag. Add it once, before your event code — the <head> is the ideal spot:

html
<!-- Your Dzati install tag (already on your site) -->
<script defer data-site="DZ-XXXXXXXX" src="https://e.dzati.com/d.js"></script>

<!-- Required for custom events — makes dzati.track() ready immediately -->
<script>
  window.dzati = window.dzati || function () { (window.dzati.q = window.dzati.q || []).push(['call', arguments]); };
  ['track','identify','pageview'].forEach(function (m) {
    window.dzati[m] = window.dzati[m] || function () { (window.dzati.q = window.dzati.q || []).push([m, arguments]); };
  });
</script>

The tracker script loads with defer, so it finishes loading after your page has rendered — which means a dzati.track() call that runs while the page is loading would otherwise be lost. This snippet makes dzati.track() available the instant your page runs: it safely queues your calls and the tracker replays them the moment it's ready. So you can call dzati.track(...) anywhere, at any time, and nothing is missed.

Only sending pageviews? You don't need this snippet — your install script tag already records those by itself. Add it only when you want to send custom events.

The API

Every custom event is sent with a single call:

js
dzati.track(eventName, data);
  • eventName — one of signup, purchase, or refund.
  • data — an object with the event's fields (shown for each event below).

You never pass a visitor or session id. The tracker attaches those automatically from the visitor's first-party cookie — the same identity used for your pageviews — so every signup and sale is attributed to the right visitor and traffic source.

How we prevent duplicates

A page reload, a retry, or a repeat call can send the same event twice. Dzati de-duplicates using the key you provide, so the same action is counted once — even across reloads, different devices, or days apart:

  • purchase — deduplicated by order_id.
  • refund — deduplicated by refund_id (or order_id if you don't send one).
  • signup — deduplicated by user_id when you provide it (otherwise every signup call is recorded).

These keys are only ever matched against themselves, so they never collapse genuinely different actions together — the same browser can sign up two separate accounts, or place two real orders, and both are counted. Send the right key and you don't have to think about duplicates.

Amounts and currency

  • value_cents is the amount in the smallest currency unit — cents for USD/EUR, pence for GBP. So $49.00 is 4900.
  • currency is an optional 3-letter ISO code such as USD. If you omit it, your site's default currency is used.
  • For refunds, send value_cents as a positive number — Dzati records it as a deduction for you.

signup

Track when a visitor creates an account or becomes a lead.

js
dzati.track('signup', {
  user_id: 'john.doe@google.com',
  plan: 'pro',
  method: 'google',
  referral_code: 'LAUNCH20'
});

All fields are optional:

  • user_id (string) — your own id for the new account: an internal id, username, or email. When you send it, Dzati counts one signup per user_id, so a page reload or a repeat call won't double-count. It's matched only against itself, so the same browser can create two different accounts and both are counted. Without it, every signup call is recorded as-is.
  • plan (string) — the plan or tier chosen, e.g. pro.
  • method (string) — how they signed up, e.g. email, google, github.
  • referral_code (string) — an acquisition or referral code.

You can include any other fields you like; they are stored alongside the event.

purchase

Track a completed sale. This records revenue and attributes it to the visitor's first touch.

js
dzati.track('purchase', {
  order_id: 'ORD-10492',      // required
  value_cents: 4900,          // required — $49.00
  currency: 'USD',            // optional
  plan: 'pro',
  coupon: 'LAUNCH20'
});

Required:

  • order_id (string) — your unique order reference. Used to prevent double-counting.
  • value_cents (integer) — the total amount charged, in the smallest currency unit.

Optional:

  • currency (string) — ISO code; defaults to your site's currency.
  • plan, coupon (string) — descriptive tags you can break revenue down by.
  • items (array) — the line items in the order (see below).

Multiple items

Pass an array of items. Each item takes sku, name, qty, and price_cents (the per-unit price):

js
dzati.track('purchase', {
  order_id: 'ORD-10492',
  value_cents: 7900,          // the actual total you charged
  currency: 'USD',
  items: [
    { sku: 'PRO-ANNUAL', name: 'Pro annual', qty: 1, price_cents: 4900 },
    { sku: 'SEAT',       name: 'Extra seat', qty: 2, price_cents: 1500 }
  ]
});
Note: value_cents is the figure we record as revenue — it is the real total you charged, after any tax, shipping or discounts. The items list is informational and does not have to add up to value_cents.

refund

Track money returned to a customer. A refund reduces the revenue and lifetime value of the original order.

js
dzati.track('refund', {
  order_id: 'ORD-10492',      // required — the order being refunded
  value_cents: 4900,          // required — amount refunded (positive)
  currency: 'USD',
  reason: 'customer_request'
});

Required:

  • order_id (string) — the order this refund belongs to.
  • value_cents (integer) — the amount refunded, as a positive number.

Optional:

  • refund_id (string) — a unique id for this refund. Send it whenever an order can have more than one refund (for example, partial refunds).
  • currency (string) — defaults to your site's currency.
  • reason (string) — e.g. customer_request, fraud, duplicate.

Refunding one item from an order

For a partial refund, send the amount being returned plus a refund_id, so several refunds against the same order are each counted:

js
dzati.track('refund', {
  order_id: 'ORD-10492',
  refund_id: 'RF-558',        // distinguishes this refund
  value_cents: 1500,          // the one seat
  currency: 'USD',
  reason: 'customer_request',
  items: [{ sku: 'SEAT', name: 'Extra seat', qty: 1, price_cents: 1500 }]
});

A second partial refund on the same order just uses a different refund_id, such as RF-559.

Good to know

  • Any fields beyond the reserved ones (order_id, value_cents, currency, refund_id) are stored as free-form properties. Keep them small — up to about 25 keys per event.
  • Don't put personal data (emails, phone numbers, card details) in event properties.
  • Events fired from localhost and staging hosts are ignored unless you enabled dev mode on the tracker.
  • Using a template engine that treats { } or {{ }} as code (WHMCS/Smarty, Handlebars, and many PHP carts)? Wrap any inline <script> that calls dzati.track(...) in the engine's raw block — in WHMCS/Smarty that's {literal} … {/literal} — or add it through your platform's custom-code field, so the braces in your event data aren't parsed away.
Tip: The setup snippet at the top handles call ordering for you — it queues any dzati.track() calls that fire before the tracker has finished loading, so you don't have to worry about where your event code sits relative to the script tag.