Référence de l'API publique
L’API publique expose en lecture seule les statistiques agrégées de vos sites, pour alimenter un dashboard maison, un compteur de vues public ou toute intégration serveur. Elle réutilise exactement les mêmes agrégats que le dashboard Elvn : mêmes chiffres, mêmes définitions.
- Base URL :
https://api.elvn.live - Version : préfixe
/v1(les évolutions incompatibles changeront de préfixe) - Méthode :
GETuniquement, réponsesapplication/json; charset=utf-8 - Serveur à serveur uniquement : aucun en-tête CORS n’est renvoyé, par
design — un appel
fetch()depuis un navigateur échoue. Votre clé API doit rester côté serveur (Node, Worker, cron…), jamais dans une page web.
Authentification
Section intitulée « Authentification »Chaque requête porte une clé API dans l’en-tête Authorization :
Authorization: Bearer elvn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxLes clés se créent dans le dashboard, Réglages de l’organisation →
Clés API (/settings/api-keys, rôle admin ou propriétaire requis). La clé
complète (elvn_ + 32 caractères) n’est affichée qu’une seule fois, à la
création — copiez-la immédiatement. Seule son empreinte SHA-256 est conservée.
Une clé donne accès en lecture à tous les sites de l’organisation qui l’a créée. La révocation (même écran) est immédiate et irréversible : les requêtes suivantes reçoivent un 401.
Clé absente, malformée, inconnue ou révoquée : la réponse est toujours le même
401 — l’API ne révèle jamais si une clé a existé.
Identifier un site
Section intitulée « Identifier un site »Les endpoints par site utilisent le public_id du site (jamais un id
numérique) : la valeur de l’attribut data-site du snippet de tracking,
visible dans Réglages du site → Suivi. Un site archivé, inexistant ou
appartenant à une autre organisation répond 404 — trois cas
indistinguables, volontairement.
Périodes
Section intitulée « Périodes »Tous les endpoints statistiques acceptent l’un ou l’autre :
| Paramètre | Valeurs | Défaut |
|---|---|---|
period |
today · yesterday · 7d · 30d · 90d · month · last_month · year |
30d |
from + to |
Jours YYYY-MM-DD, inclusifs, toujours fournis ensemble (prioritaires sur period) |
— |
Les jours sont des jours locaux du site (son fuseau IANA, configuré dans
ses réglages) ; la réponse écho la période résolue (period.from,
period.to, period.tz). from postérieur à to → 400 INVALID_PERIOD.
filter=<dimension>:<valeur>, répétable — les filtres se cumulent (AND),
une seule valeur par dimension :
?filter=country:FR&filter=device:mobileDimensions : page · entry · exit · referrer · utm_source ·
utm_medium · utm_campaign · country · region · city · browser ·
os · device · event.
Deux filtres et plus (ou un filtre croisé avec un breakdown d’une autre
dimension) forcent une lecture des événements bruts, conservés 30 jours : la
période est alors limitée à 30 jours (400 RAW_WINDOW_EXCEEDED au-delà).
Dimension inconnue ou valeur vide → 400 INVALID_PARAMS, jamais de repli
silencieux.
Limites de débit
Section intitulée « Limites de débit »600 requêtes/heure par clé (fenêtre glissante de 10 requêtes/60 s). Au-delà :
HTTP/1.1 429 Too Many Requestsretry-after: 60{ "error": { "code": "RATE_LIMITED", "message": "rate limit exceeded (600 requests/hour per key)" } }Toutes les réponses portent cache-control: no-store : mettez en cache côté
client si votre usage l’exige (les agrégats journaliers ne bougent qu’à la
clôture des sessions, un cache de 60 s est raisonnable pour un widget).
Enveloppe unique :
{ "error": { "code": "…", "message": "…" } }| Code | HTTP | Cause |
|---|---|---|
UNAUTHORIZED |
401 | Clé absente, malformée, inconnue ou révoquée |
NOT_FOUND |
404 | Site/funnel inconnu, archivé ou d’une autre organisation ; route inconnue |
INVALID_PARAMS |
400 | Paramètre malformé : preset inconnu, dimension inconnue, limit hors bornes, from sans to… |
INVALID_PERIOD |
400 | from postérieur à to |
INVALID_TIMEZONE |
400 | Fuseau du site invalide (cas limite de configuration) |
RAW_WINDOW_EXCEEDED |
400 | Filtres multiples sur plus de 30 jours |
METRIC_NOT_FILTERABLE |
400 | Métrique incompatible avec les filtres demandés (ex. sessions filtrée) |
HOURLY_CONVERSIONS_UNSUPPORTED |
400 | Timeseries conversions sur une période ≤ 48 h (grain horaire) |
RATE_LIMITED |
429 | Quota de 600 req/h dépassé (retry-after: 60) |
INTERNAL |
500 | Erreur interne — réessayez, signalez si persistant |
GET /v1/sites
Section intitulée « GET /v1/sites »Les sites actifs (non archivés) de l’organisation de la clé.
curl -s https://api.elvn.live/v1/sites \ -H "Authorization: Bearer $ELVN_API_KEY"{ "sites": [ { "id": "a1B2c3D4e5F6", "domain": "blog.exemple.fr", "name": "Blog", "timezone": "Europe/Paris", "retentionMonths": 25 } ]}id est le public_id à utiliser dans tous les endpoints suivants.
retentionMonths est la durée de conservation des statistiques du site, en
mois (réglage Suivi → Conservation des statistiques du dashboard) : les
jours plus anciens sont effacés et ne sont plus renvoyés par l’API. null :
sans limite.
GET /v1/sites/:siteId/stats
Section intitulée « GET /v1/sites/:siteId/stats »Les KPIs de la période, chacun comparé à la période précédente de même durée.
Paramètres : period ou from/to, filter (répétable).
curl -s "https://api.elvn.live/v1/sites/a1B2c3D4e5F6/stats?period=30d&filter=country:FR" \ -H "Authorization: Bearer $ELVN_API_KEY"{ "period": { "from": "2026-07-25", "to": "2026-08-23", "grain": "day", "tz": "Europe/Paris" }, "stats": { "visitors": { "value": 4210, "prev": 3980, "deltaPct": 5.8 }, "pageviews": { "value": 11893, "prev": 11020, "deltaPct": 7.9 }, "sessions": { "value": 5102, "prev": 4890, "deltaPct": 4.3 }, "bounceRate": { "value": 0.41, "prev": 0.44, "deltaPct": -6.8 }, "avgDuration": { "value": 84, "prev": 78, "deltaPct": 7.7 }, "conversions": { "value": 120, "prev": 96, "deltaPct": 25 } }}bounceRateest un ratio 0..1,avgDurationen secondes.conversionsvautnullsi le site n’a aucun goal, ou quand des filtres sont actifs (les conversions ne sont pas filtrables).- Un champ
valuepeut êtrenullquand la donnée n’est pas calculable sur la fenêtre demandée.
GET /v1/sites/:siteId/timeseries
Section intitulée « GET /v1/sites/:siteId/timeseries »La série temporelle d’une métrique. Le grain est automatique : ≤ 48 h →
hour, ≤ 90 jours → day, ≤ 366 jours → week (semaines commençant lundi),
au-delà → month.
| Paramètre | Valeurs | Défaut |
|---|---|---|
metric |
visitors · pageviews · sessions · bounceRate · avgDuration · conversions |
visitors |
compare |
true pour inclure la série de la période précédente (prev) |
false |
period / from+to, filter |
cf. conventions |
curl -s "https://api.elvn.live/v1/sites/a1B2c3D4e5F6/timeseries?period=7d&metric=pageviews&compare=true" \ -H "Authorization: Bearer $ELVN_API_KEY"{ "period": { "from": "2026-08-17", "to": "2026-08-23", "grain": "day", "tz": "Europe/Paris" }, "grain": "day", "tz": "Europe/Paris", "points": [ { "t": 1755381600000, "value": 402 }, { "t": 1755468000000, "value": 388 } ], "prev": [ { "t": 1754776800000, "value": 361 }, { "t": 1754863200000, "value": 344 } ]}t est le début du bucket en millisecondes epoch UTC (le bucket est aligné
sur le fuseau du site). value peut être null (bucket sans donnée
calculable). conversions sur une période ≤ 48 h répond
400 HOURLY_CONVERSIONS_UNSUPPORTED.
GET /v1/sites/:siteId/breakdown
Section intitulée « GET /v1/sites/:siteId/breakdown »Le classement des valeurs d’une dimension (pages, pays, sources…).
| Paramètre | Valeurs | Défaut |
|---|---|---|
dimension |
une des 14 dimensions de filtre (cf. Filtres) | requis |
limit |
1..1000 | 100 |
offset |
≥ 0 (pagination) | 0 |
search |
Sous-chaîne à chercher dans les clés (≤ 256 caractères) | — |
period / from+to, filter |
cf. conventions |
curl -s "https://api.elvn.live/v1/sites/a1B2c3D4e5F6/breakdown?period=30d&dimension=page&limit=5" \ -H "Authorization: Bearer $ELVN_API_KEY"{ "period": { "from": "2026-07-25", "to": "2026-08-23", "grain": "day", "tz": "Europe/Paris" }, "dimension": "page", "rows": [ { "key": "/", "visitors": 1804, "views": 3210, "pct": 0.43 }, { "key": "/pricing", "visitors": 902, "views": 1490, "pct": 0.21 } ], "totalKeys": 38, "totalVisitors": 4210}pct= part des visiteurs du site sur la période (0..1).- Paginez avec
limit/offset;totalKeysdonne le nombre total de clés distinctes. Les valeurs absentes sont notées(none), l’agrégat de longue traîne(other).
GET /v1/sites/:siteId/realtime
Section intitulée « GET /v1/sites/:siteId/realtime »Le panneau temps réel : visiteurs des 5 dernières minutes, activité des 30 dernières minutes. Aucun paramètre.
curl -s https://api.elvn.live/v1/sites/a1B2c3D4e5F6/realtime \ -H "Authorization: Bearer $ELVN_API_KEY"{ "generatedAt": 1755972000000, "currentVisitors": 12, "pageviewsPerMinute": [{ "t": 1755970200000, "value": 3 }], "topPages": [{ "key": "/", "visitors": 6, "views": 9 }], "topReferrers": [{ "key": "google.com", "visitors": 4, "views": 5 }], "topCountries": [{ "key": "FR", "visitors": 8, "views": 14 }], "feed": [ { "ts": 1755971940000, "event": "pageview", "path": "/pricing", "referrer": "google.com", "country": "FR", "city": "Lyon", "browser": "Firefox", "os": "Linux", "device": "desktop" } ]}Pour un simple compteur « en ce moment », lisez currentVisitors
(rafraîchissement conseillé : toutes les 10–30 s, en gardant le quota de
600 req/h en tête).
GET /v1/sites/:siteId/goals
Section intitulée « GET /v1/sites/:siteId/goals »Les conversions par goal sur la période, avec le delta vs la période
précédente. Paramètres : period ou from/to (pas de filtres).
curl -s "https://api.elvn.live/v1/sites/a1B2c3D4e5F6/goals?period=30d" \ -H "Authorization: Bearer $ELVN_API_KEY"{ "period": { "from": "2026-07-25", "to": "2026-08-23" }, "goals": [ { "goalId": 3, "name": "Inscription", "kind": "page", "pattern": "/merci", "conversions": 120, "uniqueConversions": 104, "conversionRate": 0.0247, "delta": 25 } ]}kind : page (URL visitée) ou event (événement custom).
conversionRate = visiteurs uniques convertis / visiteurs du site (0..1).
delta en % vs la période précédente (null sans base de comparaison). Un
site sans goal répond { "goals": [] }.
GET /v1/sites/:siteId/funnels
Section intitulée « GET /v1/sites/:siteId/funnels »Les funnels définis sur le site. Aucun paramètre.
curl -s https://api.elvn.live/v1/sites/a1B2c3D4e5F6/funnels \ -H "Authorization: Bearer $ELVN_API_KEY"{ "funnels": [ { "id": 1, "name": "Checkout", "stepCount": 3, "windowMinutes": 60, "version": 2, "createdAt": 1751329800000 } ]}GET /v1/sites/:siteId/funnels/:funnelId
Section intitulée « GET /v1/sites/:siteId/funnels/:funnelId »La lecture d’un funnel sur la période : visiteurs par étape, taux de passage, conversion globale et delta vs la période précédente.
| Paramètre | Valeurs | Défaut |
|---|---|---|
version |
1..version courante — chaque modification des étapes incrémente la version, les anciennes restent lisibles. Hors bornes : version courante | version courante |
period / from+to |
cf. conventions (pas de filtres) | 30d |
curl -s "https://api.elvn.live/v1/sites/a1B2c3D4e5F6/funnels/1?period=30d" \ -H "Authorization: Bearer $ELVN_API_KEY"{ "period": { "from": "2026-07-25", "to": "2026-08-23" }, "funnel": { "id": 1, "name": "Checkout", "version": 2, "windowMinutes": 60 }, "steps": [ { "step": 1, "visitors": 840, "rateFromPrevious": null }, { "step": 2, "visitors": 410, "rateFromPrevious": 0.488 }, { "step": 3, "visitors": 96, "rateFromPrevious": 0.234 } ], "entered": 840, "completed": 96, "conversionRate": 0.114, "previous": { "entered": 790, "completed": 71, "conversionRate": 0.0899 }, "delta": 27.1}Exemple d’intégration (Node.js)
Section intitulée « Exemple d’intégration (Node.js) »const BASE = "https://api.elvn.live/v1";const headers = { authorization: `Bearer ${process.env.ELVN_API_KEY}` };
async function elvn(path) { const res = await fetch(`${BASE}${path}`, { headers }); const body = await res.json(); if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`); return body;}
const { sites } = await elvn("/sites");const stats = await elvn(`/sites/${sites[0].id}/stats?period=7d`);console.log(`${sites[0].name} : ${stats.stats.visitors.value} visiteurs sur 7 jours`);À exécuter côté serveur uniquement — la clé ne doit jamais atteindre un navigateur.