Skip to content

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.

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

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>

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" });
Terminal window
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.

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-launch

utm_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.