Link Statistics
Get click statistics for a single URL you own.
The same aggregated analytics as GET /stats, pre-scoped to one link —
the response additionally echoes the link’s url_id and alias.
Custom-domain links are safe here: clicks are matched by URL id, so a
same-alias link on another domain can never bleed in.
Authentication: Required — you must own the URL.
API Key Scope: stats:read, urls:read, or admin:all
Rate Limits: 60/min, 5,000/day
Grouping Dimensions: time, browser, os, device, country,
city, referrer, utm_source, utm_medium, utm_campaign
Metrics: clicks, unique_clicks
Filtering: Filter by browser, os, device, country, city,
referrer, or the utm_* tags using query params or a JSON filters
object. Link-identity filters (short_code, url_id) do not exist
here — the path already selects the link.
Errors:
400— malformed id (not a valid ObjectId)404— no URL with that id in your account. A URL owned by someone else answers identically; this endpoint never confirms foreign ids.
Authorizations
API key authentication. Pass your key as: Bearer spoo_<your_key>
Path Parameters
Unique identifier of the URL (MongoDB ObjectId).
Query Parameters
Start of time range. Accepts ISO 8601 datetime string (e.g., 2025-01-01T00:00:00Z) or Unix timestamp in seconds (e.g., 1735689600). If omitted, defaults to 7 days before end_date.
50"2025-01-01T00:00:00Z"
End of time range. Accepts ISO 8601 datetime string (e.g., 2025-12-31T23:59:59Z) or Unix timestamp in seconds (e.g., 1767225599). If omitted, defaults to now.
50"2025-12-31T23:59:59Z"
Comma-separated grouping dimensions for the statistics breakdown. Defaults to time if omitted.
Available dimensions:
time— group by time buckets (day/week/month, auto-selected based on range)browser— group by browser name (e.g., Chrome, Firefox, Safari)os— group by operating system (e.g., Windows, macOS, Linux)device— group by device type (mobile,tablet,desktop,unknown)country— group by countrycity— group by cityreferrer— group by referrer URLutm_source— group by theutm_sourcetag on the short link (untagged clicks appear as(none))utm_medium— group by theutm_mediumtagutm_campaign— group by theutm_campaigntag
Multiple dimensions can be combined: time,browser returns time series broken down by browser.
200"time,browser"
Comma-separated metrics to include. Defaults to clicks,unique_clicks if omitted.
Available metrics:
clicks— total click countunique_clicks— unique visitor count (deduplicated by IP + User-Agent)
200"clicks,unique_clicks"
IANA timezone name for time-based grouping and output formatting (e.g., UTC, America/New_York, Asia/Kolkata). Defaults to UTC.
50"UTC"
"America/New_York"
Method 1: JSON Filters Object
JSON string containing dimension filters. Format: {"dimension": ["value1", "value2"]}
Available filter dimensions:
browser— Filter by browser name (e.g., Chrome, Firefox, Safari, Edge)os— Filter by operating system (e.g., Windows, macOS, Linux, iOS, Android)device— Filter by device type (mobile,tablet,desktop,unknown)country— Filter by country name (e.g., United States, Canada, Germany)city— Filter by city name (e.g., New York, London, Mumbai)referrer— Filter by referrer URL (e.g., https://google.com, https://twitter.com)utm_source/utm_medium/utm_campaign— Filter by campaign tags;(none)matches untagged clicks
Value format: Array of strings for each dimension.
Important: Filter values are case-sensitive. Use exact capitalization as stored in the database.
Examples:
{"browser": ["Chrome", "Firefox"]}— Chrome OR Firefox clicks{"country": ["United States", "Canada"], "browser": ["Chrome"]}— US/CA clicks from Chrome
Alternative: You can also pass filters as individual query parameters (see browser, os, country, city, referrer parameters below).
5000"{\"browser\":[\"Chrome\",\"Firefox\"]}"
Method 2: Individual Filter Parameter
Comma-separated browser names. Alternative to using the filters JSON parameter.
Important: Values are case-sensitive. Common values include: Chrome, Firefox, Safari, Edge, Opera, Samsung Internet.
Note: Both filters JSON and individual parameters can be combined.
500"Chrome,Firefox"
Method 2: Individual Filter Parameter
Comma-separated operating system names. Alternative to using the filters JSON parameter.
Important: Values are case-sensitive. Common values include: Windows, macOS, Linux, iOS, Android, Chrome OS.
Note: Both filters JSON and individual parameters can be combined.
500"Windows,macOS"
Method 2: Individual Filter Parameter
Comma-separated device types. Alternative to using the filters JSON parameter.
Values: mobile, tablet, desktop, unknown. unknown also matches clicks recorded before device tracking existed.
Note: Both filters JSON and individual parameters can be combined.
200"mobile,desktop"
Method 2: Individual Filter Parameter
Comma-separated country names. Alternative to using the filters JSON parameter.
Important: Values are case-sensitive. Use full country names as stored in the database (e.g., United States, Canada, United Kingdom, India, Germany, France, Japan).
Note: Both filters JSON and individual parameters can be combined.
1000"United States,Germany"
Method 2: Individual Filter Parameter
Comma-separated city names. Alternative to using the filters JSON parameter.
Important: Values are case-sensitive. Use exact capitalization as stored in the database.
Note: Both filters JSON and individual parameters can be combined.
1000"San Francisco,Berlin"
Method 2: Individual Filter Parameter
Comma-separated referrer URLs. Alternative to using the filters JSON parameter.
Important: Values are case-sensitive. Include the full URL including protocol.
Note: Both filters JSON and individual parameters can be combined.
2000"https://google.com,https://twitter.com"
Method 2: Individual Filter Parameter
Comma-separated campaign tag values. Alternative to using the filters JSON parameter.
Important: Values are case-sensitive. (none) matches clicks with no tag.
Note: Both filters JSON and individual parameters can be combined.
1000"newsletter,twitter"
Method 2: Individual Filter Parameter
Comma-separated campaign tag values. Alternative to using the filters JSON parameter.
Important: Values are case-sensitive. (none) matches clicks with no tag.
Note: Both filters JSON and individual parameters can be combined.
1000"email,social"
Method 2: Individual Filter Parameter
Comma-separated campaign tag values. Alternative to using the filters JSON parameter.
Important: Values are case-sensitive. (none) matches clicks with no tag.
Note: Both filters JSON and individual parameters can be combined.
1000"summer-launch"
Response
Successful Response
Response body for GET /api/v1/stats/links/{url_id}.
The standard stats wire plus the identity of the selected link.
scope stays all — the link is part of the owner's aggregate.
Stats wire scope.
Response-only: the scope request parameter no longer exists (auth
is mandatory), but the response wire keeps its scope key and the
public stats endpoint's frozen contract still carries anon.
all, anon Time range metadata inside StatsResponse.
Summary statistics block inside StatsResponse.
Keyed by '{metric}by{dimension}' (e.g. 'clicks_by_browser', 'unique_clicks_by_time'). Each value is a list of data-point objects whose keys are the dimension name, the metric name, and '{metric}_percentage'.
Time bucketing metadata — only present when 'time' is in group_by.
Optional computed metrics added by format_stats_response_with_metadata.

