Instrumenting an app · 4 min read · Updated 2026-09-22
Analytics in application code
Name the intent, fire it once, identify the person, and put the charge on the server — the browser never saw the card succeed.
Part 5 of 8 · Next: A checkout, end to end
Error tracking tells you the charge threw 40 times. It does not tell you that 3,000 people put a product in a cart last week and 700 paid. That gap is product analytics: named actions, in order, tied to a person. The SDK you already installed for exceptions is the same SDK. The envelope is not.
Concepts — visitor, session, funnel, privacy — are in the product analytics guides. This chapter is what you type on the example checkout. If your core action is signup, upgrade, or publish, keep the shape: a page or screen, a meaningful view, an intent, a start, a success or failure.
Project settings, then consent
Turn analytics on in Project settings. Browser SDKs still wait for optIn() after the visitor agrees. That is how you put the storefront behind a consent banner. A server call can record order_completed with a userId or anonymousId once the project allows analytics. See privacy and consent and the setup guide.
Talaria.init({
dsn: 'https://ingest.newtalaria.com',
apiKey: process.env.NEXT_PUBLIC_TALARIA_KEY!,
release: '1.4.2',
});
Talaria.analytics.optIn();A checkout taxonomy
Start with six names. You can add more; you cannot cheaply rename an event the quarterly report already uses. Convention: object_verb in past tense, ids in properties. Full naming rules: events and properties.
$pageview—Talaria.analytics.page()on each storefront navigation. The SDK will do this for you on the web if you callpagefrom the router; do not also inventpage_viewed.product_viewed— the product page is meaningful (/products/trail-runner), not a hover on a card.add_to_cart—sku,price,size.checkout_started— they committed to paying, not that the layout mounted twice in Strict Mode.checkout_failed— the charge did not complete. Reason as a property (card_declined), not the exception message.order_completed— server-side, after the charge and the row. This is the one the funnel exists for.
Event detail
storefront
Properties
{ sku: 'TR-900', price: 129, size: 'M' }
Identity
- anonymousId
- a7f3…c1
- sessionId
- s_9d2…4e
- userId
- user_123
What happened
- name
- add_to_cart
- kind
- track
- timestamp
- 2026-09-21T09:14:02Z
Page context
- path
- /products/trail-runner
- referrer
- https://google.com
- utmCampaign
- spring-sale
Correlation
- replayId
- rpl_4c8…
- traceId
- 4bf92f35…
- release
- 1.4.2
Talaria.analytics.page(); // $pageview
Talaria.analytics.track('product_viewed', {
sku: 'TR-900',
price: 129,
});
Talaria.analytics.track('add_to_cart', {
sku: 'TR-900',
price: 129,
size: 'M',
});
Talaria.analytics.track('checkout_started', {
value: 129,
currency: 'USD',
item_count: 1,
});The charge the browser never saw
If you record order_completed in the browser, ad blockers, crashes, and “close the tab after Pay” will undercount the only number finance trusts. The API already knows the charge succeeded. Forward the browser’s anonymousId (and userId if present) on the checkout request so the server event stitches to the same person.
Talaria::analytics()->track('order_completed', [
'sku' => 'TR-900',
'value' => 129,
'currency' => 'USD',
'order_id' => $order->id,
], [
'anonymousId' => $request->header('X-Anonymous-Id'),
'userId' => $buyer->id,
]);PHP analytics has no cookie jar and no autocapture. If you omit identity options, the row is harder to join to the storefront session. Failed charges that you still want on the funnel fire checkout_failed here too — next to captureException, not instead of it.
Identify after login, not before
anonymousId is a browser. sessionId is a visit. userId is a person. identify binds the first to the third. Call it when you know who they are — after login, after account creation — with a stable application id. Calling it on every pageview does nothing useful and creates noise in the identify stream.
Talaria.setUser({ id: user.id });
Talaria.analytics.identify(user.id, {
plan: user.plan,
});One visitor, three sessions, one person
storefront
- Mon 09:02$pageviews_9d2…4eanonymous
First visit. Visitor id created and stored first-party.
- Mon 09:05add_to_carts_9d2…4eanonymous
Same session — under 30 minutes since the last event.
- Mon 11:40$pageviews_1b4…a8anonymous
New session. Same visitor: the idle window expired.
- Mon 11:42$identifys_1b4…a8user_123
Signs in. Every later event carries the user id.
- Tue 08:15$pageviews_66f…02user_123
New UTC day, new session — still one unique person.
Do not pass email as a property — the server strips it. Do not use email as userId. Mechanics and the unique-user rule: visitors, sessions, and identify.
The funnel is five names
The checkout funnel is the sequence already drawn in Learn: $pageview → product_viewed → add_to_cart → checkout_started → order_completed. Session scope, one-day window. Every entrant who stops is a person you can open — replay, errors, trace. How the counts are computed: funnels and drop-off.
Checkout funnel · 24h window
storefront
- 01 $pageview9,318 · 100%
- 02 product_viewed5,140 · 55.2%
−4,178 dropped here
- 03 add_to_cart2,106 · 22.6%
−3,034 dropped here
- 04 checkout_started1,284 · 13.8%
−822 dropped here
- 05 order_completed742 · 8.0%
−542 dropped here
Entrants who never reached step 2 are listed by name, each with their replay, errors, and trace.
Properties that survive a year
- Scalars only — sku, price, size, currency, plan, reason. Nested objects stringify and will not filter the way you hope.
- Low cardinality in the name, high cardinality in the property.
product_viewed+{ sku: 'TR-900' }, neverproduct_TR900_viewed. - 64 keys, 1024 characters per string, 16 KB for the map or the map is dropped whole. No serialized carts. No stacks.
- Secret keys (
password,token,email,credit_card, …) never land. Do not try to outsmart the strip list.
Related guides
Instrumenting an app · 5 min
Which call to makeThe chapter you keep open while you write. A failure, an intent, a duration, or context — pick one call, or pick none.
Product analytics · 3 min
Events and propertiesFour kinds of call, one envelope, and a property bag you control. Naming is the only hard part.
Product analytics · 3 min
Visitors, sessions, and identifyThree ids doing three different jobs. Get them straight and every number downstream makes sense.
Product analytics · 4 min
Funnels and drop-offA funnel tells you which step loses people. Talaria then hands you the people, and the replay of them leaving.