The tracking API

Send conversions with their value, currency and id, report your cookie banner's choice, and attach your own data, all through window.iads.

Updated October 26, 2026

One global function, window.iads(command, params), takes two commands: conversion and consent_update. Page views, outbound clicks and scroll depth are sent without any call. Each one becomes a single event that the screens read.

The function

The install snippet is the script tag alone; the tracker defines window.iads when the script runs. To call it before the script has loaded, define this queue stub yourself, above your calls and the tag:

window.iads = window.iads || function () {
  (window.iads.q = window.iads.q || []).push(arguments);
};

With the stub in place a call can sit anywhere on the page, before or after the script tag, and queued calls run in order once the script has loaded; without it, a call made before the script has loaded throws, because window.iads does not exist yet. No ready event exists or is needed. Any command name other than conversion and consent_update is ignored.

A command takes one object of parameters. Each field is checked: what is valid is kept and what is not is left out. A whole call is dropped for one reason only: a conversion whose type is neither primary nor secondary.

The conversion command

Call conversion when a visitor completes something your site counts, with the facts of that completion. This is the call your site's Settings page shows:

window.iads('conversion', {
  type: 'primary',
  name: 'purchase', // your stable identifier for this kind of conversion
  value: 49,
  currency: 'EUR',
  id: 'ORDER-1042', // dedupes a reloaded thank-you page
})

The minimal form is the tier alone:

window.iads('conversion', { type: 'primary' });
FieldAcceptedLeft out whenSent as
type'primary' or 'secondary'Anything else drops the whole call; nothing is sent.event_props.type
nameA string, trimmed, capped at 64 characters.Not a string, or empty once trimmed.event_props.name
valueA number, or a string that parses as one; finite, zero or more. An empty string parses as 0 and is kept.Negative, or not a number. Zero is kept; omit the field when there is no value.event_props.value
currencyThree letters, uppercased.Not three letters, or sent without an accepted value.event_props.currency
idAny value, turned into text, trimmed, capped at 128 characters.Empty once trimmed.event_props.conversion_id
custom_propsA plain object of your own key/values.An array or a non-object falls back to the page-level default (see Custom data).custom_props

A left-out field is simply absent. An id sent as the literal "undefined" or "null", what a tag sends when the variable it reads was never set, passes the tracker and is read as absent by the screens, so that conversion is counted once per fire.

type is the only required field. primary is the outcome the product treats as an object: a purchase, a lead. secondary is a softer goal; it marks the session "Engaged" on the Overview's live feed and on the Sessions screen, and does not appear on the Conversions screen, which is primary-only.

name is your stable identifier for the kind of conversion (purchase, trial_signup), optional. The Conversions screen groups by it in "By name", and you can give each name a readable label in the workspace settings; the identifier itself is never rewritten. Keep it stable and short, since it is what the grouping keys on. Available from tracker 6.3.0.

value is the worth you declare, an observed unit. A negative number is refused because a refund is not a conversion and would lower both the count and the declared value; zero is accepted, a free signup being a conversion. A conversion sent without a value reads "No value declared" on the Sessions screen and on the Conversions screen's log, never 0.

currency is an ISO 4217 code and rides with the value it describes. Declared value is summed per currency and never across currencies: there is no exchange rate anywhere in the product.

id is an opaque reference, typically your order id, and it dedupes: the Conversions screen counts one conversion per id, first fire wins, so a refreshed thank-you page, a back-navigation or a re-render in a single-page app does not count twice. A conversion sent without an id is counted once per fire. Keep it a reference your back office knows, never personal data.

On the Sessions screen a primary conversion is one card: the value, the custom_props you sent as key and value rows, the page it fired on, the id, and how long after the ad click it fired. The Conversions screen aggregates the same objects. On the Events screen a conversion is listed as "Conversion" in two rows: primary, "A purchase or a lead your site reported. Counted once per id on Conversions.", and secondary, "A secondary goal your tag reported."

Call consent_update when the visitor makes a choice on your own cookie banner:

window.iads('consent_update', {
  analytics: true,
  marketing: false,
  action: 'custom',
})
FieldAcceptedOtherwise sent as
analyticstrue or falsenull, read as unknown
marketingtrue or falsenull, read as unknown
action'accept_all', 'reject_all' or 'custom''unknown'

This call is always sent, whatever its fields hold. It records an observed signal: the visitor's decision on your banner. It is not a permission for Intelligence/Ads and it gates nothing on the tracker's side; the legal basis for collection sits with the site that installs it.

Where it surfaces: the Visitors screen's "Cookie banner" panel counts, among the paid browsers it lists, those that reported a choice, and among them how many granted and how many denied analytics (the panel reads that one boolean; marketing is read on a visitor's own chip); one visitor's latest choice shows as a "Consent" chip with Marketing and Analytics each read as granted, denied or unknown. Only an explicit false reads as denied; a missing or unknown value is unknown, never denied, and a choice whose two booleans are both unknown shows no chip at all. On the Sessions screen the choice that governed that visit shows as a "Consent then" chip, Marketing and Analytics each granted, denied or unknown: the latest choice observed at or before the session started. On the Events screen the type is listed as "Consent", described as "A choice made on your cookie banner."

Custom data

Your own key/values travel in custom_props, apart from event_props. Two ways to set them:

  • Per call — pass custom_props in a conversion call. It replaces the page-level default for that one event.
  • Page-level — set window.__iads_custom_props to an object. It rides on every event sent after it is set; set it before the tracker loads to cover the first page view.

How the screens read them: scalars only — a string, a number or a boolean — with keys verbatim, in the order you sent them. A nested object or an array is not shown. The three values a tag sends when the variable it reads was never set, "undefined", "null" and the empty string, are read as absent: never printed, never a breakdown bucket. A conversion shows at most 8 pairs, each value capped at 120 characters.

On the Conversions screen the breakdown's picker offers the keys your conversions actually carry, the most carried first, and groups conversions by the value of the key you pick. The product never hardcodes a key of yours; keep yours stable, since they are what the breakdown groups by.

The automatic events

Three event types leave the page with no code on your side.

EventWhenPayloadOn the Events screen
page_viewOn load, and on every pushState, replaceState and popstate of a single-page app that changes the URL; one that leaves it as it was sends nothing.none"Page view — A page loaded."
clickA click on a link whose host is not the page's host.kind: 'outbound', the resolved href, the link's text capped at 120 characters"Click — A click on a link to another site."
scrollThe first time the page's scroll reaches 25, 50, 75 and 100%, each mark once per page view.percent"Scroll — A reader reached 25, 50, 75 or 100% of a page. Up to four per page."

The scroll marks reset on every page view, so a route change in a single-page app starts them over. A click on a link to your own site is not an event. The Events screen counts these three beside the two calls.

Every event

Each call and each automatic event carries the fields below. A field with nothing to carry is null.

GroupFieldsWhat it holds
Identityevent_id, organization_id, site_id, session_id, visitor_idA random id per event; the two ids of your snippet; the session and visitor ids described below.
Eventevent_type, event_props, timestamp_clientThe command or automatic event, its payload, the browser's clock.
Pageurl, path, domain, page_titleThe page's address and title.
Referrersreferrer, session_referrer_initial, page_referrerThe referrer, or the previous URL on a route change; the first referrer the tab saw, kept for its later page views; the previous in-app path on a route change.
Acquisitiongclid, fbclid, ttclid, msclkid, gbraid, wbraid, li_fat_id, oppref, utm_source, utm_medium, utm_campaign, utm_content, utm_term, utm_id, utm_source_platform, utm_creative_format, utm_marketing_tacticRead from the current page's URL on every event; null when it carries none. See Tag your ad links.
Devicescreen_width, screen_height, viewport_width, viewport_height, viewport_device_pixel_ratio, language, timezone_offset_minutes, user_agent_clientScreen and viewport sizes, pixel ratio, language, timezone offset and user agent.
Your datacustom_propsThe per-call value, else the page-level global.
Scriptsdk_name, sdk_versionThe tracker's name and version.

Identity is a browser, never a person. The visitor id is random and stays with one browser until its storage is cleared; the session id is random too, per tab, and a new one starts each local calendar day. No cookie is set. When storage is blocked, the event carries no visitor id and a session id keeps the events of that one page load together. Install the tracker lists the three keys.

What is accepted

The page is served from your own domain; the tracker posts from there (a page on localhost or 127.0.0.1 posts to a local address instead, so verify on the deployed site). Two things can make an event not count:

  • A required field is missing or the wrong type (organization_id, site_id, session_id, timestamp_client). The snippet always sends them, so you meet this only when you post events yourself.
  • Your own site setting drops it. "Accept incoming events" is off, or "Only accept matched hosts" is on and the page's host is not listed. This is your setting, not an error: nothing is retried and nothing is logged in the browser. A change in Site settings takes effect within a minute.

Events also carry the time we received them and the address of the connection they came from. Nothing here depends on your plan: no allowance is checked when an event is accepted or kept. A plan governs the window you can read; on Free, once the month's allowance is crossed, the month's tail is withheld from reads until a larger allowance opens it, and on a paid plan nothing stops and the overflow is billed. See Plans and billing.

The verification

  1. In your browser's developer tools, filter the requests for collect and make the call. The request's body is the event.
  2. The site's Settings page shows the last event received, with its type and the host it came from, for example conversion from your domain.
  3. The Events screen counts each type in the period; a primary conversion appears on the Conversions screen and as a card on the session's own screen.

What the API does not do

  • It identifies a browser, not a person. There is no call to set a user id or an email, and the visitor id is a random first-party identifier the browser can clear.
  • It sends a conversion as a fact, never as a judgment: no goal configuration before the first fire, no id issued by the product, no attribution model, no exchange rate.
  • It never rewrites what you send into something else. An unrecognized type drops the call rather than guessing a tier; a negative value is refused rather than clamped; a value placed inside custom_props stays one of your properties and never becomes the conversion's value.
  • A secondary conversion is not an object. It reads "Engaged" on the feed and on the session, and the Conversions screen does not list it.
  • consent_update records a choice and gates nothing: the tracker keeps sending whatever the choice was. On the Realtime screen a consent choice is not counted as activity, so a banner's dismissal never stands beside a page the visitor chose to read.
  • There is no ready event and no callback. A call returns nothing; before the script loads it needs the queue stub, or it throws.

Questions

Do I need to wait for the tracker to load before calling window.iads?
Only if you have not added the queue stub shown under The function. The install snippet is the script tag alone; with the stub placed before your calls, a call made before the script has loaded is stored and replayed in order once it has. Without it, an early call throws. There is no ready event to wait for either way.
What is the difference between event_props and custom_props?
event_props is the payload the tracker itself writes for an event (a conversion's type, value, currency and id; a scroll's percent). custom_props is your own key/values, kept apart from it.
Does reporting consent stop the tracker from collecting?
No. consent_update records the choice a visitor made on your own cookie banner, as an observed signal. It gates nothing on the tracker's side; the legal basis for collection sits with you, the site that installs it.
Why does a conversion read "No value declared" on the screens?
The value was not accepted. The tracker keeps value only when it is a finite number of zero or more, keeps currency only beside an accepted value, and reads neither from custom_props. A value sent inside custom_props is shown as one of your properties, never as the conversion's value.
What does the id do?
It dedupes. The Conversions screen counts one conversion per id, first fire wins, so a reloaded thank-you page or a back-navigation does not count twice. A conversion sent without an id is counted once per fire.