Ga naar inhoud

Scan-tracking & Analytics

Overzicht

Elke scan van een dynamischen QR-code genereert een scan-record in je workspace. De registratie vindt volledig plaats op de Cloudflare-edge — zonder externe trackingdiensten, zonder cookies en zonder dat het originele IP-adres ooit je database bereikt.

Drie manieren om scangegevens te consumeren:

Aggregatie-API

GET /v1/codes/:id/scans — tijdreeksen + top-landen/-apparaten/-OS voor een afzonderlijk code-object.

Webhooks (realtime)

qr.scanned-event per scan, HMAC-SHA256-gesigneerd. Zie Webhooks.

Dashboard

Visualisatie in het qr3.app-dashboard — geen API-call nodig.


Welke gegevens worden verzameld

Per scan wordt er een record in de tabel scans aangemaakt:

VeldBronVoorbeeld
idDoor server gegenereerde UUIDscn_d1f8…
code_idCode-ID van de gescande QR-codeqr_a1b2c3d4
workspace_idWorkspace van de codews_xxx
countryCloudflare cf.countryAT
regionCloudflare cf.regionVienna
cityCloudflare cf.cityWien
device_typeUser-Agent-parsingmobile, tablet, desktop
osUser-Agent-parsingiOS, Android, macOS, Windows
browserUser-Agent-parsingSafari, Chrome, Firefox
refererHTTP Referer-headerhttps://example.com/landing
languageAccept-Language-header (eerste taal)de
redirected_toWerkelijke redirect-bestemminghttps://example.com
ip_hashSHA-256(IP + dagelijkse salt) — niet omkeerbaar8f3a…
scanned_atISO-8601-timestamp2026-05-12T14:32:11.000Z

Geolocatie op de edge

Alle geogegevens (country, region, city) zijn afkomstig uit het cf-object van Cloudflare und zijn gebaseerd op de Cloudflare Geo-IP-database. Er worden geen externe Geo-IP-services aangeroepen — de herleiding vindt plaats in dezelfde worker die ook de redirect uitvoert.

Dit heeft drie gevolgen:

  1. Lage latentie — geen extra hop, geen DNS-lookup naar een externe provider.
  2. Privacy — het IP-adres verlaat Cloudflare niet en wordt nooit met derden gedeeld.
  3. Beperkte granulariteitcity is niet altijd beschikbaar (bijv. bij VPN’s, mobiele providers of kleine regio’s). Houd rekening met null-waarden in je dashboards.

Scan-analytics opvragen

GET /v1/codes/:id/scans

Levert geaggregeerde analytics voor een afzonderlijke QR-code over een selecteerbare periode.

Terminal window
curl "https://qr3.app/v1/codes/qr_a1b2c3d4/scans?days=30" \
-H "Authorization: Bearer qr3_sk_..."

Queryparameters:

ParameterTypeStandaardBeschrijving
daysinteger30Periode in dagen (1–365)

Response (HTTP 200):

{
"data": {
"code_id": "qr_a1b2c3d4",
"short_code": "r7f3Kx",
"total_scans": 1842,
"period_days": 30,
"period_scans": 367,
"scans_by_day": [
{ "date": "2026-04-13", "count": 12 },
{ "date": "2026-04-14", "count": 18 }
],
"top_countries": [
{ "value": "AT", "count": 142 },
{ "value": "DE", "count": 98 },
{ "value": "CH", "count": 41 }
],
"top_devices": [
{ "value": "mobile", "count": 281 },
{ "value": "desktop", "count": 72 },
{ "value": "tablet", "count": 14 }
],
"top_os": [
{ "value": "iOS", "count": 158 },
{ "value": "Android", "count": 123 },
{ "value": "macOS", "count": 48 }
]
},
"meta": { "request_id": "req_xyz123" }
}

Responsevelden:

VeldBeschrijving
total_scansTotaal aantal scans van de code over de gehele levensduur (onafhankelijk van het days-venster)
period_scansTotaal aantal scans in de geselecteerde periode
scans_by_dayDagelijkse buckets, oplopend op datum, lege dagen worden weggelaten
top_countriesTop 8 landen in de periode, aflopend
top_devicesTop 5 apparaattypen (mobile, tablet, desktop)
top_osTop 5 besturingssystemen

Aggregatie over meerdere codes

Workspace-brede totalen (bijv. scans per maand over alle codes) zijn beschikbaar via GET /v1/workspaces/:id in het veld scans_this_month. Voor analyses over meerdere codes raden we het dashboard of een periodieke export aan.


Realtime consumptie via webhooks

Als je scan-events wilt verwerken zodra ze plaatsvinden — bijvoorbeeld voor live dashboards, lead-tracking of CRM-integraties — abonneer je dan op het qr.scanned-event:

Terminal window
curl -X POST https://qr3.app/v1/webhooks \
-H "Authorization: Bearer qr3_sk_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhooks/qr3",
"events": ["qr.scanned"],
"secret": "my-secret-key-min-16-chars"
}'

Payload:

{
"id": "evt_abc123xyz",
"type": "qr.scanned",
"created": "2026-05-12T14:32:11.000Z",
"data": {
"code_id": "qr_a1b2c3d4",
"short_code": "r7f3Kx",
"scan_id": "scn_d1f8...",
"country": "AT",
"device_type": "mobile",
"os": "iOS"
}
}

Volledige documentatie over handtekeningverificatie, retry-logica en delivery-logs in API → Webhooks.


AVG & Privacy

Scan-records bevatten geen persoonsidentificerende IP-adressen. Het oorspronkelijke IP-adres wordt in de edge-worker door een cryptografische hashfunctie (SHA-256) met een dagelijks roterende salt vervangen. Dit betekent:

  • Geen heridentificatie, zelfs niet bij kennis van het algoritme
  • Geen correlatie over verschillende dagen van dezelfde bezoeker
  • Het originele IP-adres bereikt nooit de D1-database

Retentie is afhankelijk van het abonnement:

AbonnementBewaartermijn
Free7 dagen
Pro90 dagen
Business / Agency1 jaar
EnterpriseCustom (SLA)

Een dagelijks uitgevoerde cronjob (purgeOldScans) verwijdert oudere records automatisch — total_scans op het code-object blijft hierdoor ongewijzigd.


Best practices

  • Polling-frequentie: De aggregatie-API is efficiënt, maar niet bedoeld voor updates per seconde. Geef voor live updates altijd de voorkeur aan webhooks en gebruik de API alleen voor backfills / dashboards.
  • Caching: De response bevat tijdreeksen — bij grote periodes (days=365) kan de payload meerdere KB groot worden. Cache aan de clientzijde met een korte TTL (bijv. 60 s).
  • Top-N-limieten: top_countries, top_devices en top_os zijn aan de serverzijde beperkt tot respectievelijk 8 of 5 vermeldingen. Exporteer de ruwe gegevens voor diepgaandere analyses.
  • null-waarden tolereren: country, region, city, referer en language kunnen null zijn. Behandel dit in je analyse als “Onbekend”.