Link Analytics
Measure every click on an ExaLink smart link. Pull summary KPIs plus dimensional breakdowns (countries, devices, referrers) and daily timeseries for dashboards and reporting.
Click totals
Total clicks, unique visitors, and conversion counts for any date window.
Country breakdown
ISO country codes and names ranked by click volume — ideal for regional campaigns.
Device mix
Mobile, desktop, tablet, and bot classification from the user-agent at click time.
Referrers
See whether traffic came from WhatsApp, SMS clients, search, social, or direct.
Authentication
Authorization: Basic <token>. Auth guide →~1s
click to API visibility
366d
per analytics request
4+
geo, device, ref, time
100/s
shared with other ExaLink calls
Returns aggregated analytics for a single link. Omit date filters to use the link's entire lifetime. All times are UTC.
Path & query parameters
| Field | Type | Required | Description |
|---|---|---|---|
| id | path string | required | Link id from create (e.g. link_01HZX…). Returns 404 if missing or not owned by the business. |
| from | query date | optional | Inclusive start date (YYYY-MM-DD or full ISO 8601). Defaults to link createdAt date. |
| to | query date | optional | Inclusive end date. Defaults to current UTC day. Must be ≥ from. |
| granularity | query string | optional | Timeseries bucket size: "day" (default), "hour", or "week". Hour requires a range ≤ 14 days. |
| timezone | query string | optional | IANA timezone for bucketing (e.g. "Africa/Accra"). Defaults to "UTC". |
| limit | query integer | optional | Max rows per dimension array (countries, devices, referrers). Default 25, max 100. |
Request examples
curl -G 'https://api.sendexa.co/v1/exalink/links/link_01HZXK9P2M7QVR8N4W3T6Y5B0A/analytics' \-H 'Authorization: Basic YOUR_DASHBOARD_BASE64_TOKEN' \-H 'Accept: application/json' \--data-urlencode 'from=2026-07-01' \--data-urlencode 'to=2026-07-12' \--data-urlencode 'granularity=day' \--data-urlencode 'timezone=Africa/Accra' \--data-urlencode 'limit=25'
Response shape
The payload always includes summary, countries, devices, referrers, and timeseries. Dimension arrays are sorted by clicks descending.
{"success": true,"code": "ANALYTICS_OK","message": "Analytics retrieved.","requestId": "REQ-1782202000001","timestamp": "2026-07-12T11:00:00.001Z","data": {"linkId": "link_01HZXK9P2M7QVR8N4W3T6Y5B0A","shortUrl": "https://go.example.com/summer26","title": "Summer Sale 2026","range": {"from": "2026-07-01T00:00:00.000Z","to": "2026-07-12T23:59:59.999Z","timezone": "Africa/Accra","granularity": "day"},"summary": {"clicks": 1420,"uniqueClicks": 980,"conversions": 86,"conversionRate": 0.0606,"avgClicksPerUnique": 1.45,"botClicks": 12,"passwordFailures": 3},"countries": [{"country": "GH","name": "Ghana","clicks": 1102,"uniqueClicks": 760,"share": 0.7761},{"country": "NG","name": "Nigeria","clicks": 188,"uniqueClicks": 140,"share": 0.1324},{"country": "US","name": "United States","clicks": 72,"uniqueClicks": 48,"share": 0.0507},{"country": "XX","name": "Unknown","clicks": 58,"uniqueClicks": 32,"share": 0.0408}],"devices": [{"device": "mobile","clicks": 1288,"uniqueClicks": 900,"share": 0.9070},{"device": "desktop","clicks": 98,"uniqueClicks": 62,"share": 0.0690},{"device": "tablet","clicks": 22,"uniqueClicks": 14,"share": 0.0155},{"device": "bot","clicks": 12,"uniqueClicks": 4,"share": 0.0085}],"referrers": [{"referrer": "direct","clicks": 810,"uniqueClicks": 560,"share": 0.5704},{"referrer": "whatsapp","clicks": 320,"uniqueClicks": 240,"share": 0.2254},{"referrer": "sms","clicks": 180,"uniqueClicks": 120,"share": 0.1268},{"referrer": "facebook","clicks": 70,"uniqueClicks": 40,"share": 0.0493},{"referrer": "other","clicks": 40,"uniqueClicks": 20,"share": 0.0282}],"timeseries": [{"date": "2026-07-01","clicks": 42,"uniqueClicks": 31,"conversions": 2},{"date": "2026-07-02","clicks": 88,"uniqueClicks": 60,"conversions": 5},{"date": "2026-07-11","clicks": 210,"uniqueClicks": 150,"conversions": 14},{"date": "2026-07-12","clicks": 156,"uniqueClicks": 112,"conversions": 9}]}}
conversions increments when your app reports a conversion tied to the link (or when a configured conversion pixel fires). The matching webhook event is exalink.converted. Webhooks →country: "XX" means unresolved (VPN, private range, or missing header). Shares sum approximately to 1.0 within rounding.from–to window.| Field | Definition |
|---|---|
| summary.clicks | Successful redirects (password passed if required). Bot traffic included unless filtered client-side via botClicks. |
| summary.uniqueClicks | Approx. distinct visitors in the range (see unique clicks note above). |
| summary.conversions | Attributed conversions in the range. |
| summary.conversionRate | conversions / clicks (0 if clicks is 0). |
| summary.botClicks | Subset of clicks classified as automated agents. |
| summary.passwordFailures | Failed password attempts on protected links (not counted as clicks). |
| devices[].device | mobile | desktop | tablet | bot | other |
| referrers[].referrer | Normalized source label: direct, whatsapp, sms, facebook, twitter, instagram, google, other, … |
| *.share | clicks for the row divided by summary.clicks. |
| HTTP | Code | Cause |
|---|---|---|
| 400 | INVALID_DATE_RANGE | from > to, or range longer than 366 days |
| 400 | INVALID_GRANULARITY | hour requested with range > 14 days |
| 401 | UNAUTHORIZED | Missing/invalid Basic Auth |
| 404 | LINK_NOT_FOUND | Unknown or deleted link id |
| 429 | RATE_LIMIT_EXCEEDED | Too many analytics polls — prefer webhooks |
{"success": false,"code": "INVALID_DATE_RANGE","message": "Parameter 'from' must be on or before 'to'. Maximum range is 366 days.","requestId": "REQ-1782202100123","timestamp": "2026-07-12T11:10:00.123Z"}
Dashboard cache
Poll analytics every 60–300s and cache results. Do not poll on every page view of your admin UI.
Real-time counters
Increment local counters from exalink.click webhooks; use this endpoint for reconciliation only.
Nightly reports
Query granularity=day for the previous UTC day and store rows in your warehouse.
Best practices
- Prefer webhooks for live counters; use analytics for charts and historical ranges
- Always pin
timezonewhen building day-based business reports for Ghana or Nigeria ops teams - Subtract or flag
botClickswhen reporting marketing ROI - Keep ranges as tight as possible — shorter windows respond faster
- Handle empty dimension arrays gracefully in UI (new links often have zero data)