Link-Statistik-API
GET /v1/urls/{slug}/stats gibt voraggregierte Analysen für einen deiner Links zurück. Eigentümer-beschränkt, cookielos, nur aggregiert (keine Zeilen pro Klick, keine Besucherkennungen, siehe Wie wir zählen). Die Web-App-Route /x/urls/{slug}/stats gibt denselben Body zurück.
Anfrage
GET /v1/urls/{slug}/stats?from=YYYY-MM-DD&to=YYYY-MM-DD
Authorization: Bearer YOUR_TOKEN_HERE
Jedes API-Token funktioniert hier; Workspace- und persönliche Tokens beschreibt die Authentifizierung.
| Parameter | Wo | Erforderlich | Standard | Hinweise |
|---|---|---|---|---|
slug | Pfad | ja | keiner | Ein Link, der dir gehört (sonst 404). |
from | Query | nein | to − 29 Tage | Fensteranfang, UTC-Datum YYYY-MM-DD. |
to | Query | nein | heute (UTC) | Fensterende, UTC-Datum; niemals in der Zukunft. |
Fenster-Semantik (begrenzen, nicht ablehnen). from wird auf die Analyse-Aufbewahrung deines Plans begrenzt (30 Tage in Free, 730 Tage in Pro und Team). Ein Fenster, das länger als deine Aufbewahrung ist, ist kein Fehler: Es wird begrenzt und der effektive Anfang wird in range.clampedTo zurückgegeben (mit retentionDays und storedDays). Ein fehlerhaftes Fenster (from nach to oder ein nicht parsbares Datum) ist ein 400.
Ratenbegrenzung. Ein Kontingent gilt für alle /v1-Endpunkte zusammen: 300 Anfragen/Minute in Pro, 600 in Team, geteilt von allen Tokens eines Workspace. Bei Überschreitung wird 429 mit einem Retry-After-Header zurückgegeben. Siehe Ratenlimits.
Antwort 200
{
"stats": {
"slug": "spring-sale",
"zoneDomain": "snipzr.li",
"range": { "from": "2026-06-14", "to": "2026-07-13", "clampedTo": "2026-06-14", "retentionDays": 30, "storedDays": 122 },
"allTime": { "total": 5120, "preTracking": 4900, "trackingSince": "2026-07-13" },
"totals": { "human": 82, "bots": 61, "requests": 143, "qr": 12, "click": 70, "botsAndPreviews": 44, "aiAssistants": 2, "suspected": 15 },
"series": [ { "date": "2026-07-12", "n": 90, "b": 40, "bs": 9 }, { "date": "2026-07-13", "n": 53, "b": 21, "ba": 2, "bs": 6 } ],
"hourly": { "fromUtc": "2026-07-12T16:00:00Z", "buckets": [0,0,1,2,3,4,6,8,7,9,5,6,4,3,2,2,1,3,4,2,1,0,0,0] },
"geo": [ { "k": "US", "v": 40 }, { "k": "DE", "v": 22 }, { "k": "unknown", "v": 3 } ],
"referrers": [ { "k": "~direct", "v": 31 }, { "k": "reddit.com", "v": 18 }, { "k": "~other", "v": 4 } ],
"devices": [ { "k": "desktop", "v": 51 }, { "k": "mobile", "v": 28 } ],
"browsers": [ { "k": "chrome", "v": 40 } ],
"os": [ { "k": "windows", "v": 25 } ],
"languages": [ { "k": "en", "v": 60 } ],
"source": { "click": 70, "qr": 12 },
"notHuman": {
"botsAndPreviews": [ { "k": "preview", "v": 30 }, { "k": "crawler", "v": 10 }, { "k": "head", "v": 4 } ],
"aiAssistants": [ { "k": "chatgpt", "v": 2 } ],
"suspected": [ { "k": "no_language", "v": 11 }, { "k": "sweep", "v": 4 } ]
},
"freshness": "todayLive"
}
}
Felder
| Feld | Bedeutung |
|---|---|
range | Effektives Fenster + Aufbewahrungs-/Begrenzungs-Metadaten (clampedTo = effektiver Anfang; storedDays kann retentionDays übersteigen). |
allTime | Lebenszeit-Aufrufe, aufgeteilt in Vor-Erfassungs- vs. erfassten Zeitraum. Bei einem Link, der aus einem anderen Kurzlink-Dienst importiert wurde und dessen Klickzahl mitbrachte, enthält imported {count, source, importedAt} diese Zahl: source ist bitly, rebrandly, tinyurl oder csv (eine Importdatei), importedAt der UTC-Tag des Imports. Sie ist nie Teil von total oder totals und fehlt bei allen anderen Links. |
totals | Fenstersummen. human = requests − bots ist die Hauptzahl. bots ist jede Anfrage, die nicht als menschlich zählt, aufgeteilt in botsAndPreviews + aiAssistants + suspected. requests (roh, inkl. Bots/Monitore): nicht darauf abrechnen oder alarmieren. |
series | Pro UTC-Tag {date, n, b} (Mensch = n − b), aufsteigend, Null-Tage weggelassen; ba (KI-Assistenten) und bs (mutmaßlich automatisiert), Teile von b, erscheinen an Tagen, an denen es welche gibt. |
hourly | Gleitende letzte 24 Stunden menschlicher Klicks nach UTC-Stunde, unabhängig vom Fenster (leer bei einem rein historischen Fenster). |
geo,referrers,devices,browsers,os,languages | [{k, v}], absteigend nach v sortiert. Verweise sind nur-Host; Sentinels ~direct (kein Verweis) und ~other (zusammengefasster Rest). Länderschlüssel unknown, wenn nicht bestimmbar. |
source | {click, qr}-Aufteilung menschlicher Klicks. |
notHuman | {botsAndPreviews, aiAssistants, suspected}: jeweils eine [{k, v}]-Liste von Gründen, die sich zu ihrer Summe addiert. Bots & Vorschauen: preview, crawler, tool, monitor, prefetch, head, no_user_agent, link_check, declared und unrecorded für Tage, bevor Gründe erfasst wurden. KI-Assistenten: chatgpt, claude, perplexity, mistral, meta, other. Mutmaßlich automatisiert: no_language, not_navigation, inconsistent, data_center, burst, sweep, clockwork. Was sie bedeuten: Wie wir zählen. |
freshness | todayLive | final | degraded. |
Zählungen sind pro UTC-Tag monoton nicht abnehmend, außer einem kurzen Rückgang während eines stündlichen Konsolidierungsfensters; sie pendeln sich innerhalb der Stunde ein. Behandle einen vorübergehenden Rückgang am selben Tag nicht als Datenverlust.
Fehler
| Status | Wann |
|---|---|
400 | fehlerhaftes Fenster (from > to, ungültiges Datum) oder ungültiger Slug |
404 | Slug für diesen Eigentümer nicht gefunden |
429 | über dem geteilten /v1-Ratenlimit des Plans (Retry-After-Header) |
503 | Analysespeicher nicht erreichbar und keine Live-Daten decken das Fenster ab |
Ein degraded-200 (Speicher aus, aber aktuelle Live-Daten verfügbar) unterscheidet sich von einem 503 (nichts auslieferbar). Stelle freshness: "degraded" als „nur aktuelle Daten" dar.
Beispiel
curl -H "Authorization: Bearer $SNIPZR_TOKEN" \
"https://api.snipzr.com/v1/urls/spring-sale/stats?from=2026-06-14&to=2026-07-13"
JSON-Schema
Die Antwort wird durch ein veröffentlichtes JSON-Schema (2020-12) beschrieben: https://www.snipzr.com/schemas/v1/link-stats.schema.json. Richte deinen Validator oder Codegenerator auf diese URL.
Versionierung
Additive, abwärtskompatible Felder können ohne Versionssprung erscheinen, also toleriere unbekannte Felder; das JSON-Schema wird mit ihnen aktualisiert. Entfernungen/Umbenennungen sind eine neue Hauptversion. Die Web-App kann dieselben Daten als CSV exportieren (Langformat date,metric,key,value); die API ist nur JSON.