Skip to Content
GuidesSkoup Analytics

Skoup Analytics

Skoup Analytics mesure les visites que ChatGPT, Perplexity, Gemini ou Claude envoient sur votre site, pour Revenue › Trafic IA et GET /v1/brands/{brand}/traffic. Activez-le dans Réglages › Intégrations › Skoup Analytics, puis collez la balise.

<script defer src="https://app.skoup.ai/t.js" data-site="site_…"></script>

À coller sur toutes les pages, juste avant </body>. Les hits partent vers https://api.skoup.ai/t (POST, JSON en text/plain, sendBeacon), regroupés par seconde.

Avec un framework

Le cœur et ses wrappers sont publiés sur npm, code source sur github.com/lunifyfr/skoup-sdk  (MIT) :

PackagePour
@skoup/analyticsLe cœur : createSkoup({ site }), ou la balise skoup.iife.js
@skoup/analytics-react<SkoupProvider site>, useSkoup(), useSkoupPageview()
@skoup/analytics-next<SkoupAnalytics site> dans le layout racine (App Router)
@skoup/analytics-vueapp.use(createSkoupPlugin({ site, router })), useSkoup()
@skoup/analytics-nuxtModule : skoup: { site } dans nuxt.config
@skoup/analytics-svelteinitSkoup({ site }), trackPage() depuis afterNavigate
// Next.js — app/layout.tsx import { SkoupAnalytics } from '@skoup/analytics-next' export default function RootLayout({ children }) { return <SkoupAnalytics site="site_…" consent="wait">{children}</SkoupAnalytics> }

Chaque wrapper rend la même instance : skoup.event(), skoup.consent(), skoup.attribution(). Les pages vues suivent la navigation du framework, rien à appeler.

Ce que Skoup Analytics mesure

EnvoyéJamais envoyé
Pages vues : hôte, chemin, paramètres utm_* et refTitre de la page, contenu des formulaires, autres paramètres d’URL, fragment
Site de provenance (referrer, sans ses paramètres)Taille d’écran, langue, navigateur, système
Événements nommés (skoup('event', …)), avec leurs propriétés scalairesL’adresse IP n’est pas stockée : elle sert au pays, puis est oubliée
Identifiant de visiteur : une valeur aléatoire dans le cookie skp_vid (13 mois), posé sur le domaine racine du site (nordvelo.fr pour www., shop. et app. : un seul visiteur d’un sous-domaine à l’autre)Toute donnée d’identité

Une visite regroupe les hits d’un même visiteur sans trente minutes d’inactivité ; une page entrée depuis un assistant IA ou avec un utm_source ouvre une nouvelle visite, pour être attribuée. La source d’une visite (referrer ou utm_source) est classée par la liste de surfaces que Skoup maintient. Le premier contact d’une conversion est la plus ancienne visite du même visiteur dans les 30 derniers jours.

Consentement

Le script dépose un cookie : chargez-le après le consentement de vos visiteurs, via votre bandeau (CMP). Ou laissez-le charger et retenez le cookie :

<script defer src="https://app.skoup.ai/t.js" data-site="site_…" data-consent="wait"></script> <script> // quand votre bandeau reçoit l'accord : window.skoup && window.skoup('consent', 'granted') </script>

Sans cookie, chaque hit est une visite d’un visiteur inconnu : pas de premier contact, pas de conversion différée.

Événements

// une inscription, une demande de démo, un appel, une réservation… skoup('event', 'signup', { plan: 'growth' }) // une commande hors Shopify (montant, devise, identifiant de commande) skoup('event', 'purchase', null, { value: 129.9, currency: 'EUR', order_id: '1042' })

Un nom d’événement est en [a-z0-9_], 64 caractères au plus ; jusqu’à 20 propriétés scalaires de 256 caractères. Pour une boutique, la conversion du rapport compte les purchase ; pour un SaaS ou un établissement, les événements clés choisis dans l’app (tous les événements nommés par défaut). Les appels faits avant le chargement du script sont pris en file : window.skoup = window.skoup || function () { (window.skoup.q = window.skoup.q || []).push(arguments) }.

Une application monopage voit chaque changement de route comme une page ; skoup('pageview') force une page.

Attribuer un abonnement Stripe

skoup.attribution() rend ce dont la visite vient — { visitor_id, referrer, landing_url, utm_source, utm_medium, utm_campaign }, gardé pendant la session du navigateur. Écrivez-le dans les métadonnées de l’abonnement (ou du client) Stripe, que Skoup lit déjà :

const from = skoup.attribution() ?? {} await stripe.checkout.sessions.create({ subscription_data: { metadata: { skoup_referrer: from.referrer, skoup_utm_source: from.utm_source, skoup_landing_url: from.landing_url } }, // … })

Boutique Shopify

Sur une boutique Shopify connectée, Skoup pose lui-même le pixel Skoup Analytics (extension web pixel de l’app) dès que la marque a sa clé de site : pages vues, produits vus, ajouts au panier, checkouts et achats, y compris sur les pages de checkout où une balise de thème ne va pas. Rien à coller dans le thème ; la balise reste utile pour vos autres sites (landing, blog).

Le pixel envoie ses hits par l’app proxy de la boutique (https://votre-boutique.fr/apps/skoup/t) : first-party, signé par Shopify, hors des listes de bloqueurs. Le consentement est celui de la boutique : le pixel est déclaré analytics auprès de Shopify, qui ne le charge qu’après l’accord du visiteur là où la loi l’exige (bandeau Shopify ou app de consentement compatible).

Chaque achat porte l’identifiant de la commande et le jeton de checkout : Skoup rapproche la commande reçue par webhook de la visite qui l’a faite, quel que soit l’ordre d’arrivée. C’est ce qui donne le « Premier contact IA » de Revenue › Commandes et first_touch de GET /v1/brands/{brand}/attribution : l’acheteur qui a demandé à ChatGPT il y a dix jours puis est revenu par Google.

Le pixel demande les accès write_pixels et read_customer_events : une boutique connectée avant leur ajout affiche « Reconnectez la boutique » dans Réglages › Intégrations. Régénérer la clé du site met le pixel à jour ; oublier la clé le retire de la boutique.

Proxy first-party

Servez la balise et recevez les hits sur votre propre domaine : les bloqueurs de publicité ne voient plus skoup.ai, et le cookie skp_vid est posé par la réponse du collecteur, en HTTP, donc 13 mois même sur Safari (qui limite à 7 jours un cookie posé en JavaScript). Rien à déclarer chez Skoup, comme le tunnel de Sentry : copiez le secret dans Réglages › Intégrations › Skoup Analytics › Installer › Proxy first-party, et servez la balise depuis votre domaine. Le script servi en /_skoup/t.js envoie ses hits en /_skoup/t tout seul (data-endpoint le force si besoin) :

<script defer src="https://www.votre-site.fr/_skoup/t.js" data-site="site_…"></script>

Votre serveur transmet deux chemins, en ajoutant deux en-têtes à la requête vers le collecteur :

CheminVersEn-têtes ajoutés
GET /_skoup/t.jshttps://app.skoup.ai/t.js—
POST /_skoup/thttps://api.skoup.ai/tX-Skoup-Proxy: <secret> · X-Skoup-Client-IP: <IP du visiteur>

Le collecteur ne fait confiance à X-Skoup-Client-IP (pour le pays, jamais conservée) et ne renvoie le cookie qu’avec le bon secret ; la réponse du collecteur, Set-Cookie compris, est retournée telle quelle au navigateur. Sans le secret, le hit est traité comme un hit direct.

nginx

location = /_skoup/t.js { proxy_pass https://app.skoup.ai/t.js; proxy_set_header Host app.skoup.ai; proxy_ssl_server_name on; } location = /_skoup/t { proxy_pass https://api.skoup.ai/t; proxy_set_header Host api.skoup.ai; proxy_ssl_server_name on; proxy_set_header X-Skoup-Proxy "skp_proxy_…"; proxy_set_header X-Skoup-Client-IP $remote_addr; proxy_pass_request_headers on; }

Cloudflare Worker (route www.votre-site.fr/_skoup/*)

export default { async fetch(request, env) { const url = new URL(request.url) if (url.pathname === '/_skoup/t.js') { return fetch('https://app.skoup.ai/t.js', { cf: { cacheTtl: 3600 } }) } if (url.pathname === '/_skoup/t' && request.method === 'POST') { const headers = new Headers(request.headers) headers.set('X-Skoup-Proxy', env.SKOUP_PROXY_SECRET) headers.set('X-Skoup-Client-IP', request.headers.get('CF-Connecting-IP') ?? '') return fetch('https://api.skoup.ai/t', { method: 'POST', headers, body: request.body }) } return new Response(null, { status: 404 }) }, }

Next.js (app/_skoup/[...path]/route.ts)

export async function GET() { return fetch('https://app.skoup.ai/t.js', { next: { revalidate: 3600 } }) } export async function POST(request: Request) { const ip = request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ?? '' return fetch('https://api.skoup.ai/t', { method: 'POST', headers: { 'Content-Type': 'text/plain', 'X-Skoup-Proxy': process.env.SKOUP_PROXY_SECRET!, 'X-Skoup-Client-IP': ip }, body: await request.text(), }) }

Le secret se renouvelle en même temps que la clé du site (« Régénérer la clé »). Gardez-le côté serveur : jamais dans la page.

Pièges

  • Un site par marque, des hôtes déclarés : les hits venus d’un autre domaine que ceux de la clé sont ignorés (vide = tous). Un hôte déclaré couvre ses sous-domaines : nordvelo.fr accepte www., shop. et app. ; un second domaine (une landing sur un autre nom) se déclare à part. Le cookie est posé sur le domaine racine que le navigateur accepte ; data-cookie-domain (ou cookieDomain) le force.
  • La journée en cours n’est pas comptée : le rapport s’arrête à hier ; les hits sont enregistrés chaque minute.
  • Régénérer la clé refuse l’ancienne aussitôt : mettez la balise à jour. Oublier la clé arrête la collecte et garde les visites déjà mesurées.
  • Bloqueurs de publicité et Safari : un bloqueur peut retenir le script ; Safari limite un cookie posé en JavaScript à 7 jours, ce qui raccourcit le premier contact. Le proxy first-party ci-dessus lève les deux ; sur Shopify, le pixel passe par l’app proxy de la boutique.
Last updated on