siteline Start free trial Log in

How to track custom events in SiteLine

See your data

SiteLine ingest accepts two event types: pageview and custom. Pageviews are automatic after install. Custom events are named product actions you send on purpose. A custom event without a name is dropped. Properties are optional and capped so cardinality cannot explode.

Custom events count toward the same pool as pageviews. Goals that match an event name do not send a second event. Define the goal in the dashboard after the name is flowing.

Limits and payload shape: custom events. Plans: billing.

What to send (and what not to)

Send verbs that mean a decision: signup_clicked, checkout_started, signup_completed, purchase. Do not send mouse moves, scroll depth, or a new name per user id. There is no user id in this tracker. Properties may be string, number, or boolean only — no objects, no arrays, no PII you would not want in a table.

Names should be lowercase and stable. The Events breakdown and event-name goals match the string exactly. Outbound Link and File Download are the names the optional auto-trackers already use. Do not reuse them for something else.

1. Install the tracker first

HTML: script tag with data-site-id and absolute data-endpoint. React: SDK with <Analytics />. Confirm Live shows pageviews. Custom events from a page that never inited go nowhere.

2. Call track at the moment it happened

Vanilla / shared core

import { track } from '@siteline.tools/tracker';

track('checkout_started', {
    plan: 'growth',
    value: 19.99,
    trial: true,
});

init() must have run. The HTML snippet calls init() as it loads. If you only use the package, call init({ siteId, endpoint }) once at startup.

React

import { useAnalytics } from '@siteline.tools/react';

const { track } = useAnalytics();
track('checkout_started', { plan: 'growth' });

Call it in the handler that means the thing happened (onClick, successful fetch), not in a useEffect that re-fires on every render. You will bill yourself.

The collect POST looks like this (UTMs are parsed from the page query string when present):

{
    "public_id": "YOUR_SITE_ID",
    "name": "checkout_started",
    "type": "custom",
    "url": "https://example.com/checkout",
    "path": "/checkout",
    "referrer": "https://example.com/pricing",
    "hostname": "example.com",
    "properties": { "plan": "growth" },
    "utm_source": "newsletter"
}

You do not assemble this JSON by hand in production code. track() does. Endpoint: POST /api/analytics/event (alias POST /js/event).

3. Stay inside the property caps

Enforced in the tracker and again on ingest:

Extra keys are dropped. Long keys and strings are truncated. Do not "just add the user email to be safe."

There is no server-side catalog you must register before a name is allowed. First event with a new name appears in the Events breakdown once it ingests. That is convenient and dangerous: typos become new rows forever. Pick a short list and stick to it.

4. Turn on auto outbound/downloads only if you need them

Script attributes:

React options: trackOutboundLinks, trackFileDownloads, fileDownloadExtensions.

These emit custom events and therefore cost quota. A docs site that links out on every page can burn a surprising share of a Starter 1M pool. Leave the flags false (the default) unless the report is worth it.

5. Verify in the product

Open the analytics site → Events. Your names should appear with counts. Live is only a 30-minute window of pageviews/visitors/top pages — use Events for custom names, or fire an event and watch Network for the POST.

Then, if the event is a conversion, create a goal with match type event name and the exact string. Conversion rate is unique visitors who sent that event divided by unique visitors in the range (subject to the visibility gate). No extra snippet.

SPA and name hygiene

The core already sends pageviews on history changes (with App Router caveats). Do not also track('pageview'). Pageviews are type pageview, name pageview. A custom event named pageview is a mess.

If you fire signup_completed on a thank-you page and also goal-match exact path /thanks, you will have two goals measuring related things. Pick one primary conversion rule.

FAQ

Can I send events from the server?

The documented install is the browser tracker posting JSON to collect. This guide is that path. Do not invent a private server-to-server API from this article.

Why did my eleventh property disappear?

The eleventh key is dropped. Ten is the cap. Same for overlong strings. Check the payload in Network; ingest will not reject the whole event just to preserve extra keys.

Do properties show up as funnel steps?

No. Funnel and goal steps match exact path, path contains, or event name. Properties are on the event, not step matchers. Keep the name meaningful enough to goal on.