Skip to main content

Analytics

Read scan analytics for a single link or aggregated across your whole account. Analytics endpoints require a valid API key but no specific scope — any active key can call them.

Bot traffic is excluded by default (see exclude_bots below).


Endpoints

Per-link (:id is the link's dynamic_link_id):

GET /links/:id/analytics/general
GET /links/:id/analytics/activity
GET /links/:id/analytics/ops
GET /links/:id/analytics/country
GET /links/:id/analytics/region
GET /links/:id/analytics/browser
GET /links/:id/analytics/time
POST /links/:id/analytics/export

Account-wide (all links on your account):

GET /analytics/general
GET /analytics/activity
GET /analytics/ops
GET /analytics/country
GET /analytics/region
GET /analytics/browser
GET /analytics/qr-code
GET /analytics/time
POST /analytics/export

ops groups scans by operating system, country by country, region by city, browser by browser, and qr-code (account-wide only) by link.

note

Requesting analytics for a link id that doesn't exist returns 200 with empty data, not 404.


Query parameters

All GET endpoints accept:

ParamTypeDefaultDescription
durationstring48_hoursOne of today, yesterday, 48_hours, 7_days, 30_days, 3_months, 1_year, custom.
date_fromdatestart of monthStart date (YYYY-MM-DD), used when duration is custom.
date_todatetodayEnd date (YYYY-MM-DD), used when duration is custom.
exclude_botsbooleantrueExclude scans identified as bot traffic.
limitnumber20Max rows for the grouped endpoints (ops, country, region, browser, qr-code). Capped at 1000.
curl "https://api.prolinksqr.com/links/summer-sale/analytics/country?duration=30_days&limit=10" \
-H "Authorization: Basic key-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Response shapes

general — totals

{ "data": { "numberOfLinks": 12, "numberOfScans": 3542 } }

(For the per-link endpoint, numberOfScans is scoped to that link.)

Grouped endpoints (ops, country, region, browser, qr-code)

An array ranked by scans; percentage is a string with two decimals:

{
"data": [
{
"number": 1,
"name": "United States",
"scans": 1893,
"percentage": "53.44"
},
{ "number": 2, "name": "Germany", "scans": 771, "percentage": "21.77" }
]
}

activity — scans over time

Series grouped three ways, ready for charting (x labels, y counts):

{
"data": {
"Year": { "x": [2026], "y": [3542] },
"Month": { "x": ["May", "Jun"], "y": [1200, 2342] },
"Day": { "x": ["2026-06-23", "2026-06-24"], "y": [130, 98] }
}
}

time — day/hour heatmap

Scan counts keyed by <Day>-<hour> (hour is 023):

{ "data": { "Mon-9": 42, "Mon-10": 61, "Tue-14": 18 } }

Export scan logs

POST /links/:id/analytics/export
POST /analytics/export

Exports the raw scan log as a CSV file (Content-Type: text/csv, sent as an attachment). Columns: link_id, browser_name, device_type, device_vendor, os_name, created_at, country_name, region, city.

The export is scoped the same way as the GET endpoints above: the account-wide route returns all of your account's links, and the per-link route returns only the specified link's scans.

Body

FieldTypeRequiredNotes
startDatedatenoOnly include scans on or after this date.
endDatedatenoOnly include scans on or before this date.
formatstringnoDefaults to csv (currently the only output format).
filtersobjectnoReserved for future use; currently has no effect on the export.

If you omit both startDate and endDate, the export defaults to the last 48 hours (same default as the GET endpoints above). If you provide either one, the other defaults to the start of the current month (startDate) or today (endDate).

curl -X POST https://api.prolinksqr.com/links/summer-sale/analytics/export \
-H "Authorization: Basic key-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "startDate": "2026-06-01", "endDate": "2026-06-30" }' \
-o export_summer-sale.csv