getting-started

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ções recording_start quando ela está desativada.
  • Você já usa o tracker principal de analytics (/js/main.js). A gravação usa o mesmo data-fl-website-id, os mesmos cookies de visitante e de sessão e o mesmo endpoint /events do 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úblicoOrigem
/js/main.jshttps://cdn.flowsery.com/main.js
/js/recording.jshttps://cdn.flowsery.com/recording.js
/api/trackhttps://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:

  1. Taxa de amostragem de gravação: a parcela de sessões que chega a ser gravada. Defina com data-recording-sample (ou a opção recordingSampleRate do SDK), 0–100, padrão 100. O navegador decide, então sessões fora da amostra nunca baixam o gravador.
  2. 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ção aiSampleRate do SDK), 0–100, padrão 100. O gravador envia isso ao Flowsery no handshake recording_start e 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

  1. O script lê o data-fl-website-id da 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).
  2. Ele envia um POST recording_start para /events. Se o servidor rejeitar (gravação desativada, cota excedida etc.), o script para.
  3. Se for aceito, ele carrega o rrweb e começa a capturar eventos num buffer em memória.
  4. 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.
  5. No pagehide / beforeunload, um chunk final é enviado com finalize: true por um transporte à prova de descarregamento, navigator.sendBeacon para configurações com proxy de mesma origem, ou uma requisição fetch com 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 para ready para 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-cookieless no 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 keepalive ou 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 requestIdleCallback já vem integrado no rrweb 2.x.
  • Privacidade: o gravador respeita o Do Not Track apenas quando data-respect-dnt="true" está definido. Caso contrário, ele grava todos os visitantes que chegam ao recording_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_start e 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_start bem-sucedido seguido de POSTs recording_chunk periódicos.
  • Verifique a resposta de recording_start: se for accepted: 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 CompressionStream nã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.