Aggregerings-API
GET /v1/codes/:id/scans — tidsserier + top-lande/-enheder/-OS for et enkelt kodeobjekt.
Hvert scan af en dynamisk QR-kode opretter en scan-record i dit workspace. Indsamlingen sker fuldstændigt på Cloudflare-edge — uden eksterne trackingtjenester, uden cookies, og uden at den originale IP-adresse nogensinde når din database.
Tre måder at forbruge scandata på:
Aggregerings-API
GET /v1/codes/:id/scans — tidsserier + top-lande/-enheder/-OS for et enkelt kodeobjekt.
Webhooks (realtid)
qr.scanned-event pr. scan, HMAC-SHA256-signeret. Se Webhooks.
Dashboard
Visualisering i qr3.app-dashboardet — intet API-kald nødvendigt.
For hvert scan oprettes der en record i tabellen scans:
| Felt | Kilde | Eksempel |
|---|---|---|
id | Servergenereret UUID | scn_d1f8… |
code_id | Kode-ID for den scannede QR-kode | qr_a1b2c3d4 |
workspace_id | Kodens workspace | ws_xxx |
country | Cloudflare cf.country | AT |
region | Cloudflare cf.region | Vienna |
city | Cloudflare cf.city | Wien |
device_type | User-Agent-parsing | mobile, tablet, desktop |
os | User-Agent-parsing | iOS, Android, macOS, Windows |
browser | User-Agent-parsing | Safari, Chrome, Firefox |
referer | HTTP Referer-header | https://example.com/landing |
language | Accept-Language-header (første sprog) | de |
redirected_to | Faktisk redirect-destination | https://example.com |
ip_hash | SHA-256(IP + daglig salt) — ikke-reversibel | 8f3a… |
scanned_at | ISO-8601-tidsstempel | 2026-05-12T14:32:11.000Z |
Alle geodata (country, region, city) stammer fra Cloudflares cf-objekt og er baseret på Cloudflares Geo-IP-database. Der anmodes ikke om eksterne Geo-IP-tjenester — opløsningen sker i den samme worker, som også udfører redirectet.
Dette har tre konsekvenser:
city er ikke altid tilgængelig (f.eks. ved VPN’er, mobiludbydere eller små regioner). Forvent null-værdier og tag højde for dem i dine dashboards.GET /v1/codes/:id/scansLeverer aggregeret analytics for en enkelt QR-kode over en valgt tidsperiode.
curl "https://qr3.app/v1/codes/qr_a1b2c3d4/scans?days=30" \ -H "Authorization: Bearer qr3_sk_..."const analytics = await qr3.scans.get('qr_a1b2c3d4', { days: 30 });console.log(analytics.period_scans, analytics.top_countries);qr3 scans qr_a1b2c3d4 --days 30Query-parametre:
| Parameter | Type | Standard | Beskrivelse |
|---|---|---|---|
days | integer | 30 | Tidsperiode i dage (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" }}Svarfelter:
| Felt | Beskrivelse |
|---|---|
total_scans | Samlet antal scan i kodens levetid (uafhængigt af days-vinduet) |
period_scans | Summen af scan i det valgte tidsvindue |
scans_by_day | Daglige buckets, stigende efter dato, tomme dage udelades |
top_countries | Top 8 lande i tidsvinduet, faldende |
top_devices | Top 5 enhedstyper (mobile, tablet, desktop) |
top_os | Top 5 operativsystemer |
Workspace-dækkende summe (f.eks. scan pr. måned på tværs af alle koder) er tilgængelige via GET /v1/workspaces/:id i feltet scans_this_month. Til analyser på tværs af koder anbefaler vi dashboardet eller en periodisk eksport.
Hvis du vil behandle scan-events, så snart de sker — f.eks. til live-dashboards, lead-tracking oder CRM-integrationer — skal du abonnere på qr.scanned-eventet:
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" }}Komplet dokumentation om signaturverifikation, retry-logik og leveringslogge findes i API → Webhooks.
Scan-records indeholder ingen personhenførbare IP-adresser. Den oprindelige IP-adresse erstattes i edge-workeren af en kryptografisk hashfunktion (SHA-256) med en dagligt roterende salt. Det betyder:
Opbevaringstid afhænger af din plan:
| Plan | Opbevaringstid |
|---|---|
| Free | 7 dage |
| Pro | 90 dage |
| Business / Agency | 1 år |
| Enterprise | Custom (SLA) |
Et dagligt cronjob (purgeOldScans) fjerner automatisk ældre records — total_scans på kodeobjektet forbliver upåvirket af dette.
days=365) kan payloaden blive flere KB stor. Cache på klientsiden med en kort TTL (f.eks. 60 s).top_countries, top_devices og top_os er begrænset på serversiden til henholdsvis 8 og 5 poster. Eksporter rådataene for mere dybdegående analyser.null-værdier: country, region, city, referer og language kan være null. Håndter dette som “Ukendt” i din analyse.