Events and taxonomy

The event envelope, money and identifier rules, the standard taxonomy, reserved names, custom schemas and validation.

Every Kentro Pixel event, from the browser or from your server, uses one JSON envelope and one event name from a shared taxonomy. Each name has a JSON Schema, a consent purpose and a list of sources that make it authoritative; this page covers all three and how to check events before you send them.

In this page

  • The envelope
  • Context
  • Money
  • Email and phone identifiers
  • How to read the taxonomy
  • Standard taxonomy
  • Which event should I send?
  • Reserved for Kentro
  • Custom events and the schema registry
  • Validating events without sending them

The envelope

The SDK fills in ids, context and consent for you; server integrations build the envelope themselves.

{
  "event_id": "evt_192f0c51a2b9f3c7d1e5a2b4c6d8e0f",
  "event_name": "commerce.added_to_cart",
  "schema_version": 1,
  "occurred_at": "2026-10-09T17:00:00.000Z",
  "anonymous_id": "anon_6f1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e",
  "session_id": "sess_0a1b2c3d4e5f60718293a4b5",
  "subject_ref": null,
  "commerce_subject_ref": null,
  "order_ref": null,
  "campaign_ref": "cmp_spring_launch",
  "creative_ref": null,
  "landing_page_ref": null,
  "experiment_ref": null,
  "experiment_variant_ref": null,
  "context": {
    "page_url": "https://www.example.com/products/mug?utm_source=google&utm_medium=cpc&gclid=abc123",
    "page_title": "Mug",
    "referrer_domain": "www.google.com",
    "device_class": "desktop",
    "locale": "en-US",
    "sdk": { "name": "kentro-pixel-js", "version": "1.3.0" }
  },
  "consent": { "analytics": "granted", "marketing": "denied", "functional": "granted", "policy_version": "2026-10", "source": "cmp", "recorded_at": "2026-10-09T16:59:00Z", "region": "US-CA", "gpc": false },
  "properties": { "product_id": "sku-123", "quantity": 1, "unit_price": { "amount_minor": 1999, "currency": "USD" } }
}
FieldType and limitsNotes
event_idstring, 1 to 128 charactersUnique per real-world event and stable across retries; deduplicated per property. When omitted, Kentro derives it from a hash of the envelope, so two identical envelopes count once.
event_namestring, 3 to 128 charactersnamespace.name in lower case: letters, then a dot, then letters, digits or underscores.
schema_versioninteger, 1 to 1000Defaults to 1.
occurred_atISO 8601 timestampDefaults to the time of receipt. Rejected with CLOCK_SKEW when more than 7 days in the past or 5 minutes in the future.
anonymous_id, session_idstring up to 128 characters, or nullBrowser identifiers; the SDK fills them.
subject_ref, commerce_subject_refstring up to 256 characters, or nullPseudonymous person references: your login id, your commerce customer id. Kept as sent on server events; on browser events set only through identity_token.
identity_tokenstring up to 1,024 charactersBrowser events: an identity token your server signed (see Identity tokens). Verified on arrival, never stored.
order_ref, campaign_ref, creative_ref, landing_page_ref, experiment_ref, experiment_variant_refstring up to 256 characters, or nullJoin keys for orders, Kentro GO campaigns, creatives, landing pages and experiments.
contextobjectPage and device context, see below.
consentobjectConsent snapshot. A missing purpose is unknown.
propertiesobjectEvent-specific data, validated against the event's schema.

An envelope may be at most 32 KB serialized. Unknown top-level fields are dropped. Kentro adds the workspace, property, source type, environment and receipt time itself.

Context

context accepts:

FieldNotes
page_url, page_titleKeeps only utm_* and click ids from the query string, loses its fragment and credentials, and has sensitive paths redacted.
referrer or referrer_domainReduced to a host name.
utmsource, medium, campaign, content, term, id.
click_idsgclid, gbraid, wbraid, fbclid, ttclid, msclkid. Raw values stay only with marketing consent; otherwise they are kept as SHA-256 hashes.
device_class, botDerived from the request's user agent for browser sources; settable by server sources.
locale, timezone, app_version, source_channel, sdkDescriptive context.
ga4_client_idYour site's GA4 client id (the _ga cookie value), used for GA4 deliveries.
client_user_agentServer sources: the visitor's browser user agent, for Meta Conversions API matching. Kept only on accepted events whose consent grants marketing.

Property values whose key ends in url, uri, href, link or path get the same URL treatment as page_url.

Money

Money is always an object with integer minor units and an upper-case ISO 4217 code:

{ "amount_minor": 4999, "currency": "USD" }

4999 is 49.99 USD; for zero-decimal currencies such as JPY, amount_minor is the whole amount. Floats, strings and extra keys are rejected with SCHEMA_VIOLATION.

Email and phone identifiers

  • Raw email and phone values at the top level of properties or under properties.customer are replaced on ingestion by email_sha256 and phone_sha256 (email trimmed and lower-cased, phone reduced to its digits, then SHA-256 as lower-case hex); the raw value is discarded.
  • The builtin schemas accept identifiers only inside customer, so send properties.customer.email (or a pre-hashed email_sha256), never a top-level email. If you hash yourself, use the same normalization.
  • The shared customer object accepts ref, email_sha256, phone_sha256, country (2 characters) and marketing_opt_in (boolean).
  • In custom events, a top-level property whose name ends like a contact field (customer_email, email_address, phone_number, mobile) is replaced by <name>_sha256. In every event, email addresses inside other strings become [email] and phone numbers inside free text become [phone].

How to read the taxonomy

Three separate things describe every event:

  • What happened: the namespace and the Category column. marketing.* events are website and acquisition behavior; commerce.* events are shopping and business records. The category ops marks Kentro GO operations, which Kentro GO records itself.
  • Which consent it needs: the Consent purpose column. The purpose is fixed per event and does not follow the namespace. Most marketing.* website events need analytics consent; lead, opt-in and acquisition events need marketing consent; browser shopping events need analytics consent; order, payment, refund, return, subscription, customer and fulfillment records are functional.
  • Whether it is a fact: the Authoritative from column. Orders, refunds and other revenue facts are authoritative only from a server source; a browser copy is accepted as a signal.
PurposeWhat the consent coversEvents
analyticsMeasuring how people use your site and store.Page views, sessions, site search, content views, CTA clicks, form starts and submissions, signups, experiment exposures and asset engagement; browser shopping events.
marketingLeads, opt-ins and acquisition.marketing.lead_captured, marketing.email_opt_in_recorded, marketing.ad_clicked, marketing.lead_qualified, marketing.demo_booked.
functionalBusiness records you must keep. Collected unless the snapshot explicitly says functional: "denied".Orders and payments, cancellations, refunds, returns, subscriptions, customer records, fulfillment and shipping costs.

The purpose decides whether Kentro collects an event, not whether it is exported. Ad networks receive a person only with an explicit marketing grant, even for a functional order (see Destinations).

Standard taxonomy

Every builtin event has an allowlist of properties (additionalProperties is false), so unlisted keys are rejected. Strings are at most 256 characters unless the full schema says otherwise; counts are non-negative integers (quantity and step start at 1); items is an array of up to 200 line items (product_id and quantity required; variant_id, sku, name, category, unit_price and total optional). Browser or server covers browser, server, Shopify pixel, Kentro OS and Kentro GO landing pages; Server only covers the server API, Kentro OS, CRM and imports. Events from any other source are accepted but flagged is_authoritative: false. The full JSON Schemas are available from GET /v1/event-schemas.

EventCategoryRequired propertiesOther allowed propertiesConsent purposeAuthoritative from
marketing.page_viewedmarketingnonepage_type, page_name, page_path, titleanalyticsBrowser or server
marketing.session_startedmarketingnoneentry_url, referrer_domain, landinganalyticsBrowser or server
marketing.product_viewed (deprecated: recorded as commerce.product_viewed)marketingproduct_idproduct_name, category, price (money)analyticsBrowser or server
marketing.search_performedmarketingqueryresults_count, categoryanalyticsBrowser or server
marketing.content_viewedmarketingnonecontent_id, content_type, content_nameanalyticsBrowser or server
marketing.cta_clickedmarketingcta_idcta_text, destination_url, locationanalyticsBrowser or server
marketing.form_startedmarketingform_idform_nameanalyticsBrowser or server
marketing.form_submittedmarketingform_idform_name, fields (field names only), success, customeranalyticsBrowser or server
marketing.lead_capturedmarketingnonelead_ref, form_id, source, customermarketingBrowser or server
marketing.signup_completedmarketingnonemethod, plan, customeranalyticsBrowser or server
marketing.email_opt_in_recordedmarketingnonelist_id, source, double_opt_in, customermarketingBrowser or server
marketing.experiment_exposedmarketingnonearmanalyticsBrowser or server
marketing.asset_engagedmarketingasset_refasset_type, action, secondsanalyticsBrowser or server
commerce.product_viewedcommerceproduct_idvariant_id, sku, name, category, brand, price (money), in_stockanalyticsBrowser or server
commerce.collection_viewedcommercecollection_idname, product_countanalyticsBrowser or server
commerce.added_to_cartcommerceproduct_id, quantityvariant_id, sku, name, unit_price (money), cart_idanalyticsBrowser or server
commerce.removed_from_cartcommerceproduct_id, quantityvariant_id, sku, name, cart_idanalyticsBrowser or server
commerce.checkout_startedcommercenonecart_id, checkout_id, total (money), item_countanalyticsBrowser or server
commerce.checkout_step_completedcommercestepcheckout_id, step_nameanalyticsBrowser or server
commerce.payment_attemptedcommercenonecheckout_id, payment_method, amount (money), successanalyticsBrowser or server
commerce.order_placedcommerceorder_id, total (money)subtotal, tax, shipping, discount (money), items, item_count, coupon_code, payment_method, customerfunctionalServer only
commerce.order_paidcommerceorder_id, total (money)payment_method, transaction_reffunctionalServer only
commerce.order_cancelledcommerceorder_idreasonfunctionalServer only
commerce.order_refundedcommerceorder_id, amount (money)reason, refund_reffunctionalServer only
commerce.order_partially_refundedcommerceorder_id, amount (money)items, reason, refund_reffunctionalServer only
commerce.return_createdcommerceorder_idreturn_ref, items, reasonfunctionalServer only
commerce.subscription_startedcommercesubscription_idplan, amount (money), intervalfunctionalServer only
commerce.subscription_renewedcommercesubscription_idamount (money), period_endfunctionalServer only
commerce.subscription_cancelledcommercesubscription_idreasonfunctionalServer only
commerce.customer_createdcommercecustomernonefunctionalServer only
commerce.customer_updatedcommercecustomernonefunctionalServer only
commerce.fulfillment_shippedcommerceorder_idfulfillment_ref, carrier, tracking_reffunctionalServer only
commerce.fulfillment_deliveredcommerceorder_idfulfillment_ref, delivered_atfunctionalServer only
commerce.shipping_cost_finalizedcommerceorder_id, shipping_cost (money)carrierfunctionalServer only
marketing.ad_clicked (optional)marketingproviderad_ref, click_id_typemarketingBrowser or server
marketing.lead_qualified (send from your server)marketinglead_refscore, stagemarketingServer only
marketing.demo_bookedmarketingnonelead_ref, scheduled_at, sourcemarketingBrowser or server
  • marketing.product_viewed is deprecated. Send commerce.product_viewed. The old name is still accepted, validated against its own schema, then recorded as commerce.product_viewed with product_name renamed to name. The per-event result carries "recorded_as": "commerce.product_viewed", and the event debugger shows "renamed_from": "marketing.product_viewed". Audience rules and destination mappings must use commerce.product_viewed.
  • marketing.lead_qualified: send it from your server when a lead is qualified in your CRM or sales process. A browser copy is accepted but not authoritative.
  • marketing.ad_clicked is optional: send it for an ad click you observed yourself, for example through a redirect service. Kentro already records ad clicks from the click ids on page views.

Which event should I send?

To recordSendConsent purposeConversion
A page viewNothing: the SDK sends marketing.page_viewed on every page load and route change, and marketing.session_started when a session begins. Call page only for extra page views.analyticsNo
A product viewcommerce.product_viewedanalyticsNo
An add to cartcommerce.added_to_cart, and commerce.removed_from_cart for removalsanalyticsNo
A checkoutcommerce.checkout_started, then commerce.checkout_step_completed for each stepanalyticsNo
A purchaseFrom your server: commerce.order_paid (and commerce.order_placed if you record orders before payment). From the browser: commerce.order_placed, accepted as a non-authoritative signal.functionalYes, once per order
A refund or cancellationFrom your server: commerce.order_refunded, commerce.order_partially_refunded or commerce.order_cancelledfunctionalCorrects the order's conversion
A lead formmarketing.lead_captured; add marketing.form_submitted to measure any form, lead or notmarketing (lead_captured), analytics (form_submitted)marketing.lead_captured only
A newsletter or list opt-inmarketing.email_opt_in_recordedmarketingNo
A signupmarketing.signup_completedanalyticsYes
A booked demomarketing.demo_bookedmarketingYes
A lead qualified in your CRMFrom your server: marketing.lead_qualifiedmarketingNo
A subscriptionFrom your server: commerce.subscription_started, commerce.subscription_renewed, commerce.subscription_cancelledfunctionalNo
  • One order counts once. Analytics keep one conversion per order reference: a server copy wins over a browser copy and commerce.order_paid over commerce.order_placed. Refunds and cancellations correct that conversion and never add a new one.
  • One form submission counts once. Kentro GO landing pages send marketing.form_submitted (field names only) and marketing.lead_captured (hashed email and phone) for each submission; only marketing.lead_captured is a conversion. Lead events of the same type with the same lead_ref also count once.
  • Conversion types. Conversion facts have one of seven types: lead_captured, signup_completed, demo_booked, order_placed and order_paid are conversions; order_refunded (full and partial refunds) and order_cancelled correct an order. These seven values are the only ones GET /v1/analytics/conversions?type= and audience conversion conditions accept. In Kentro GO, the Analytics page's Conversions view shows the totals by type.

Reserved for Kentro

Eighteen names describe facts Kentro computes itself, operations Kentro GO performs, or the history Kentro Email records. You cannot send them: every route (browser, batch, GIF beacon, server API and the validate endpoint) rejects them with RESERVED_EVENT, whatever the schema_version, with a reason that says what to use instead. GET /v1/event-schemas still lists them with reserved: true and that explanation in reserved_reason. Pixel audience rules and destination mappings that name them are refused.

EventWhy it is reservedUse instead
marketing.purchase_attributedComputed by Kentro attribution.GET /v1/analytics/attribution
marketing.conversion_confirmedDerived by Kentro from authoritative order and lead events.Send commerce.order_placed, commerce.order_paid or marketing.lead_captured from your server, and read GET /v1/analytics/conversions.
marketing.audience_joined, marketing.audience_exitedKentro records audience membership at each audience recompute.The audience endpoints (/v1/audiences) and webhook audience syncs.
marketing.campaign_impressionSynced by Kentro GO from the ad providers' insights.Campaign results in Kentro GO.
marketing.campaign_activated, marketing.campaign_pausedRecorded by Kentro GO when it activates or pauses a campaign (category ops).Nothing: they are never sent by a website or a server.
email.subscribed, email.unsubscribedThe Kentro Email consent history.Change a contact's subscription in Kentro Email.
email.sent, email.delivered, email.delivery_delayed, email.bounced, email.complained, email.rejected, email.rendering_failed, email.opened, email.clickedThe Kentro Email sending history.Read campaign and flow results in Kentro Email.

Kentro Email segments can use the email.* events; Pixel audiences cannot. A Kentro Email link click also records an email touchpoint for attribution (see Processing).

Custom events and the schema registry

Custom event schemas are not available in this preview: you cannot create them, and the collector accepts the builtin taxonomy above. When they become available, these rules apply:

  • A custom schema (an event name, a version, a category and a JSON Schema for properties) is validated exactly like a builtin. A builtin with the same name always wins, and a reserved name stays refused.
  • Its consent purpose is functional when its category is ops and analytics otherwise; a custom event never has the marketing purpose.
  • It is authoritative only when sent through the server API.
  • Registry changes reach the collector within 60 seconds.

The schema listing:

RequestAnswer
GET https://apis.kentro.live/pixel/v1/event-schemas (Kentro authentication){ "builtin": [...], "custom": [...] }: the builtin taxonomy and your workspace's custom schemas.
GET https://pixel.kentro.live/v1/event-schemas (public, cached for 5 minutes)The builtins only, with "custom": [].

Each builtin entry carries event_name, version, category, required, schema, authoritative_sources, consent_purpose, description, reserved, reserved_reason, replaced_by and builtin: true. replaced_by names the event a deprecated name is recorded as ("commerce.product_viewed" for marketing.product_viewed, null otherwise). Each custom entry carries event_name, version, category, schema, status, builtin: false, reserved: false, reserved_reason: null and replaced_by: null.

Validating events without sending them

POST /v1/event-schemas/validate runs the ingestion checks (envelope, clock skew, schema, identity tokens, sensitive-data detectors and the consent decision) on one envelope or { "events": [...] } (1 to 100), evaluated as browser events, and stores nothing.

  • Authenticate with a property key (X-Kentro-Pixel-Key header, key query parameter or key in the body) on the collector host, or with your Kentro credentials on the management host. With a property key the property's settings apply; with Kentro credentials the default settings do.
  • It does not check the origin allowlist, the per-key event rate limit or duplicates; requests count against the collector's per-IP limits.
  • In Kentro GO, the property's Validate tab runs the same check.
curl -sS https://pixel.kentro.live/v1/event-schemas/validate \
  -H "X-Kentro-Pixel-Key: pk_live_Xq3M9b2LkV7tR1sNw8YhC4Ze" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      { "event_id": "evt_1", "event_name": "commerce.added_to_cart", "consent": { "analytics": "granted" }, "properties": { "product_id": "sku-1", "quantity": 1, "unit_price": { "amount_minor": 1999, "currency": "USD" } } },
      { "event_id": "evt_2", "event_name": "commerce.added_to_cart", "consent": { "analytics": "granted" }, "properties": { "product_id": "sku-1", "quantity": 1, "unit_price": { "amount_minor": 19.99, "currency": "USD" } } },
      { "event_id": "evt_3", "event_name": "marketing.product_viewed", "consent": { "analytics": "granted" }, "properties": { "product_id": "sku-1", "product_name": "Mug" } },
      { "event_id": "evt_4", "event_name": "marketing.purchase_attributed", "properties": { "order_ref": "order-1001", "model": "last_touch" } }
    ]
  }'
{
  "results": [
    { "index": 0, "event_id": "evt_1", "event_name": "commerce.added_to_cart", "valid": true, "outcome": "accepted", "reason_code": null },
    { "index": 1, "event_id": "evt_2", "event_name": "commerce.added_to_cart", "valid": false, "reason_code": "SCHEMA_VIOLATION", "reason": "properties/unit_price/amount_minor must be integer" },
    { "index": 2, "event_id": "evt_3", "event_name": "marketing.product_viewed", "valid": true, "outcome": "accepted", "reason_code": null, "recorded_as": "commerce.product_viewed" },
    { "index": 3, "event_id": "evt_4", "event_name": "marketing.purchase_attributed", "valid": false, "reason_code": "RESERVED_EVENT", "reason": "marketing.purchase_attributed is computed by Kentro attribution; read it from the attribution endpoints (GET /v1/analytics/attribution) instead of sending it" }
  ]
}

outcome is accepted, quarantined or suppressed, exactly what ingestion would record. recorded_as is present when the event was sent under a deprecated name.