Skip to content

How-to

Track custom events with praxis.track

Download Markdown

Use window.praxis.track(type, props) to track a custom event from page JavaScript. In the site admin, open Composer > Scripts to add a sender, and Insights > Events & Capture > Catalog to define what the event means. A definition alone sends nothing.

Checked against the product’s code on 7 November 2026.

The helper sends through the site’s own event collector, subject to analytics consent and capture limits.

Start with Page scripts and events if you need to add the sender to a page. The following example runs inside a Composer page script:

window.praxis.track("demo_request", {
source: "product_page",
path: window.location.pathname
});

This is an integration example, not a built in event. Use a name and properties that describe the interaction on your site.

Argument Contract
type A lowercase name beginning with a letter, followed by letters, digits or underscores. It must contain 3 to 64 characters.
props A JSON serializable object. An array or missing value is treated as an empty object.
Return value No delivery receipt or promise. The helper returns silently on an invalid name, refusal or serialization error.

The helper becomes available with the page’s capture runtime. A Composer Page load script runs after that helper is installed. On a page without Composer page scripts, a visitor who refused analytics or sends Global Privacy Control gets no capture runtime, so window.praxis is undefined. Other code should check first, for example window.praxis && window.praxis.track("demo_request", {}).

Keep properties specific to the action. Do not send passwords, payment data or unrelated personal data. The event catalog describes properties; it is not a sanitizer for arbitrary values your code sends.

The capture runtime sends nothing while analytics is not allowed for the visitor, including an undecided visitor in an opt in region. It checks the browser’s Global Privacy Control signal and saved analytics refusal on each call. Do Not Track suppresses the beacon while no analytics choice has been saved.

Capture has event budgets in the browser and a rate cap at the public collector. Capture health reports dropped activity. A call to track is therefore not proof that a row was stored.

The public collector refuses event types reserved for the server. It also refuses experiment and variation stamps supplied by the browser. Do not send a browser purchase, refund or exposure to stand in for platform records of those actions.

Check the sender as well as the event definition:

  • Make sure the capture runtime has installed window.praxis.track before your code calls it.
  • Check analytics consent, Global Privacy Control and the saved analytics choice. The consent rules above still apply.
  • Use a valid event name and JSON serializable properties. Invalid input can return silently.
  • Review the browser event budget, the collector rate cap and Capture health for dropped activity.

The helper gives no delivery receipt. A call does not confirm that the event was stored.

  1. Open Insights.
  2. Open Events & Capture.
  3. Open Catalog.
  4. Choose New event.
  5. Enter Label.
  6. Enter Event name (snake_case).
  7. Add What it means (optional) if a description would help.
  8. Review Count by default.
  9. Review Intended weight. Recording a weight here does not apply it to live scoring.
  10. If the event carries a property, choose + Add a property under Properties it carries (optional).
  11. Enter the property key.
  12. Choose its type: text, number or yes/no. Repeat the property steps for any others the event carries.
  13. If you added a numeric property, review Monetary/numeric value comes from. Leave it at no value if the event just counts.
  14. Choose Preview.
  15. Read what will be recorded.
  16. Choose Define event when the preview matches your intent.
  17. Check the result, which says the event is in the catalog.

A definition also records its value source, counting defaults and intended weight.

For a custom definition:

  • Follow the same name shape as track.
  • Avoid the reserved praxis_ prefix and structural names pageview, exposure, goal and tick.
  • Keep the key stable. Rename the label if the wording changes. A definition’s key cannot be changed in place.

Defining an event does not add a listener or start sending it. Add a page or section binding, call track, or enable the appropriate automatic capture separately.

The catalog is not an ingestion allowlist. A valid custom event can arrive without a definition and appear in Needs review. Disabling a definition removes its compiled capture bindings; it is not a general server block on custom calls to track.

The catalog shows built in events alongside your own. Examples include:

Event Meaning
pageview A page view from the site’s capture runtime.
section_view A section became sufficiently visible when that capture class is enabled.
content_click A click through to content from a bound section.
page_engagement Visible time on a page when that capture class is enabled.
form_submit A successful native form submission recorded by the server.

Automatic capture has controls for section views, clicks within sections, outbound links, downloads, scroll depth, search, forms, video and time on content. Query parameters selects additional arrival parameters to capture. Enabling collection requires approval.

An event can be listed before anything on the site sends it. It collects nothing until something does.

See the complete event catalog for every seeded event, its sender and its properties.

An event’s catalog weight records intent. It does not change live affinity scoring. Changing live weights is a separate approved personalization setting.

A goal uses the recorded events to define a result. Agree the event meaning with the people building goals and experiments before instrumenting the page. For consent details, read Privacy and consent.

After your own sign in succeeds, post the customer’s stable account identifier to /api/dxp/identity/link. The server identifies the current browser from its cookie. This links the browser for counting; it does not authenticate the customer or grant access to paid content. The page’s capture script now installs praxis.identify and praxis.logout. On eligible pages for the site’s own signed-in shoppers, it can submit a signed link automatically. This still needs analytics consent and a visitor cookie; it does not replace account sign-in.

Live connection tickets included with a page are encrypted; do not try to read the visitor id by decoding one. Keep the live channel’s shared secret on the server. If that secret is missing or empty, the site issues no live connection ticket.

POST /api/dxp/consent no longer returns a visitorId field. Its JSON reply still reports the recorded purposes, consent regime, policy version, GPC downgrade and consent snapshot. GET /api/dxp/live-check reports whether the browser has an identity without printing any part of its id. Do not use either reply to obtain the visitor id.

Do not send a visitor ID. Once a site has created its identity secret, a link needs a valid server-issued assertion and numeric exp; a missing or invalid assertion is refused. The platform keeps that site secret encrypted and does not expose it as a customer setting. An unreadable stored secret refuses linking. A site that has never created one can still accept an unsigned link. For a custom sign-in integration, ask support how to obtain the required assertion; an account identifier alone is not proof of authentication.

This example is only for an integration that already has a valid server-issued assertion. customerId is the stable account identifier from your verified sign-in flow; identityAssertion is that assertion and identityExpiry is its numeric expiry. Do not invent these values.

const response = await fetch("/api/dxp/identity/link", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ accountId: customerId, assertion: identityAssertion, exp: identityExpiry })
});
const result = await response.json();
if (!response.ok || !result.ok) {
// Handle the refused link in your own account flow.
}

When the customer signs out, post to /api/dxp/identity/detach as part of your own sign out flow. Check the response before assuming detachment succeeded. A successful detach clears the person and visitor cookies; the next eligible page load can create a fresh anonymous identity. It does not replace your application’s session logout. Consent and the site’s counting policy still govern retained identity details.

const detached = await fetch("/api/dxp/identity/detach", { method: "POST" });
if (!detached.ok) {
// Handle the failed detach in your own account flow.
}

Return to Counting people and linking browsers to review the saved link and erasure boundaries.