Skip to main content
Every event you send to Scanova Conversion Tracking — whether from the browser or your server — follows a common structure. This page documents every field you can include and explains what the tracking pipeline does with it.

Browser events (POST /ct)

Browser events are sent automatically by the SDK or manually via scanova('track', ...). They represent actions that happen in the user’s browser.

Fields you can send

FieldTypeRequiredDescription
event_idUUID stringNoUnique identifier for this event. Auto-generated by the SDK if omitted. Send a stable ID from your code if you want safe retries.
site_idstringYesYour tracking site ID from the dashboard.
event_typestringYesThe type of event. Use snake_case (e.g. page_view, cta_click, signup_completed).
scan_session_idUUID stringNoSet automatically by the SDK from the scnv URL parameter. Required for QR attribution.
web_session_idUUID stringNoSet automatically by the SDK per browser session (30-minute timeout).
visitor_idUUID stringNoSet automatically by the SDK. Persists for 1 year via cookie.
page_urlstringNoFull URL of the current page including query string.
page_titlestringNoPage title. Not sent by the Browser SDK; only useful for custom direct API integrations.
referrerstringNoThe referring URL.
event_timeISO 8601 stringNoEvent time in UTC. Defaults to server receive time if omitted. Note: the Browser SDK sends a timestamp key which is a separate, internal field — when calling the API directly, use event_time.
deviceobjectNoBrowser/device context — see below.
metadataobjectNoCustom key-value data. Max 10 KB, max depth 5. No raw email addresses.
device object fields:
FieldDescription
user_agentBrowser user-agent string
screen_widthScreen width in pixels
screen_heightScreen height in pixels
languageBrowser language (e.g. en-US)

Example browser event payload

{
  "event_id": "f9ac7db6-f900-4d8e-8918-c846834195a8",
  "site_id": "N74rwgykxCwUe7SDFb2BMVN8Kc0aCQvKajiUKz9MSk3Bldn70jw8uLE3dUTgeS6r",
  "event_type": "cta_click",
  "scan_session_id": "7ad26d4f-3181-4ef8-b6ca-b8f59499dd43",
  "page_url": "https://yoursite.com/?scnv=7ad26d4f-3181-4ef8-b6ca-b8f59499dd43",
  "referrer": "",
  "timestamp": "2026-05-13T10:00:00.000Z",
  "device": {
    "user_agent": "Mozilla/5.0 ...",
    "screen_width": 1680,
    "screen_height": 1050,
    "language": "en-US"
  },
  "metadata": {
    "button_text": "Start Free Trial",
    "section": "pricing"
  }
}

Server events (POST /server-events)

Server events are sent from your backend using an API key. They represent actions that happen on your server, such as completed purchases, confirmed sign-ups, or leads created in your CRM.

Fields you can send

FieldTypeRequiredDescription
event_idUUID stringRecommendedUnique event ID for safe retries. Generate once, persist, reuse on retry.
site_idstringYesYour tracking site ID. Must match the API key’s authorized site.
event_namestringYesSemantic event name (e.g. purchase, signup, lead).
scan_session_idUUID stringYesLinks this server event to the originating QR scan. Pass from browser to your server.
web_session_idUUID stringNoThe browser’s web session ID — pass from the browser if available, for richer session linking.
visitor_idUUID stringNoThe browser’s persistent visitor ID — pass from the browser if available.
event_timeISO 8601 stringNoWhen the event occurred. Defaults to time of receipt.
conversion_valueobjectNo{ "amount": 99.99, "currency": "USD" }. Currency must be a 3-letter ISO 4217 code.
user_identifiersobjectNoHashed user identifiers — see below. Never send raw email or phone.
propertiesobjectNoCustom key-value metadata. Max 10 KB. No raw emails.
consentstringNogranted, denied, or pending.
user_identifiers object fields (all hashed):
FieldDescription
email_hashSHA-256 hash of the user’s lowercase email address
phone_hashSHA-256 hash of the user’s E.164-format phone number
external_idYour internal user/customer ID

Example server event payload

{
  "event_id": "550e8400-e29b-41d4-a716-446655440000",
  "site_id": "N74rwgykxCwUe7SDFb2BMVN8Kc0aCQvKajiUKz9MSk3Bldn70jw8uLE3dUTgeS6r",
  "event_name": "purchase",
  "scan_session_id": "7ad26d4f-3181-4ef8-b6ca-b8f59499dd43",
  "conversion_value": { "amount": 49.99, "currency": "USD" },
  "user_identifiers": {
    "email_hash": "b94d27b9934d3e08a52e52d7da7dabfac484efe04294e576fc583c381f2d9c5d",
    "external_id": "usr_1234"
  },
  "properties": {
    "order_id": "ord_9876",
    "plan": "pro"
  }
}

Event naming conventions

Use consistent, descriptive names in snake_case. A clear naming scheme makes reports easier to read.
GoodAvoid
page_viewpageView, PageView, pv
cta_clickclick1, btnClick
signup_completedsignup, reg
purchasebuy, order_placed_final

Idempotency

Both browser and server events support an event_id field for deduplication:
  • If the same event_id arrives more than once, the duplicate is stored but marked is_duplicate = 1
  • Duplicates are excluded from analytics views automatically
  • Always reuse the same event_id when retrying a failed server event

Privacy and GDPR

  • Never send raw email addresses in metadata or properties. Use user_identifiers with hashed values.
  • The consent field controls PII handling in the pipeline:
    • granted — all fields are stored normally
    • denied or pendingpage_url, referrer, city, and metadata are stripped before storage
    • The consent value itself is always stored as an audit trail
The Browser SDK does not have a built-in consent API. The recommended approach is to conditionally load the SDK based on your consent management platform’s decision:
<script>
  // Only load the SDK after the user grants consent
  if (userHasGrantedConsent()) {
    (function(w,d,s,o,f,js,fjs){
      w['ScanovaTrackingObject']=o;w[o]=w[o]||function(){(w[o].q=w[o].q||[]).push(arguments)};
      js=d.createElement(s),fjs=d.getElementsByTagName(s)[0];
      js.id=o;js.src=f;js.async=1;fjs.parentNode.insertBefore(js,fjs);
    })(window,document,'script','scanova','https://cdn.scanova.io/ct/js/qcg.min.js');
    scanova('init', 'YOUR_SITE_ID', { autoPageview: true });
  }
</script>
For server events, pass the consent value directly in every request payload alongside your other fields.