Consentimento de Cookies para Next.js, Gatsby e Sites Estáticos: Guia de Integração para Desenvolvedores
O Problema do Consentimento em Sites Estáticos
Frameworks modernos de JavaScript como Next.js, Gatsby e Nuxt.js introduziram uma mudança de paradigma em como as páginas web são construídas e entregues. As páginas são pré-renderizadas em tempo de build ou no servidor e depois hidratadas no cliente. Isso cria um desafio único para o consentimento de cookies: o banner de consentimento precisa estar pronto antes que qualquer script de rastreamento seja executado, mas a própria página pode já estar renderizada e em cache na borda.
Os CMPs tradicionais foram projetados para páginas em PHP renderizadas no servidor ou HTML simples, em que o documento é carregado linearmente de cima para baixo. Em um mundo de frameworks com code splitting, lazy loading e streaming server-side rendering, essas suposições deixam de valer. Acertar o consentimento nesses ambientes exige entender o pipeline de renderização.
Por que o Timing Importa Mais do que Você Imagina
Em uma página HTML padrão, colocar o script do CMP no <head> antes de outros scripts é simples. No Next.js App Router ou Gatsby, a situação é mais complexa:
- O HTML pré-renderizado chega primeiro: O navegador recebe o HTML completo do CDN ou servidor. Se houver scripts inline ou tags de terceiros embutidos nesse HTML, eles podem ser executados antes que sua lógica de consentimento seja carregada.
- Lacuna de hidratação: A hidratação do React acontece depois que o HTML é pintado. Se o seu componente de consentimento for um componente React, ele não existe em estado funcional até a hidratação ser concluída. Durante essa lacuna, tags do Google ou scripts de analytics podem disparar sem consentimento.
- Complicações de cache na borda: Se você usa ISR (Incremental Static Regeneration) ou funções de edge, o HTML é armazenado em cache. Você não pode injetar dinamicamente lógica dependente de consentimento em HTML em cache sem um mecanismo no lado do cliente.
O princípio central é este: o consentimento precisa ser estabelecido no nível do script, não no nível do componente. Um componente React que renderiza um banner de consentimento chega tarde demais se só se torna interativo após a hidratação.
Integração com Next.js App Router
O Next.js 13+ com o App Router introduziu uma nova forma de lidar com scripts. Aqui está a abordagem recomendada para integração de consentimento:
Passo 1: Carregar o Script do CMP no Layout Raiz
Use o componente Script do Next.js com a estratégia beforeInteractive no seu layout.tsx raiz. Isso diz ao Next.js para injetar o script no documento HTML inicial, antes do início da hidratação:
A estratégia beforeInteractive é crítica. A estratégia padrão afterInteractive carrega scripts após a hidratação, o que é tarde demais para o consentimento. Com beforeInteractive, o script do CMP é incluído no HTML renderizado no servidor e executa conforme a página é carregada.
Passo 2: Definir o Consentimento Padrão Antes das Tags do Google
Antes do seu snippet do Google Tag Manager ou gtag.js, inclua um script inline que defina os estados de consentimento padrão. Isso garante que, mesmo que o GTM carregue antes de o banner do CMP aparecer, ele respeite os padrões negados:
Esse script inline deve ser colocado no <head> do seu layout raiz, antes dos scripts do CMP e do GTM. No Next.js, você pode usar uma tag <script> normal dentro do elemento <head> do seu layout para esse fim.
Passo 3: Tratar Mudanças de Rota
Em navegação de single-page application, o script do CMP é carregado uma vez, mas as mudanças de rota não disparam um reload completo da página. Seu CMP precisa persistir nas navegações no lado do cliente. O FlexyConsent lida com isso automaticamente — uma vez carregado, permanece ativo em todas as mudanças de rota sem reinicialização.
Integração com Next.js Pages Router
Para projetos que ainda usam o Pages Router, a abordagem é semelhante, mas usa _document.tsx em vez do layout raiz. Coloque o script do CMP no componente <Head> da sua classe Document personalizada. A estratégia beforeInteractive funciona da mesma forma no Pages Router.
A principal diferença é que _document.tsx só é renderizado no servidor, então qualquer lógica de consentimento aqui é garantida no payload HTML inicial.
Integração com Sites Estáticos em Gatsby
O Gatsby gera HTML totalmente estático em tempo de build. Não há renderização no servidor em tempo de requisição, o que simplifica alguns aspectos, mas complica outros:
- Use
gatsby-ssr.tsxpara injetar o script do CMP no<head>de cada página. A APIonRenderBodypermite adicionar scripts ao head que estarão presentes em cada arquivo HTML estático. - Evite plugins do Gatsby que fazem lazy-load do consentimento: Alguns plugins da comunidade encapsulam o consentimento em componentes React que só montam após a hidratação. Isso cria a lacuna de timing discutida anteriormente.
- Coloque os padrões de consentimento inline: Use
setHeadComponentsemgatsby-ssr.tsxpara adicionar um script inline definindo estados de consentimento padrão. Esse script estará no HTML estático e será executado imediatamente.
A abordagem em tempo de build do Gatsby significa que cada arquivo HTML no seu CDN incluirá o script de consentimento. Isso é, na verdade, ideal — não há lógica de servidor para falhar ou fazer cache incorretamente.
Considerações para Nuxt.js
O Nuxt.js (baseado em Vue) tem seus próprios padrões. No Nuxt 3, use o composable useHead ou a configuração de head em nuxt.config.ts para adicionar o script do CMP globalmente. O Nuxt suporta a opção body: false (que coloca scripts no head) e o atributo async para carregamento não bloqueante.
Para o modo de renderização no servidor do Nuxt, o mesmo princípio se aplica: o script do CMP precisa estar na resposta HTML inicial, não ser injetado dinamicamente por um componente Vue após o mount.
Evitando Layout Shift
Banners de consentimento são notórios por causar Cumulative Layout Shift (CLS), um Core Web Vital que afeta o ranqueamento em SEO. Quando um banner aparece depois que a página é renderizada, ele empurra o conteúdo para baixo ou o sobrepõe de forma inesperada.
Estratégias para minimizar CLS causado por banners de consentimento:
- Use um banner posicionado na parte inferior: Banners na parte inferior da viewport não deslocam o conteúdo da página. Essa é a abordagem mais amigável para CLS.
- Reserve espaço: Se você precisar usar um banner no topo, reserve o espaço vertical no seu CSS para que o layout da página considere o banner antes de ele ser renderizado.
- Evite modais em overlay no carregamento: Paredes de consentimento em tela cheia que aparecem depois que a página foi renderizada causam sensação de instabilidade no layout. Se você precisar de uma parede, renderize-a como parte do estado inicial da página.
- Carregue o CMP de forma síncrona no head: Quando o CMP é carregado como script de bloqueio de renderização no head, o banner pode aparecer como parte da pintura inicial em vez de surgir depois.
A Abordagem Agnóstica de Framework do FlexyConsent
O FlexyConsent foi projetado para funcionar com qualquer framework — ou sem framework algum — atuando no nível do script em vez do nível do componente. Eis por que isso importa:
- Única tag de script assíncrona: Uma única tag
<script>no<head>é tudo de que você precisa. Nada de pacotes npm para instalar, wrappers específicos de framework ou configuração de build. - Padrões de consentimento disparam imediatamente: O script define os padrões do Consent Mode V2 como sua primeira ação, antes de qualquer callback ou manipulação de DOM. Isso significa que as tags do Google respeitam o consentimento desde o primeiro milissegundo.
- Sem dependência de DOM: A lógica de consentimento não espera React, Vue ou Svelte hidratarem. Ela opera independentemente do ciclo de vida do framework.
- Funciona com SSG, SSR, ISR e CSR: Por ser um script simples, funciona de forma idêntica, seja a página gerada estaticamente, renderizada no servidor, regenerada incrementalmente ou renderizada no cliente.
Dica para desenvolvedores: O teste mais simples para verificar a integração correta do CMP é abrir a aba Network do seu navegador, filtrar por domínios do Google e recarregar a página. Nenhuma requisição ao Google deve disparar antes de o comando de padrão de consentimento aparecer no console. Se disparar, seu CMP está carregando tarde demais.
O plano gratuito do FlexyConsent suporta pageviews ilimitadas e funciona com Next.js, Gatsby, Nuxt, Astro, SvelteKit, Remix e HTML puro. A integração é a mesma em todos eles: uma tag de script, colocada corretamente.