Track funnel events with track and identify
Updated
Once the Kalman tag is installed, page views, click IDs and UTM tags are recorded automatically. This article covers the two calls you add yourself:
kalman('track', ...)marks a funnel step, such as an intake starting or a purchase.kalman('identify', ...)links the visitor's browser to their later purchases, so ad platforms can match more of them.
Do you need this?
It depends on where your purchases come from.
- If you've connected Sylaris OS or a webhook source: intake, purchase, approval and refill events already arrive server-side. You usually only need
identify, on the page where the patient enters their email. - If not: add the
trackcalls below for the steps your site handles.
The install page's Track funnel steps section tells you which case applies to your workspace.
The events
| Event | When to fire it | Example |
|---|---|---|
page_view |
Automatic on every page load and in-app navigation. Nothing to add. | — |
lead |
Someone leaves their details: a waitlist, quiz or contact form. | kalman('track', 'lead'); |
intake_started |
The first step of the intake form is shown. | kalman('track', 'intake_started'); |
intake_step_completed |
A step of the intake is completed. | kalman('track', 'intake_step_completed', { step_index: 2, step_count: 6 }); |
intake_completed |
The intake is submitted. | kalman('track', 'intake_completed'); |
product_selected |
The patient picks a plan or product. | kalman('track', 'product_selected', { product_sku: 'plan-a' }); |
checkout_started |
The checkout page or payment step opens. | kalman('track', 'checkout_started', { product_sku: 'plan-a', value: 199, currency: 'USD' }); |
purchase |
The payment succeeds (the confirmation page). | kalman('track', 'purchase', { order_ref: orderId, product_sku: 'plan-a', value: 199, currency: 'USD' }); |
account_created |
The patient creates a portal account. | kalman('track', 'account_created'); |
portal_viewed |
The patient opens the portal after signing in. | kalman('track', 'portal_viewed'); |
custom |
Anything else worth counting. | kalman('track', 'custom', { name: 'pricing_faq_opened' }); |
In these examples, orderId stands for a variable your page already has. It isn't text to copy.
Events the browser can't send
provider_approved, provider_declined, order_shipped, refill_purchased, subscription_canceled and refund_issued only come from your platform (Sylaris OS or a webhook source). If a page sends one, Kalman refuses it.
Custom events
A custom name must start with a letter. It can use only letters, numbers and underscores, up to 40 characters. Kalman refuses any name that refers to a condition or medication, or to one of your own sensitive terms. Refused names show up as a count in your weekly privacy summary.
If you call kalman('track', 'pricing_faq_opened') with a name that isn't on the list, it's recorded as a custom event with that name.
Fields Kalman accepts
For purchase, checkout_started and product_selected:
order_ref: your order ID. Kalman uses it to match the server event for the same order, so a purchase is counted once. Letters, numbers and- _ . :only, up to 120 characters.product_sku: your SKU code, mapped to a product in Kalman (see Products and aliases). Use a code likeplan-a, never a medication name. Up to 100 characters, with the same characters allowed asorder_ref.value: the amount as a number, such as199or199.50. No currency symbol.currency: a 3-letter code, such asUSD,CADorGBP.event_id(optional): an ID shared with the Meta pixel for the same event, so Meta keeps one copy. See "Using the Meta pixel too" below.
For intake steps:
step_indexandstep_count: whole numbers.journey_key: a short code saying which intake it is, such asintake_v2. Letters, numbers,-and_, up to 40 characters.
What gets dropped
- The tag sends only the fields listed above. Anything else you pass is left out in the browser.
- A value in the wrong format is dropped and the rest of the event is kept. For example, a SKU with spaces, a value that isn't a number, or a currency that isn't 3 letters.
- Never put names, conditions, medications, intake answers or free text in any field.
Link the visitor (identify)
Call identify once the patient has typed their email, for example when that form step is submitted:
// On the step where the patient types their email, e.g. on submit:
kalman('identify', { email: emailInput.value });
// Phone too, if you collect it:
kalman('identify', { email: emailInput.value, phone: phoneInput.value });
// Your own patient or account ID, if you have one:
kalman('identify', { email: emailInput.value, external_id: accountId });
emailInput.value, phoneInput.value and accountId stand for values your form or page already holds. They aren't text to copy. Pass the variable, not a fixed value.
What happens:
- In the browser, the tag lowercases the email and keeps only the phone's digits. A 10-digit number is treated as a US number. It then hashes each value (SHA-256).
- Only the hashes reach Kalman. The plain email and phone never leave the browser.
- If none of the values is usable (no
@in the email, too few digits in the phone), nothing is sent. - Hashing needs a secure page, so
identifyworks onhttpspages only.
Using the Meta pixel too
If the Meta pixel fires the same event, give both the same ID so Meta counts it once:
var id = kalman.eventId();
kalman('track', 'purchase', {
event_id: id,
order_ref: orderId,
value: 199,
currency: 'USD',
});
fbq('track', 'Purchase', {}, { eventID: id });
Where to paste the calls
- Custom site or intake: call
kalman(...)in your code where the step happens. - Webflow or Framer: the page's custom code (before
</body>) on that step's page. - WordPress: a code snippet plugin, or your theme's footer.
- Google Tag Manager: a Custom HTML tag with the call inside a
<script>, fired by a trigger on that step.
The snippet must be on the page too.
Check it worked
- Do the step on your own site.
- On the install page, open Check it worked and click Events log for the last 10 minutes. You can also open Event log in the sidebar.
- Look for a row with the event name and the source Browser tag. For a purchase, check the Value and Product columns too.
The filter shows Last 10 minutes · show all. Click it to see everything. If nothing shows up, see Troubleshooting: no data.
What Kalman never sends
Kalman builds what goes to ad platforms from a short allowlist. It never sends product names, SKUs, conditions, medications or intake answers. Email and phone only ever travel as hashes. Read more in Event log and data flow.
Related articles
- Install the Kalman tagCopy the snippet from Integrations → Tracking, paste it in the head of every page, allow your domains, then press Verify installation.
- The Event log, deliveries and the data-flow recordSee every event Kalman received, exactly what it sent to Meta and why anything was held back, and download a data-flow record.
- Products and aliasesAdd your programs with a SKU, price and projected LTV, and link unmatched SKUs or Stripe prices so revenue and LTV land on the right product.
- Connect Sylaris OSSend payments, provider decisions, shipments and refills from Sylaris OS to Kalman over a signed webhook, then check that they arrived.
- Stripe and webhook catchersConnect Stripe, or catch any platform's webhook, map its fields to Kalman events, test the mapping, and watch for changes.
- Troubleshooting: no data or nothing sentWhy the tag isn't recording, a tracking domain is stuck, or events aren't reaching an ad platform, and how to fix each case.
Support
Still stuck? Log in and open a request.
We answer in writing within one business day.
Open a request