JavaScript API

Every method on window.mrkr, the declarative data-attribute alternative, and what happens if you call it before the tracker has loaded.

Markdown
Updated Oct 4, 2026
On this page
  1. Before you call anything
  2. mrkr.track(name, props?)
  3. mrkr.revenue(amount, props?)
  4. mrkr.pageview()
  5. mrkr.sessionId
  6. mrkr.checkoutMetadata()
  7. Declarative attribute API
  8. Script tag configuration

Two ways to send a custom event: call a method on window.mrkr, or annotate an element with a data-mrkr-event attribute and let a click do it for you.

Before you call anything

The install snippet loads the tracker with defer, and there is no stub or command queue waiting to replay your early calls: unlike some analytics snippets, window.mrkr simply does not exist until the deferred script has executed. An inline <script> placed after the snippet in your HTML runs immediately during parsing, before the deferred script has had a chance to run, so calling window.mrkr.track(...) from it will throw.

mrkr.track(name, props?)

ts
mrkr.track(name: string, props?: Record<string, string | number | boolean | object>): void

name is truncated to 64 characters with no other validation. If you call track() with no name, or a falsy one, the call doesn't throw: the server receives an event with no name and records it as a plain pageview instead, which will misattribute the hit rather than surface an error.

props accepts a plain object with up to 8 keys. If you send more, the 8 kept are chosen by sorting all keys alphabetically and taking the first 8, not the order you wrote them. Keys longer than 64 characters are truncated; keys containing anything outside letters, numbers, _, ., :, - are dropped silently. String values truncate to 256 characters; booleans and finite numbers pass through unchanged; null, undefined, NaN, and Infinity are dropped; objects and arrays are JSON-stringified and then also truncated to 256 characters, so a large nested object can be cut off mid-JSON and become unparseable on read. track() returns nothing and does not return a promise: it queues the event, which is flushed with the rest of the batch about a second later, sooner if ten events are already waiting, and immediately when the tab is hidden or closed.

mrkr.revenue(amount, props?)

ts
mrkr.revenue(amount: number, props?: Record<string, string | number | boolean | object>): void

amount is coerced with Number(amount) || 0: a non-numeric value silently becomes 0 rather than throwing. The call sends an event named revenue with amount merged into props.

mrkr.pageview()

ts
mrkr.pageview(): void

Closes out the route you're leaving (flushing its final page_leave with duration, visible and engaged time), starts fresh timers, fires a pageview for the current URL. The tracker already calls this automatically on history.pushState, history.replaceState, popstate, and a bfcache restore, so most single-page apps never need to call it directly: reach for it only if your router doesn't go through the History API, such as an old-style #/route hash router.

mrkr.sessionId

ts
mrkr.sessionId: string

A live, read-only string getter for the current session. When tracking activity rotates the session after 30 minutes of inactivity, this property immediately reflects the new ID. Reading it does not keep a session alive. For checkout, use checkoutMetadata() to capture a fresh session at the time the customer starts paying.

mrkr.checkoutMetadata()

js
const metadata = window.mrkr?.checkoutMetadata() ?? {};
// { mrkr_session_id: "s_..." }
// Send metadata to your own checkout endpoint.

Returns only mrkr_session_id, refreshes an idle session if necessary and remembers the checkout's originating session in this tab for up to 24 hours. It reads no form values and creates no persistent cookie. Your server must pass the metadata to Stripe; this helper cannot change a Checkout Session already created elsewhere. See Stripe attribution.

Native same-origin POST formhtml
<form method="post" action="/api/checkout" data-mrkr-checkout>
  <button type="submit">Checkout</button>
</form>

Only a same-origin POST form marked data-mrkr-checkout receives a hidden mrkr_session_id field. Native submission and new FormData(form) both capture the current session. Read that field on your server and pass it to Stripe as shown in the revenue guide. Other forms and their input values are untouched.

Declarative attribute API

html
<button data-mrkr-event="cta_click"
        data-mrkr-prop-variant="hero"
        data-mrkr-prop-plan="pro">
  Start free
</button>
<!-- equivalent to: mrkr.track("cta_click", { variant: "hero", plan: "pro" }) -->

data-mrkr-event sets the event name, capped at 64 characters like track(). Any data-mrkr-prop-<key> attribute becomes a property; camelCase-looking dataset keys are converted back to snake_case, so data-mrkr-prop-plan-tier becomes plan_tier in props. Attribute values are always strings: there's no client-side type coercion, unlike calling track() directly with a number or boolean.

Script tag configuration

AttributeDefaultWhat it does
data-siteNoneRequired. Your site id.
data-cookiesabsentOpt-in. "on" enables cookie mode (a one-year first-party _pw_id). Absent = cookieless = no cookie written or read.
data-endpointsame-origin /api/collectOverride the ingest URL.
data-replay-endpointsame-origin /api/replayOverride the replay ingest URL.
data-mask-input"1"Masks all typed input in session replay. Set "0" to disable, not recommended.
data-autocaptureno longer usedRetired in September 2026 when click autocapture was removed. Ignored by the tracker; safe to delete from your snippet.
data-debug"0"Set "1" to log tracker activity to the console.

See custom events for when to reach for track() versus the declarative attribute, and what mrkr records automatically for what's already captured without either.