Saltearse al contenido

Seguimiento de escaneos y analíticas

Resumen

Cada escaneo de un código QR dinámico genera un registro de escaneo (Scan-Record) en tu espacio de trabajo. La recopilación se realiza por completo en el Edge de Cloudflare, sin servicios de seguimiento externos, sin cookies y sin que la IP original llegue nunca a tu base de datos.

Tres formas de consumir los datos de escaneo:

API de agregación

GET /v1/codes/:id/scans — Series temporales + principales países/dispositivos/sistemas operativos para un único objeto de código.

Webhooks (tiempo real)

Evento qr.scanned por escaneo, firmado con HMAC-SHA256. Consulta Webhooks.

Panel de control

Visualización en el panel de control de qr3.app, sin necesidad de llamadas a la API.


Qué datos se recopilan

Por cada escaneo se crea un registro en la tabla scans:

CampoOrigenEjemplo
idUUID generado por el servidorscn_d1f8…
code_idID del código QR escaneadoqr_a1b2c3d4
workspace_idEspacio de trabajo del códigows_xxx
countrycf.country de CloudflareAT
regioncf.region de CloudflareVienna
citycf.city de CloudflareWien
device_typeAnálisis del User-Agentmobile, tablet, desktop
osAnálisis del User-AgentiOS, Android, macOS, Windows
browserAnálisis del User-AgentSafari, Chrome, Firefox
refererCabecera HTTP Refererhttps://example.com/landing
languageCabecera Accept-Language (primer idioma)de
redirected_toDestino real de la redirecciónhttps://example.com
ip_hashSHA-256(IP + sal diaria) — no reversible8f3a…
scanned_atMarca de tiempo ISO-86012026-05-12T14:32:11.000Z

Geolocalización en el Edge

Todos los datos geográficos (country, region, city) provienen del objeto cf de Cloudflare y se basan en la base de datos Geo-IP de Cloudflare. No se realizan consultas a servicios externos de Geo-IP; la resolución se realiza en el mismo Worker que ejecuta la redirección.

Esto tiene tres consecuencias:

  1. Baja latencia: sin saltos adicionales ni búsquedas DNS a un proveedor externo.
  2. Privacidad: la dirección IP no sale de Cloudflare y nunca se comparte con terceros.
  3. Granularidad limitada: la ciudad (city) no siempre está disponible (por ejemplo, con VPNs, operadores de telefonía móvil o regiones pequeñas). Cuenta con valores null y considéralos en tus paneles de control.

Consultar analíticas de escaneo

GET /v1/codes/:id/scans

Devuelve analíticas agregadas para un único código QR durante un período de tiempo seleccionable.

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

Parámetros de consulta (Query Parameters):

ParámetroTipoPor defectoDescripción
daysinteger30Período en días (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" }
}

Campos de respuesta:

CampoDescripción
total_scansTotal acumulado de escaneos del código (independientemente del intervalo de días days)
period_scansSuma de escaneos en el intervalo de tiempo seleccionado
scans_by_dayAgrupaciones diarias, en orden ascendente por fecha; se omiten los días sin actividad
top_countriesLos 8 principales países en el intervalo de tiempo, en orden descendente
top_devicesLos 5 principales tipos de dispositivos (mobile, tablet, desktop)
top_osLos 5 principales sistemas operativos

Agregación de múltiples códigos

Los totales a nivel de espacio de trabajo (por ejemplo, escaneos al mes de todos los códigos) están disponibles a través de GET /v1/workspaces/:id en el campo scans_this_month. Para análisis cruzados entre códigos, recomendamos utilizar el panel de control o realizar una exportación periódica.


Consumo en tiempo real a través de webhooks

Si deseas procesar los eventos de escaneo en el momento en que ocurren (por ejemplo, para paneles de control en vivo, seguimiento de clientes potenciales o integraciones con CRM), suscríbete al evento qr.scanned:

Ventana de terminal
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"
}
}

Documentación completa sobre verificación de firmas, lógica de reintentos e historial de entregas en API → Webhooks.


RGPD y privacidad de datos

Los registros de escaneo no contienen direcciones IP de carácter personal. La IP original se reemplaza en el Edge Worker mediante una función de hash criptográfica (SHA-256) con una sal (salt) que rota diariamente. Esto significa:

  • No es posible la reidentificación, incluso si se conoce el algoritmo
  • No hay correlación entre diferentes días para un mismo visitante
  • La IP original nunca llega a la base de datos D1

La retención depende del plan:

PlanRetención
Free7 días
Pro90 días
Business / Agency1 año
EnterprisePersonalizado (SLA)

Una tarea programada (cron job) diaria (purgeOldScans) elimina automáticamente los registros más antiguos; el valor total_scans del objeto de código no se ve afectado por esto.


Buenas prácticas

  • Frecuencia de sondeo (polling): La API de agregación es eficiente, pero no está diseñada para consultas cada segundo. Para actualizaciones en vivo, prioriza siempre el uso de webhooks y reserva la API para cargas históricas (backfills) o paneles de control.
  • Caché: La respuesta contiene series temporales; con intervalos grandes (days=365), la carga útil puede llegar a pesar varios KB. Almacena en caché en el lado del cliente con un TTL corto (por ejemplo, 60 s).
  • Límites Top-N: top_countries, top_devices y top_os están limitados en el servidor a 8 o 5 entradas respectivamente. Para análisis más profundos, exporta los datos en bruto.
  • Tolerar valores null: country, region, city, referer y language pueden ser null. Trata estos casos como “Desconocido” en tus análisis.