Enregistrement de sessions avec le script Flowsery
L'enregistrement de sessions vous permet de rejouer ce que de vrais visiteurs ont fait sur votre site, mouvements de souris, clics, saisies dans les formulaires, changements de page, en ajoutant un petit script à votre HTML. L'enregistreur est un bundle JS distinct du tracker d'analyse principal, il ne se charge donc que si vous l'activez.
L'enregistreur repose sur rrweb et envoie ses événements de mutation du DOM à Flowsery sous forme de fragments compressés en gzip. Le premier fragment est un instantané complet ; les fragments suivants sont incrémentaux.
Prérequis
- L'enregistrement doit être activé pour le site dans votre tableau de bord Flowsery (
Paramètres du site → Général → Enregistrement des sessions). Le serveur rejette les requêtesrecording_startlorsqu'il est désactivé. - Le tracker d'analyse principal (
/js/main.js) est déjà en place. L'enregistrement utilise le mêmedata-fl-website-id, les mêmes cookies de visiteur et de session et le même endpoint/eventsque le tracker principal.
Démarrage rapide (CDN)
Ajoutez la balise script juste après votre tracker d'analyse principal :
<script defer data-fl-website-id="flid_******" src="https://cdn.flowsery.com/main.js"></script>
<script defer data-fl-website-id="flid_******" src="https://cdn.flowsery.com/recording.js"></script>L'enregistreur applique les mêmes contrôles que le tracker principal (détection des bots, localhost, iframe, file://, auto-exclusion) et s'arrête proprement si l'un d'eux s'applique.
Vous préférez une seule balise ? Ajoutez l'attribut data-recording à votre tracker principal et Flowsery injecte l'enregistreur pour vous, sans second <script> :
<script defer data-fl-website-id="flid_******" data-recording src="https://cdn.flowsery.com/main.js"></script>Activer via le SDK npm
Si vous initialisez Flowsery avec le SDK npm, activez l'enregistrement avec une seule option au lieu d'une balise script :
import { initFlowsery } from 'flowsery';
await initFlowsery({
websiteId: 'flid_******',
recording: true,
});Le SDK charge le bundle de l'enregistreur à la demande depuis le CDN de Flowsery lors de la première initialisation, rrweb n'est donc jamais inclus dans le bundle de votre application. Les événements de suivi passent toujours par votre apiBase s'il est défini. Pour n'enregistrer qu'une partie des sessions, ajoutez recordingSampleRate, et pour n'analyser par IA qu'une partie de celles-ci, ajoutez aiSampleRate (tous deux 0–100, par défaut 100) : consultez la section Échantillonnage. Tout ce qui suit, le prérequis dans le tableau de bord, les modes de confidentialité, les contrôles et la compatibilité navigateur, s'applique de la même façon.
Configuration avec reverse proxy (recommandée en production)
Les bloqueurs de publicité et les extensions anti-pistage bloquent les scripts tiers et analytics.flowsery.com directement. Faire passer le script et l'endpoint des événements par votre propre domaine contourne ce blocage, les IP des visiteurs et la précision restent intactes.
L'enregistreur déduit automatiquement la base de l'API de son propre <script src>, comme le fait le tracker principal. Tant que le bundle d'enregistrement est servi sous /js/recording.js sur votre domaine, aucune configuration supplémentaire n'est nécessaire.
Next.js
// next.config.js
async rewrites() {
return [
{ source: '/js/main.js', destination: 'https://cdn.flowsery.com/main.js' },
{ source: '/js/recording.js', destination: 'https://cdn.flowsery.com/recording.js' },
{ source: '/api/track', destination: 'https://analytics.flowsery.com/analytics/events' },
];
}<script defer data-fl-website-id="flid_******" src="/js/main.js"></script>
<script defer data-fl-website-id="flid_******" src="/js/recording.js"></script>Autres proxies
Le même schéma fonctionne avec n'importe quel reverse proxy. Associez les trois chemins :
| Chemin public | Origine |
|---|---|
/js/main.js | https://cdn.flowsery.com/main.js |
/js/recording.js | https://cdn.flowsery.com/recording.js |
/api/track | https://analytics.flowsery.com/analytics/events |
Pour les guides de proxy propres à chaque framework (Astro, Caddy, Express, FastAPI, Nginx, PHP, Vue, etc.), consultez les guides d'assistance sur les proxies.
Configuration
L'enregistreur lit sa configuration dans les mêmes attributs de la balise <script> que le tracker principal. La plupart des options sont héritées automatiquement ; celles ci-dessous sont propres à l'enregistrement.
data-rrweb-src (facultatif)
Remplace l'URL que l'enregistreur utilise pour charger rrweb. Par défaut : https://cdn.jsdelivr.net/npm/rrweb@2/dist/rrweb.min.js.
<script defer data-fl-website-id="flid_******" data-rrweb-src="/js/rrweb.min.js" src="/js/recording.js"></script>Utile lorsque votre CSP interdit cdn.jsdelivr.net, ou lorsque vous voulez héberger rrweb vous-même pour éviter les requêtes tierces.
data-recording-sample (facultatif)
N'enregistre qu'un pourcentage des sessions. Accepte un nombre entier 0–100.
- Par défaut :
100: enregistre chaque session. Omettez l'attribut pour un enregistrement complet. - Exemple :
data-recording-sample="30"enregistre ~30 % des sessions.
<script defer data-fl-website-id="flid_******" data-recording-sample="30" src="https://cdn.flowsery.com/recording.js"></script>La décision est déterministe pour chaque session : un visiteur est enregistré ou ignoré de façon cohérente pendant toute sa session, d'un rechargement à l'autre et d'une navigation à l'autre, de sorte que vous n'obtenez jamais de visites à moitié enregistrées. Les sessions non échantillonnées ne téléchargent pas du tout l'enregistreur. Consultez la section Échantillonnage pour savoir comment cela se combine avec l'échantillonnage de l'analyse IA.
data-ai-sample (facultatif)
Parmi les sessions que vous enregistrez, n'en envoie qu'un pourcentage à l'analyse de session par IA. Accepte un nombre entier 0–100.
- Par défaut :
100: analyse chaque session enregistrée. - Exemple :
data-ai-sample="50"envoie ~50 % des sessions enregistrées à l'analyse IA.
<script defer data-fl-website-id="flid_******" data-recording-sample="30" data-ai-sample="50" src="https://cdn.flowsery.com/recording.js"></script>L'enregistreur transmet ce taux à Flowsery dans la poignée de main recording_start ; le serveur le stocke sur l'enregistrement et l'applique au moment où l'analyse est mise en file d'attente (le navigateur est alors parti depuis longtemps). Consultez la section Échantillonnage.
Niveaux de confidentialité
Le mode de confidentialité est décidé côté serveur et transmis à l'enregistreur dans la réponse à recording_start. Tous les sites utilisent actuellement balanced, et le tableau de bord ne propose aucun réglage pour le changer. Modes disponibles :
- balanced (par défaut), masque les champs de mot de passe, d'e-mail et de téléphone. Les autres champs et le texte sont enregistrés tels quels.
- strict : masque tous les champs et tout le contenu textuel, bloque
<video>,<audio>et<canvas>, désactive l'enregistrement du canvas. - relaxed : aucun masquage. À utiliser uniquement pour des applications internes dont vous maîtrisez les saisies.
Pour obtenir un autre mode sur une page, il faudrait post-traiter les enregistrements côté serveur ; le script applique ce que le serveur renvoie.
Échantillonnage
Sur les sites à fort trafic, il est rarement nécessaire d'enregistrer chaque visite. Flowsery échantillonne en deux étapes indépendantes, toutes deux définies sur le script (ou le SDK npm): il n'y a rien à configurer dans le tableau de bord :
- Taux d'échantillonnage de l'enregistrement: la part des sessions qui sont réellement enregistrées. Se définit avec
data-recording-sample(ou l'option SDKrecordingSampleRate),0–100, par défaut100. C'est le navigateur qui décide, si bien que les sessions non échantillonnées ne téléchargent jamais l'enregistreur. - Taux d'échantillonnage de l'analyse IA: la part des sessions déjà enregistrées qui sont envoyées à l'analyse de session par IA. Se définit avec
data-ai-sample(ou l'option SDKaiSampleRate),0–100, par défaut100. L'enregistreur transmet ce taux à Flowsery dans la poignée de mainrecording_startet le serveur l'applique par enregistrement, car l'analyse IA s'exécute après la fermeture de la page.
Les deux se multiplient. Avec un taux d'enregistrement de 30 % et un taux d'IA de 50 %, ~30 % des sessions sont enregistrées et ~15 % (30 % × 50 %) obtiennent un verdict d'IA, les autres restent entièrement rejouables, mais ne sont simplement pas analysées par IA.
L'échantillonnage est déterministe, et non aléatoire : la décision d'enregistrement dépend de la session, si bien qu'un visiteur est enregistré (ou non) de façon cohérente pendant toute sa session et d'un rechargement à l'autre. Les valeurs par défaut de 100 conservent le comportement d'origine, tout enregistrer et tout analyser, de sorte que rien ne change tant que vous n'abaissez pas un taux.
Fonctionnement
- Le script lit
data-fl-website-iddans sa propre balise et récupère les UID du visiteur et de la session dans les cookies posés par le tracker principal (_fs_vid,_fs_sid). - Il envoie
recording_starten POST à/events. Si le serveur refuse (enregistrement désactivé, quota dépassé, etc.), le script s'arrête. - En cas d'acceptation, il charge rrweb et commence à capturer les événements dans un tampon en mémoire.
- Toutes les 15 secondes (ou plus tôt si le tampon dépasse 500 événements / 256 Ko), le tampon est converti en JSON Lines → compressé en gzip → encodé en base64 → envoyé en POST comme
recording_chunk. Le serveur stocke les fragments dans R2 et agrège les métriques (nombre d'événements, indicateurs de clic, de saisie, d'erreur et de clic de rage, durée) sur la ligne de l'enregistrement. - Lors de l'événement
pagehide/beforeunload, un dernier fragment est envoyé avecfinalize: truevia un transport résistant au déchargement de la page,navigator.sendBeaconpour les configurations proxifiées de même origine, ou une requêtefetchaveckeepalivepour les configurations directes (cross-origin), afin que le dernier fragment survive à la destruction de la page. Le serveur passe le statut de l'enregistrement àreadypour qu'il apparaisse dans la liste des enregistrements du tableau de bord.
Compatibilité navigateur
- Chrome/Edge 80+, Firefox 113+, Safari 16.4+ : prise en charge complète, compression gzip via
CompressionStream. - Anciennes versions de Safari / Firefox : l'enregistreur se rabat sur des fragments non compressés. Ils sont stockés, mais la lecture dans le tableau de bord exige l'encodage gzip, donc les enregistrements des anciens navigateurs ne se rejoueront pas tant que le décodeur ne les prendra pas en charge.
- Navigation privée de Safari :
sessionStorageest propre à chaque onglet ; un nouvel UID d'enregistrement est généré à chaque ouverture d'onglet. Pour le reste, tout fonctionne. - Mode sans cookies (
data-cookielesssur le tracker principal) : l'enregistrement est désactivé, car il n'y a aucun UID de visiteur ou de session à rattacher.
Coût et performances
- Réseau : une session typique pèse 50 à 500 Ko compressés, bien moins qu'une vidéo. Les fragments sont envoyés toutes les 15 s sur une connexion
keepalive, ou via la Beacon API au déchargement de la page. - CPU : rrweb exécute un MutationObserver au repos, mesurable mais bien en dessous de 1 % de CPU sur des pages typiques. Le délestage via
requestIdleCallbackest intégré à rrweb 2.x. - Confidentialité : l'enregistreur respecte
Do Not Trackuniquement sidata-respect-dnt="true"est défini. Sinon, il enregistre tous les visiteurs qui atteignentrecording_start.
Désactiver l'enregistrement
Trois options :
- Globalement : désactivez l'enregistrement dans les paramètres du site. Le serveur rejettera
recording_startet le script s'arrêtera. - Par page : n'incluez pas la balise
<script src="/js/recording.js">. - Par visiteur : définissez
localStorage.setItem('flowsery_ignore', 'true'), le même mécanisme d'exclusion que celui du tracker principal.
Dépannage
L'onglet Enregistrements est vide
- Vérifiez que l'enregistrement est activé pour le site.
- Ouvrez les DevTools → Réseau. Vous devriez voir un POST
recording_startréussi, suivi de POSTrecording_chunkréguliers. - Vérifiez la réponse de
recording_start: siaccepted: false, le script s'arrête ; la réponse indique aussi pourquoi (quota dépassé, enregistrement désactivé).
"Cet enregistrement est trop court pour être rejoué"
L'enregistrement existe mais contient moins de 2 événements. Causes fréquentes :
- Le visiteur a fermé l'onglet avant l'envoi du premier fragment.
- Un bloqueur de publicité a empêché le chargement de rrweb. Cherchez des erreurs CSP ou réseau dans la console.
CompressionStreamétait absent et l'encodage de repli a stocké un fragment que le lecteur du tableau de bord ne sait pas encore décoder.
L'enregistrement se charge mais le contournement via mon reverse proxy ne s'applique pas
Assurez-vous que le script est servi exactement depuis /js/recording.js. L'expression régulière de déduction automatique reconnaît script.js, main.js et recording.js (avec un suffixe .hash.js facultatif) ; les autres chemins se rabattent sur l'hôte d'analyse codé en dur. Si vous devez servir le script depuis un autre chemin, définissez explicitement data-api="https://yourdomain.com/api".