Aggregations-API
GET /v1/codes/:id/scans — Zeitreihen + Top-Länder/-Geräte/-OS für ein einzelnes Code-Objekt.
Każde skanowanie dynamicznego kodu QR generuje rekord skanowania (Scan-Record) w Twoim Workspace. Rejestracja odbywa się w całości na Cloudflare-Edge — bez zewnętrznych usług śledzących, bez plików cookie i bez sytuacji, w której oryginalny adres IP kiedykolwiek trafia do Twojej bazy danych.
Trzy sposoby na konsumowanie danych skanowania:
Aggregations-API
GET /v1/codes/:id/scans — Zeitreihen + Top-Länder/-Geräte/-OS für ein einzelnes Code-Objekt.
Webhooks (Echtzeit)
qr.scanned-Event pro Scan, HMAC-SHA256-signiert. Siehe Webhooks.
Dashboard
Visualisierung im qr3.app-Dashboard — kein API-Call nötig.
Dla każdego skanowania tworzony jest rekord w tabeli scans:
| Pole | Źródło | Przykład |
|---|---|---|
id | UUID wygenerowane przez serwer | scn_d1f8… |
code_id | ID skanowanego kodu QR | qr_a1b2c3d4 |
workspace_id | Workspace kodu | ws_xxx |
country | Cloudflare cf.country | AT |
region | Cloudflare cf.region | Vienna |
city | Cloudflare cf.city | Wien |
device_type | Parsowanie User-Agent | mobile, tablet, desktop |
os | Parsowanie User-Agent | iOS, Android, macOS, Windows |
browser | Parsowanie User-Agent | Safari, Chrome, Firefox |
referer | Nagłówek HTTP Referer | https://example.com/landing |
language | Nagłówek Accept-Language (pierwszy język) | de |
redirected_to | Rzeczywisty cel przekierowania | https://example.com |
ip_hash | SHA-256(IP + codzienny salt) — nieodwracalny | 8f3a… |
scanned_at | Znacznik czasu ISO-8601 | 2026-05-12T14:32:11.000Z |
Wszystkie dane geograficzne (country, region, city) pochodzą z obiektu cf od Cloudflare i bazują na bazie danych Geo-IP Cloudflare. Nie są odpytywane żadne zewnętrzne usługi Geo-IP — rozpoznawanie odbywa się w tym samym Workerze, który wykonuje przekierowanie.
Ma to trzy konsekwencje:
city nie zawsze jest dostępne (np. w przypadku sieci VPN, operatorów komórkowych lub małych regionów). Należy spodziewać się wartości null i uwzględnić je w swoich dashboardach.GET /v1/codes/:id/scansZwraca zagregowane dane analityczne dla pojedynczego kodu QR w wybranym okresie.
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 30Parametry zapytania (Query-Parameter):
| Parametr | Typ | Domyślnie | Opis |
|---|---|---|---|
days | integer | 30 | Okres w dniach (1–365) |
Odpowiedź (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" }}Pola odpowiedzi:
| Pole | Opis |
|---|---|
total_scans | Całkowita liczba skanowań kodu od początku jego istnienia (niezależnie od okna days) |
period_scans | Suma skanowań w wybranym oknie czasowym |
scans_by_day | Dzienne grupy (buckets), rosnąco według daty, puste dni są pomijane |
top_countries | Top 8 krajów w oknie czasowym, malejąco |
top_devices | Top 5 typów urządzeń (mobile, tablet, desktop) |
top_os | Top 5 systemów operacyjnych |
Sumy dla całego Workspace (np. skanowania na miesiąc dla wszystkich kodów) są dostępne przez GET /v1/workspaces/:id w polu scans_this_month. Do analiz między wieloma kodami zalecamy Dashboard lub okresowy eksport.
Jeśli chcesz przetwarzać zdarzenia skanowania natychmiast, gdy się pojawią — na przykład na potrzeby dashboardów na żywo, śledzenia leadów lub integracji z CRM — zasubskrybuj zdarzenie qr.scanned:
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 (ładunek danych):
{ "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" }}Pełna dokumentacja dotycząca weryfikacji sygnatur, logiki ponownych prób (retry) i logów dostarczeń znajduje się w sekcji API → Webhooks.
Rekordy skanowania nie zawierają osobowych adresów IP. Oryginalny adres IP jest zastępowany w Edge-Workerze przez kryptograficzną funkcję skrótu (SHA-256) z codziennie rotowanym soleniem (salt). Oznacza to:
Okres przechowywania danych (retencja) zależy od planu:
| Plan | Przechowywanie |
|---|---|
| Free | 7 dni |
| Pro | 90 dni |
| Business / Agency | 1 rok |
| Enterprise | Niestandardowy (SLA) |
Codziennie uruchamiane zadanie cron (purgeOldScans) automatycznie usuwa starsze rekordy — pole total_scans w obiekcie kodu pozostaje nienaruszone.
days=365) ładunek danych (payload) może mieć rozmiar kilku KB. Buforuj dane po stronie klienta z krótkim czasem życia (TTL, np. 60 s).top_countries, top_devices, top_os są ograniczone po stronie serwera odpowiednio do 8 lub 5 wpisów. Do głębszych analiz wyeksportuj surowe dane.null: country, region, city, referer, language mogą mieć wartość null. W swoich analizach traktuj je jako „Nieznane”.