Gravação de sessões com o script do Flowsery
A gravação de sessões permite reproduzir o que visitantes reais fizeram no seu site (movimentos do mouse, cliques, preenchimento de formulários, transições de página) adicionando um pequeno script ao seu HTML. O gravador é um bundle JS separado do tracker principal de analytics, então ele só é carregado quando você o ativa.
O gravador é construído sobre o rrweb e envia os seus eventos de mutação do DOM ao Flowsery em chunks comprimidos com gzip. O primeiro chunk é um snapshot completo; os chunks seguintes são incrementais.
Pré-requisitos
- A gravação precisa estar ativada no site no seu painel do Flowsery (
Definições do site → Geral → Gravação de sessões). O servidor rejeita as requisiçõesrecording_startquando ela está desativada. - Você já usa o tracker principal de analytics (
/js/main.js). A gravação usa o mesmodata-fl-website-id, os mesmos cookies de visitante e de sessão e o mesmo endpoint/eventsdo tracker principal.
Início rápido (CDN)
Adicione a tag de script logo depois do tracker principal de analytics:
<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>O gravador aplica as mesmas verificações do tracker principal (detecção de bots, localhost, iframe, file://, autoexclusão) e encerra sem erros quando alguma delas se aplica.
Prefere uma única tag? Adicione o atributo data-recording ao tracker principal e o Flowsery injeta o gravador para você, sem precisar de um segundo <script>:
<script defer data-fl-website-id="flid_******" data-recording src="https://cdn.flowsery.com/main.js"></script>Ativar pelo SDK npm
Se você inicializa o Flowsery pelo SDK npm, ative a gravação com uma única flag em vez de uma tag de script:
import { initFlowsery } from 'flowsery';
await initFlowsery({
websiteId: 'flid_******',
recording: true,
});O SDK carrega o bundle do gravador sob demanda a partir da CDN do Flowsery na primeira inicialização, então o rrweb nunca entra no bundle da sua aplicação. Os eventos de rastreamento continuam passando pelo seu apiBase quando ele está definido. Para gravar apenas uma parcela das sessões, adicione recordingSampleRate, e para analisar por IA apenas uma parcela dessas, adicione aiSampleRate (ambos 0–100, padrão 100): consulte Amostragem. Tudo o que vem a seguir (o pré-requisito no painel, os modos de privacidade, as verificações e o suporte a navegadores) se aplica da mesma forma.
Configuração com proxy reverso (recomendada para produção)
Bloqueadores de anúncios e extensões de proteção contra rastreamento bloqueiam scripts de terceiros e analytics.flowsery.com diretamente. Encaminhar tanto o script quanto o endpoint de eventos pelo seu próprio domínio contorna isso, e os IPs dos visitantes e a precisão continuam intactos.
O gravador deduz automaticamente a base da API a partir do seu próprio <script src>, da mesma forma que o tracker principal. Desde que o bundle de gravação seja servido em /js/recording.js no seu domínio, nenhuma configuração extra é necessária.
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>Outros proxies
O mesmo formato funciona para qualquer proxy reverso. Mapeie os três caminhos:
| Caminho público | Origem |
|---|---|
/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 |
Para guias de proxy específicos por framework (Astro, Caddy, Express, FastAPI, Nginx, PHP, Vue etc.), consulte os guias de proxy no suporte.
Configuração
O gravador lê a sua configuração dos mesmos atributos da tag <script> que o tracker principal. A maioria das opções é herdada automaticamente; as opções abaixo são específicas da gravação.
data-rrweb-src (opcional)
Substitui a URL que o gravador usa para carregar o rrweb. O padrão é 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>Útil quando a sua CSP proíbe cdn.jsdelivr.net ou quando você quer hospedar o rrweb por conta própria para evitar requisições a terceiros.
data-recording-sample (opcional)
Grave apenas uma porcentagem das sessões. Aceita um número inteiro de 0–100.
- Padrão:
100: grava todas as sessões. Omita o atributo para gravação completa. - Exemplo:
data-recording-sample="30"grava ~30% das sessões.
<script defer data-fl-website-id="flid_******" data-recording-sample="30" src="https://cdn.flowsery.com/recording.js"></script>A decisão é determinística por sessão: um visitante é gravado ou ignorado de forma consistente durante toda a sessão, entre recarregamentos e navegações de página, então você nunca obtém visitas gravadas pela metade. Sessões fora da amostra não baixam o gravador por completo. Consulte Amostragem para saber como isso se combina com a amostragem da análise de IA.
data-ai-sample (opcional)
Das sessões que você grava, envie apenas uma porcentagem para a análise de sessão por IA. Aceita um número inteiro de 0–100.
- Padrão:
100: analisa todas as sessões gravadas. - Exemplo:
data-ai-sample="50"envia ~50% das sessões gravadas para a análise de IA.
<script defer data-fl-website-id="flid_******" data-recording-sample="30" data-ai-sample="50" src="https://cdn.flowsery.com/recording.js"></script>O gravador envia essa taxa ao Flowsery no handshake recording_start; o servidor a armazena na gravação e a aplica quando a análise é enfileirada (o navegador já foi embora nesse momento). Consulte Amostragem.
Níveis de privacidade
O modo de privacidade é decidido no servidor e enviado ao gravador na resposta de recording_start. Atualmente todo site recebe balanced, e o painel não tem nenhuma configuração para isso. Modos disponíveis:
- balanced (padrão): mascara os campos de senha, email e telefone. Os outros campos e o texto são gravados como estão.
- strict: mascara todos os campos, mascara todo o conteúdo de texto, bloqueia
<video>,<audio>e<canvas>e desativa a gravação de canvas. - relaxed: sem mascaramento. Use apenas em apps internas em que você controla o que é digitado.
Para ter um modo diferente numa página, você precisaria pós-processar as gravações no servidor; o script respeita o que o servidor retornar.
Amostragem
Em sites de alto tráfego você raramente precisa gravar todas as visitas. O Flowsery faz amostragem em dois estágios independentes, ambos configurados no script (ou no SDK npm): não há nada para definir no painel:
- Taxa de amostragem de gravação: a parcela de sessões que chega a ser gravada. Defina com
data-recording-sample(ou a opçãorecordingSampleRatedo SDK),0–100, padrão100. O navegador decide, então sessões fora da amostra nunca baixam o gravador. - Taxa de amostragem da análise de IA: a parcela das sessões já gravadas que são enviadas para a análise de sessão por IA. Defina com
data-ai-sample(ou a opçãoaiSampleRatedo SDK),0–100, padrão100. O gravador envia isso ao Flowsery no handshakerecording_starte o servidor a aplica por gravação, já que a análise de IA roda depois que a página é fechada.
As duas se multiplicam. Com uma taxa de gravação de 30% e uma taxa de IA de 50%, ~30% das sessões são gravadas e ~15% (30% × 50%) recebem um veredito de IA: o restante continua totalmente reproduzível, apenas sem análise de IA.
A amostragem é determinística, não aleatória: a decisão de gravação é baseada na sessão, então um visitante é gravado (ou não) de forma consistente durante toda a sessão e entre recarregamentos. Os padrões de 100 mantêm o comportamento original, gravar e analisar tudo, então nada muda até você reduzir uma taxa.
Como funciona
- O script lê o
data-fl-website-idda sua própria tag e obtém os UIDs de visitante e de sessão a partir dos cookies definidos pelo tracker principal (_fs_vid,_fs_sid). - Ele envia um POST
recording_startpara/events. Se o servidor rejeitar (gravação desativada, cota excedida etc.), o script para. - Se for aceito, ele carrega o rrweb e começa a capturar eventos num buffer em memória.
- A cada 15 segundos (ou antes, se o buffer passar de 500 eventos / 256 KB), o buffer é convertido em JSON Lines → comprimido com gzip → codificado em base64 → enviado por POST como
recording_chunk. O servidor armazena os chunks no R2 e consolida métricas (contagens de eventos, flags de clique/entrada/erro/rage click, duração) na linha da gravação. - No
pagehide/beforeunload, um chunk final é enviado comfinalize: truepor um transporte à prova de descarregamento,navigator.sendBeaconpara configurações com proxy de mesma origem, ou uma requisiçãofetchcom keepalive para configurações diretas (de origem cruzada): para que o último chunk sobreviva ao encerramento da página. O servidor muda o status da gravação parareadypara que ela apareça na lista de gravações do painel.
Suporte a navegadores
- Chrome/Edge 80+, Firefox 113+, Safari 16.4+: suporte completo, compressão gzip via
CompressionStream. - Safari / Firefox mais antigos: o gravador recorre a chunks sem gzip. Eles são armazenados, mas a reprodução no painel exige a codificação gzip, então as gravações de navegadores mais antigos não serão reproduzidas até que o decodificador passe a suportá-las.
- Modo privado do Safari: o
sessionStorageé por aba; um novo UID de gravação é gerado sempre que uma aba é aberta. Fora isso, funciona. - Modo sem cookies (
data-cookielessno tracker principal): a gravação fica desativada porque não há UID de visitante nem de sessão para associar.
Custo e desempenho
- Rede: uma sessão típica tem de 50 a 500 KB comprimidos; muito menos que um vídeo. Os chunks são enviados a cada 15 s numa conexão
keepaliveou pela Beacon API no descarregamento da página. - CPU: o rrweb executa um MutationObserver ocioso: mensurável, mas bem abaixo de 1% de CPU em páginas típicas. O adiamento via
requestIdleCallbackjá vem integrado no rrweb 2.x. - Privacidade: o gravador respeita o
Do Not Trackapenas quandodata-respect-dnt="true"está definido. Caso contrário, ele grava todos os visitantes que chegam aorecording_start.
Desativar a gravação
Três opções:
- Globalmente: desative a gravação nas definições do site. O servidor vai rejeitar o
recording_starte o script vai parar. - Por página: não inclua a tag
<script src="/js/recording.js">. - Por visitante: defina
localStorage.setItem('flowsery_ignore', 'true'): a mesma exclusão usada pelo tracker principal.
Solução de problemas
A aba Gravações está vazia
- Confirme que a gravação está ativada no site.
- Abra DevTools → Network. Você deve ver um POST
recording_startbem-sucedido seguido de POSTsrecording_chunkperiódicos. - Verifique a resposta de
recording_start: se foraccepted: false, o script para; a resposta também informa o motivo (cota excedida, gravação desativada).
"Gravação curta demais para replay"
A gravação existe, mas tem menos de 2 eventos. Causas comuns:
- O visitante fechou a aba antes que o primeiro chunk pudesse ser enviado.
- Um bloqueador de anúncios impediu o carregamento do rrweb. Verifique o Console em busca de erros de CSP ou de rede.
- O
CompressionStreamnão estava disponível e a codificação alternativa armazenou um chunk que o player do painel ainda não consegue decodificar.
A gravação carrega, mas o desvio pelo meu proxy reverso não funciona
Garanta que o script seja servido exatamente a partir de /js/recording.js. A regex de dedução automática reconhece script.js, main.js e recording.js (com o sufixo opcional .hash.js); outros caminhos recorrem ao host de analytics fixo no código. Se você precisar servir a partir de outro caminho, defina data-api="https://yourdomain.com/api" explicitamente.