Custom events, goals & UTM tracking
Custom events record what automatic tracking misses: signups, checkouts, feature usage. Track them from the browser with window.lytics.track(), or from a server with the SDK or POST /v1/events; goals then turn event names or URL paths into conversion metrics.
Track from the browser
Section titled “Track from the browser”Once lytics.js has loaded, call window.lytics.track(name, props?):
window.lytics.track("signup", { plan: "pro" });| Constraint | Value |
|---|---|
name |
Must match [a-zA-Z0-9_.:-]{1,64}; truncated to 64 characters |
props |
Flat object of string/number/boolean values. Nested objects aren’t supported |
props size |
Serialized to at most 2048 bytes |
Track before the script has loaded
Section titled “Track before the script has loaded”If you need to call track() before lytics.js has finished loading (for example from an inline script that fires early), install this stub first. It queues calls, and the real tracker drains the queue in order right after its own initial pageview:
<script> window.lytics = window.lytics || { q: [], track: function (name, props) { this.q.push([name, props]); } };</script><script src="https://cdn.analytics.canarycoders.es/lytics.js" data-domain="myapp.com" defer></script>
<script> // Safe to call immediately; queued if lytics.js hasn't run yet. window.lytics.track("landing_cta_click");</script>Track from a server
Section titled “Track from a server”Use the SDK or a raw POST /v1/events call with a full (cly_live_…) key. Read-only keys get 403 read_only_key:
import { createClient } from "@canarylytics/sdk";
const lytics = createClient({ apiKey: process.env.CANARYLYTICS_KEY });await lytics.events.track("signup", { plan: "pro" }, { path: "/app/onboarding" });curl https://api.analytics.canarycoders.es/v1/events \ -H "Authorization: Bearer cly_live_…" \ -H "Content-Type: application/json" \ -d '{"name":"signup","props":{"plan":"pro"},"path":"/app/onboarding"}'path defaults to "/". sessionId is optional and lets you attach the event to an existing client-minted session. Omit it and the server mints a random one. Server-side events skip geo/UA classification entirely: isBot is always false, and there is no traffic-source label.
Goals turn a custom event name or a URL path pattern into a conversion metric. They are created in the dashboard, under Settings then Goals. There is no public REST or SDK endpoint to create one, only to read the resulting stats:
- Event goals match an exact custom event name.
- Path goals match an exact path, or a path with a
/*suffix for prefix matching (for example/checkout/success/*).
A project can have up to 20 goals. Read conversion counts and rates with GET /v1/stats/goals or client.stats.goals(). Conversion rate is converted sessions divided by total sessions in the window.
UTM tracking
Section titled “UTM tracking”For page_view events only, utm_source, utm_medium, and utm_campaign are extracted from the query string of the landing path at ingest time and stored alongside the event. No snippet configuration is needed; it happens automatically for any URL like:
https://myapp.com/?utm_source=newsletter&utm_medium=email&utm_campaign=spring-launchutm_term and utm_content are not captured. Read the breakdown with GET /v1/stats/utm or client.stats.utm(), which returns sessions and pageviews grouped independently by source, medium, and campaign.