Skip to content

Analytics Interpretation

The xQR analytics API gives you rich data about how your links and QR codes are performing. This guide helps you interpret that data and act on it.

Analytics Overview

xQR collects analytics every time a short link or QR code is scanned. Data includes:

  • Timestamp — When the scan happened
  • Country — Derived from the visitor’s IP via GeoIP
  • Device type — Mobile, tablet, or desktop
  • Browser — Chrome, Safari, Firefox, etc.
  • OS — iOS, Android, Windows, macOS, etc.
  • Referrer — Where the visitor came from (if available)

Key Metrics

Summary Endpoint

GET /v1/analytics/summary?period=30d

Returns workspace-wide KPIs:

{
"data": {
"total_scans": 15420,
"unique_visitors": 12893,
"scans_change_pct": 12.5,
"top_countries": [
{ "country": "US", "country_code": "US", "scans": 5200 },
{ "country": "Germany", "country_code": "DE", "scans": 2100 }
],
"top_devices": [
{ "device": "mobile", "scans": 9800, "percentage": 63.5 },
{ "device": "desktop", "scans": 4800, "percentage": 31.1 }
]
}
}

Key insights:

  • scans_change_pct — Percentage change vs the previous period. Positive = growth
  • unique_visitors vs total_scans — The ratio tells you about repeat scanning behavior. A high ratio of total to unique suggests engaged users scanning multiple times
  • top_countries — Identify your strongest markets for geo-targeted campaigns

Timeseries Endpoint

GET /v1/analytics/timeseries?period=30d&granularity=day

Returns scan counts over time:

{
"data": [
{ "timestamp": "2026-03-01T00:00:00Z", "scans": 489 },
{ "timestamp": "2026-03-02T00:00:00Z", "scans": 512 },
{ "timestamp": "2026-03-03T00:00:00Z", "scans": 623 }
]
}

How to read this:

  • Look for trends — Is traffic growing, flat, or declining?
  • Identify spikes — Correlate with marketing campaigns or social media mentions
  • Spot patterns — Day-of-week patterns reveal when your audience is most active
  • Use hourly granularity for recent data to find peak hours

Geography Endpoint

GET /v1/analytics/geography?period=30d

{
"data": [
{ "country": "United States", "country_code": "US", "scans": 5200, "percentage": 33.7 },
{ "country": "Germany", "country_code": "DE", "scans": 2100, "percentage": 13.6 },
{ "country": "United Kingdom", "country_code": "GB", "scans": 1800, "percentage": 11.7 }
]
}

How to act on this:

  • Set up geo-routing — If significant traffic comes from specific countries, create routing rules to redirect to localized pages
  • Time your campaigns — Publish during peak hours for your top countries
  • Identify new markets — Unexpected traffic from a country might indicate an opportunity

Devices Endpoint

GET /v1/analytics/devices?period=30d

{
"data": {
"devices": [
{ "device": "mobile", "scans": 9800, "percentage": 63.5 },
{ "device": "desktop", "scans": 4800, "percentage": 31.1 },
{ "device": "tablet", "scans": 820, "percentage": 5.3 }
],
"browsers": [
{ "browser": "Chrome", "scans": 7200 },
{ "browser": "Safari", "scans": 5100 }
],
"os": [
{ "os": "iOS", "scans": 6200 },
{ "os": "Android", "scans": 4800 }
]
}
}

How to act on this:

  • Mobile-first — If most scans are mobile (common for QR codes), ensure your destination pages are mobile-optimized
  • Device routing — Use smart routing to send mobile users to app download pages
  • Browser testing — Prioritize testing on your most popular browsers

GET /v1/analytics/top-links?period=30d&limit=10

Use this to identify your highest and lowest performing links.

What to look for:

  • High scan count + low engagement — Destination page may not be relevant
  • Low scan count on promoted links — QR code may be poorly placed or too small to scan
  • Sudden drops — Check if the destination URL is still working

GET /v1/analytics/links/{link_id}?period=30d

Deep-dive into a specific link’s performance:

{
"data": {
"link_id": "d47f2e1a-...",
"short_code": "summer24",
"total_scans": 2341,
"unique_visitors": 1987,
"timeseries": [ ... ],
"geography": [ ... ],
"devices": { ... }
}
}

Common Analysis Patterns

Campaign Comparison

Compare two campaigns by pulling their link stats:

const campaigns = ["campaign-a-link-id", "campaign-b-link-id"];
const results = await Promise.all(
campaigns.map(async (id) => {
const res = await fetch(
`https://xqr.co/api/v1/analytics/links/${id}?period=30d`,
{ headers: { Authorization: `Bearer ${apiKey}` } }
);
return res.json();
})
);
results.forEach(({ data }) => {
console.log(`${data.short_code}: ${data.total_scans} scans`);
});

Monitoring with Webhooks

Set up a link.threshold webhook to get notified when links hit scan milestones:

{
"url": "https://your-app.com/webhooks/xqr",
"events": ["link.threshold", "link.scanned"]
}

This is useful for:

  • Celebrating milestones — Notify your team when a campaign hits 1,000 scans
  • Alerting on anomalies — Detect unusual traffic spikes that could indicate abuse

Export to BI Tools

Pull timeseries data and export to your BI stack:

Terminal window
# Export 90 days of daily scan data as JSON
curl "https://xqr.co/api/v1/analytics/timeseries?period=90d&granularity=day" \
-H "Authorization: Bearer $XQR_API_KEY" \
| jq '.data' > scans_90d.json

Best Practices

  1. Check analytics regularly — Set up a weekly review cadence
  2. Use labels — Label your links by campaign, channel, or team for easier filtering
  3. Compare periods — Use 7d vs 30d to spot trends
  4. Act on geography — Set up routing rules for your top traffic sources
  5. Monitor outliers — Both unusually high and low scan counts deserve investigation
  6. Combine with UTM — Add UTM parameters to destination URLs for end-to-end tracking in Google Analytics

Was this page helpful?