Click analytics
Two endpoints report on clicks: a raw log of individual clicks, and an aggregated time series of click counts. Both are nested under a link and both require the links:read scope.
| Method | Path | Scope | Returns |
|---|---|---|---|
GET | /v1/links/{id}/clicks | links:read | Paginated log of single clicks |
GET | /v1/links/{id}/stats | links:read | Click counts grouped by period |
A link belonging to another account returns 404 not_found from both endpoints.
The click object
{
"id": "c41d8b30-9e57-4a22-b6f8-1d0e7a94c2b5",
"ip": "203.0.113.42",
"country": "US",
"visitor_id": "visitor-9f2c1b",
"referrer": "https://twitter.com/",
"device": "mobile",
"browser": "Safari",
"platform": "iOS",
"created_at": "2026-08-28T10:16:31.000000Z"
}| Field | Type | Description |
|---|---|---|
id | uuid | The click’s identifier |
ip | string | null | IP address the click came from |
country | string | null | Two-letter country code resolved from the IP |
visitor_id | string | null | Pseudonymous visitor identifier, stable across clicks from the same visitor |
referrer | string | null | The page the visitor came from, when the browser sent one |
device | string | null | Device category, for example mobile or desktop |
browser | string | null | Browser name |
platform | string | null | Operating system |
created_at | timestamp | When the click was recorded |
Any of the enriched fields can be null — referrer when the visitor
navigated directly, country when the IP could not be resolved, and the
device fields when the user agent could not be parsed.
The click object carries a link_id field in webhook deliveries, where the link it belongs to would otherwise be ambiguous. It is omitted from this endpoint’s responses, because the link is already named in the request path.
List clicks
GET /v1/links/{id}/clicksScope: links:read
Returns the raw click log for a link, newest first, in the standard paginated shape.
| Query parameter | Type | Description |
|---|---|---|
page | integer | Page to return. Defaults to 1. |
per_page | integer | Results per page. Defaults to 15, maximum 100. |
curl "https://app.linksqueeze.io/api/v1/links/9b1f4e2a-6c3d-4a17-9f2e-7c8d5a1b3e40/clicks?per_page=100" \
-H "Authorization: Bearer $LINKSQUEEZE_API_KEY" \
-H "Accept: application/json"{
"data": [
{
"id": "c41d8b30-9e57-4a22-b6f8-1d0e7a94c2b5",
"ip": "203.0.113.42",
"country": "US",
"visitor_id": "visitor-9f2c1b",
"referrer": "https://twitter.com/",
"device": "mobile",
"browser": "Safari",
"platform": "iOS",
"created_at": "2026-08-28T10:16:31.000000Z"
}
],
"links": { "first": "...", "last": "...", "prev": null, "next": "..." },
"meta": { "current_page": 1, "per_page": 100, "total": 128 }
}Click statistics
GET /v1/links/{id}/statsScope: links:read
Returns click counts grouped into time buckets — the shape you want for a chart, without paging through every individual click.
| Query parameter | Type | Description |
|---|---|---|
group_by | string | One of day, week, or month. Defaults to day. |
from | date | Only count clicks from this date onward. Inclusive, from the start of the day. |
to | date | Only count clicks up to this date. Inclusive, through the end of the day. |
curl "https://app.linksqueeze.io/api/v1/links/9b1f4e2a-6c3d-4a17-9f2e-7c8d5a1b3e40/stats?group_by=day&from=2026-07-01&to=2026-07-31" \
-H "Authorization: Bearer $LINKSQUEEZE_API_KEY" \
-H "Accept: application/json"{
"data": [
{ "period": "2026-07-01", "clicks": 2 },
{ "period": "2026-07-02", "clicks": 1 }
]
}| Field | Type | Description |
|---|---|---|
period | date | The start of the bucket, as YYYY-MM-DD |
clicks | integer | Number of clicks recorded within that bucket |
Buckets are sorted oldest first. period is always the first day of the bucket: the day itself for day, the Monday for week, and the first of the month for month.
Empty periods are omitted. A day with no clicks does not appear in the
response as a zero — it is simply absent. If you are drawing a chart, generate
the full range of periods yourself and fill in the gaps with 0.
This response is not paginated and has no links or meta object. Narrow it with from and to rather than by paging.
An invalid group_by value is rejected with 422 validation_error.