Introdução
O CookiePilot é uma plataforma de gestão de consentimento (CMP), em conformidade com o RGPD, com a Lei n.º 41/2004 (que transpõe a diretiva ePrivacy) e com o Google Consent Mode v2. Em Portugal, o cumprimento destas regras é fiscalizado pela CNPD (Comissão Nacional de Proteção de Dados).
Para quem é
- Donos de sites: instalação sem escrever código.
- Programadores: API, eventos, integrações com o GTM.
- Agências: white-label, gestão de vários domínios.
Início rápido
Passo 1: Registo
- Crie uma conta em app.cookiepilot.io/register.
- Adicione o seu domínio no painel e copie a chave da API (formato
cp_live_...).
Passo 2: Instalar o código
A instalação direta são dois scripts no <head>, por esta ordem.
Passo 2a: Consentimento por omissão (stub inline). Cole este primeiro, antes de qualquer outro script (cookiepilot.js, GA, GTM, tags de publicidade e de rastreio):
<script>"use strict";(function(){window.dataLayer=window.dataLayer||[];var d={ad_storage:"denied",ad_user_data:"denied",ad_personalization:"denied",analytics_storage:"denied",functionality_storage:"denied",personalization_storage:"denied",security_storage:"granted",wait_for_update:500},h=false;try{for(var i=0;i<window.dataLayer.length;i++){var x=window.dataLayer[i];if(x&&x[0]==="consent"&&x[1]==="default"){h=true;break}}}catch(err){}if(!h&&window.dataLayer.length)window.dataLayer.unshift(["consent","default",d]);window.gtag=function(){window.dataLayer.push(arguments)};if(!h)window.gtag("consent","default",d);var a=document.cookie.match(/(^|)cookiepilot_consent=([^;]+)/);if(a){try{var e=JSON.parse(decodeURIComponent(a[2]));window.gtag("consent","update",{analytics_storage:e.analytics?"granted":"denied",ad_storage:e.marketing?"granted":"denied",ad_user_data:e.marketing?"granted":"denied",ad_personalization:e.marketing?"granted":"denied",functionality_storage:e.preferences?"granted":"denied",personalization_storage:e.preferences?"granted":"denied",security_storage:"granted"})}catch(err){}}})();</script>
Este snippet inline define imediatamente todas as categorias como denied (com wait_for_update: 500), para que o estado por omissão do Google Consent Mode v2 esteja pronto antes de tudo o resto carregar. Para um visitante que regressa, lê o consentimento guardado diretamente do cookie e dispara um consent update.
Passo 2b: Script do banner. Adicione este logo a seguir ao stub inline:
<!-- CookiePilot -->
<script async src="https://cdn.cookiepilot.io/cookiepilot.js" data-cpkey="TWOJ_KLUCZ"></script>
Passo 3: Configurar o banner
No painel: Domínio → Configuração → Aparência:
- posição do banner (topo, fundo, modal),
- cores e textos,
- um botão flutuante "Definições de cookies" para visitantes que regressam.
Integração com o Google Tag Manager
Através do GTM instala o CookiePilot com uma única tag Custom HTML que define o estado de consentimento por omissão e carrega o banner na fase mais inicial do GTM. Não precisa de um ficheiro stub separado nem de uma segunda tag.
Tag: CookiePilot - Consent Init + Banner
No GTM, crie uma tag Custom HTML (Tags → Nova → HTML personalizado) e cole:
<script>"use strict";
(function() {
window.dataLayer=window.dataLayer||[];var d={ad_storage:"denied",ad_user_data:"denied",ad_personalization:"denied",analytics_storage:"denied",functionality_storage:"denied",personalization_storage:"denied",security_storage:"granted",wait_for_update:500},h=false;try{for(var i=0;i<window.dataLayer.length;i++){var x=window.dataLayer[i];if(x&&x[0]==="consent"&&x[1]==="default"){h=true;break}}}catch(err){}if(!h&&window.dataLayer.length)window.dataLayer.unshift(["consent","default",d]);window.gtag=function(){window.dataLayer.push(arguments)};if(!h)window.gtag("consent","default",d);var a=document.cookie.match(/(^|)cookiepilot_consent=([^;]+)/);if(a){try{var e=JSON.parse(decodeURIComponent(a[2]));window.gtag("consent","update",{analytics_storage:e.analytics?"granted":"denied",ad_storage:e.marketing?"granted":"denied",ad_user_data:e.marketing?"granted":"denied",ad_personalization:e.marketing?"granted":"denied",functionality_storage:e.preferences?"granted":"denied",personalization_storage:e.preferences?"granted":"denied",security_storage:"granted"})}catch(err){}}
var s = document.createElement('script');
s.src = 'https://cdn.cookiepilot.io/cookiepilot.js?cpkey=' + encodeURIComponent('TWOJ_KLUCZ');
document.head.appendChild(s);
})();
</script>
Acionador: Consent Initialization - All Pages. A tag deve disparar uma vez por página. As tags Google (GA4, Google Ads), o Facebook Pixel e outras tags de marketing NÃO usam o acionador Consent Initialization; disparam mais tarde (Consent Checks ou um acionador dependente do consentimento). Guarde a tag e publique o contentor do GTM.
Ordem e acionadores
| Ordem | Tag | Acionador |
|---|---|---|
| 1 | CookiePilot - Consent Init + Banner | Consent Initialization - All Pages |
| 2 | GA4, Google Ads, UET | All Pages (o Consent Mode trata do consentimento) |
| 3 | Facebook Pixel, TikTok, LinkedIn, etc. | Custom Event cookiepilot_consent_update + condição de consentimento (ver abaixo) |
Tags não Google (Facebook Pixel, TikTok, LinkedIn)
O Google Consent Mode cobre apenas as tags Google. Para todos os outros scripts, o widget envia um evento para o dataLayer a cada alteração do consentimento:
dataLayer.push({
event: 'cookiepilot_consent_update',
cookiepilot_consent: {
necessary: true,
analytics: true,
marketing: true,
preferences: false
}
});
O evento dispara também em cada visita de um utilizador que regressa (quando o widget lê o cookie de consentimento), pelo que o acionador do GTM funciona em todas as visitas, não só na primeira decisão.
Padrão partilhado (faça isto uma vez)
Configura estes três elementos uma vez e depois reutiliza-os para todas as tags não Google.
- Acionador (Triggers → New → Custom Event): Event name
cookiepilot_consent_update. Sem condições, sem "Once per page" (a tag tem de poder disparar de novo após uma decisão alterada). - Data Layer Variable para cada categoria que usa:
- Name
cookiepilot_consent.marketing→ variável, p. ex.dlv.cp_marketing - Name
cookiepilot_consent.analytics→ variável, p. ex.dlv.cp_analytics - Name
cookiepilot_consent.preferences→ variável, p. ex.dlv.cp_preferences
- Name
- Trigger Group ou uma condição no acionador:
dlv.cp_marketing equals true(para tags de marketing) ou o campo relevante.
Em cada um dos exemplos abaixo, o Trigger é o mesmo Custom Event com uma condição adicionada na variável certa.
Facebook Pixel
Tag no GTM: Tags → New → Custom HTML.
<script>
!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
document,'script','https://connect.facebook.net/en_US/fbevents.js');
fbq('init', 'YOUR_PIXEL_ID');
fbq('track', 'PageView');
</script>
- Acionador:
cookiepilot_consent_update+ condiçãodlv.cp_marketing equals true. - Opções de disparo da tag: Once per page.
Opcionalmente, para conformidade total com o Facebook Limited Data Use, adicione uma segunda tag que chame fbq('consent','revoke') com o acionador dlv.cp_marketing equals false.
TikTok Pixel
Tag no GTM: Tags → New → Custom HTML.
<script>
!function (w, d, t) {
w.TiktokAnalyticsObject=t;var ttq=w[t]=w[t]||[];ttq.methods=["page","track","identify","instances","debug","on","off","once","ready","alias","group","enableCookie","disableCookie","holdConsent","revokeConsent","grantConsent"],ttq.setAndDefer=function(t,e){t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}};for(var i=0;i<ttq.methods.length;i++)ttq.setAndDefer(ttq,ttq.methods[i]);ttq.instance=function(t){for(var e=ttq._i[t]||[],n=0;n<ttq.methods.length;n++)ttq.setAndDefer(e,ttq.methods[n]);return e},ttq.load=function(e,n){var r="https://analytics.tiktok.com/i18n/pixel/events.js",o=n&&n.partner;ttq._i=ttq._i||{},ttq._i[e]=[],ttq._i[e]._u=r,ttq._t=ttq._t||{},ttq._t[e]=+new Date,ttq._o=ttq._o||{},ttq._o[e]=n||{};n=document.createElement("script");n.type="text/javascript",n.async=!0,n.src=r+"?sdkid="+e+"&lib="+t;e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(n,e)};
ttq.load('YOUR_TIKTOK_PIXEL_ID');
ttq.grantConsent();
ttq.page();
}(window, document, 'ttq');
</script>
- Acionador:
cookiepilot_consent_update+ condiçãodlv.cp_marketing equals true. - Opções de disparo da tag: Once per page.
ttq.grantConsent() é a nova API do TikTok (introduzida em 2024). Sem ela, o TikTok recebe dados com hash sem consentimento, o que viola os termos.
LinkedIn Insight Tag
<script type="text/javascript">
_linkedin_partner_id = "YOUR_LINKEDIN_PARTNER_ID";
window._linkedin_data_partner_ids = window._linkedin_data_partner_ids || [];
window._linkedin_data_partner_ids.push(_linkedin_partner_id);
</script>
<script type="text/javascript">
(function(l) {
if (!l){window.lintrk = function(a,b){window.lintrk.q.push([a,b])};
window.lintrk.q=[]}
var s = document.getElementsByTagName("script")[0];
var b = document.createElement("script");
b.type = "text/javascript";b.async = true;
b.src = "https://snap.licdn.com/li.lms-analytics/insight.min.js";
s.parentNode.insertBefore(b, s);})(window.lintrk);
</script>
- Acionador:
cookiepilot_consent_update+ condiçãodlv.cp_marketing equals true. - Opções de disparo da tag: Once per page.
Hotjar
<script>
(function(h,o,t,j,a,r){
h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
h._hjSettings={hjid:YOUR_HOTJAR_ID,hjsv:6};
a=o.getElementsByTagName('head')[0];
r=o.createElement('script');r.async=1;
r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
a.appendChild(r);
})(window,document,'https://static.hotjar.com/c/hotjar-',".js?sv=");
</script>
- Acionador:
cookiepilot_consent_update+ condiçãodlv.cp_analytics equals true. - Opções de disparo da tag: Once per page.
O Hotjar entra em analytics, não em marketing (mede comportamento, não anúncios). Verifique a sua própria política de cookies, algumas empresas classificam o Hotjar de outra forma.
Microsoft Clarity
<script type="text/javascript">
(function(c,l,a,r,i,t,y){
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
})(window, document, "clarity", "script", "YOUR_CLARITY_PROJECT_ID");
</script>
- Acionador:
cookiepilot_consent_update+ condiçãodlv.cp_analytics equals true. - Opções de disparo da tag: Once per page.
Pinterest Tag
<script>
!function(e){if(!window.pintrk){window.pintrk = function () {
window.pintrk.queue.push(Array.prototype.slice.call(arguments))};var
n=window.pintrk;n.queue=[],n.version="3.0";var
t=document.createElement("script");t.async=!0,t.src=e;var
r=document.getElementsByTagName("script")[0];
r.parentNode.insertBefore(t,r)}}("https://s.pinimg.com/ct/core.js");
pintrk('load', 'YOUR_PINTEREST_TAG_ID');
pintrk('page');
</script>
- Acionador:
cookiepilot_consent_update+ condiçãodlv.cp_marketing equals true. - Opções de disparo da tag: Once per page.
Microsoft Ads (UET)
O UET suporta o Google Consent Mode desde o final de 2023, pelo que não precisa de um acionador Custom Event. Adicione a tag da forma padrão (All Pages, Once per page) e o UET lê o ad_storage do próprio GCM, que o widget define.
Mapeamento de categorias (resumo)
| Tag | Categoria | Campo em cookiepilot_consent |
|---|---|---|
| Facebook Pixel | marketing | marketing |
| TikTok Pixel | marketing | marketing |
| LinkedIn Insight | marketing | marketing |
| marketing | marketing | |
| Hotjar | analytics | analytics |
| Microsoft Clarity | analytics | analytics |
| Mixpanel, Amplitude | analytics | analytics |
| Intercom, Drift, Crisp | preferences | preferences |
| GA4, Google Ads, UET | (GCM, sem acionador) | tratado por gtag('consent','update') |
Referência da API
O CookiePilot expõe o objeto window.CookiePilot:
| Método | Descrição |
|---|---|
CookiePilot.getConsent() | O estado atual do consentimento, ou null se nenhuma decisão foi tomada. |
CookiePilot.acceptAll() | Consentir todas as categorias. |
CookiePilot.rejectAll() | Rejeita tudo exceto necessary. |
CookiePilot.updateConsent(partial) | Atualiza categorias selecionadas, p. ex. { analytics: true }. |
CookiePilot.showSettings() | Abre o modal de preferências. |
CookiePilot.hideSettings() | Fecha o modal de preferências. |
CookiePilot.showMyConsent() / hideMyConsent() | Mostra/oculta o botão flutuante. |
Exemplo
const consent = CookiePilot.getConsent();
// { necessary: true, analytics: true, marketing: false, preferences: false }
CookiePilot.updateConsent({ analytics: true });
document.getElementById('cookie-settings').addEventListener('click', () => {
CookiePilot.showSettings();
});
Ligação "Gerir cookies" no rodapé
<a href="#" onclick="CookiePilot.showSettings(); return false;">Gerir cookies</a>
Eventos JavaScript
O widget dispara um evento nativo cookiepilot:consent no window. O listener tem de ser registado antes de o widget carregar se quiser apanhar o evento para um visitante que regressa (o disparo ocorre de imediato assim que o widget arranca):
<script>
window.addEventListener('cookiepilot:consent', (e) => {
if (e.detail.marketing) {
fbq('init', 'YOUR_PIXEL_ID');
}
});
</script>
<script src="https://cdn.cookiepilot.io/cookiepilot.js" data-cpkey="TWOJ_KLUCZ"></script>
e.detail contém o mesmo payload que getConsent(). Para integrações baseadas no GTM, use o evento do dataLayer descrito acima em vez deste, porque o dataLayer é um array persistente e o GTM apanha eventos históricos.
Categorias de consentimento
| Categoria | Descrição | Por omissão |
|---|---|---|
necessary | Necessários para o site funcionar | Sempre ativo |
analytics | Estatísticas e analítica | Requer consentimento |
marketing | Publicidade e remarketing | Requer consentimento |
preferences | Personalização, idioma | Requer consentimento |
Mapeamento para o Google Consent Mode
| Categoria CookiePilot | Campos do Consent Mode |
|---|---|
analytics | analytics_storage |
marketing | ad_storage, ad_user_data, ad_personalization |
preferences | functionality_storage, personalization_storage |
| (sempre) | security_storage: granted |
Google Consent Mode v2
A versão 2 acrescentou ad_user_data e ad_personalization (obrigatórios desde março de 2024 na UE/EEE para a publicidade do Google).
| Parâmetro | Descrição |
|---|---|
ad_storage | Cookies de publicidade |
analytics_storage | Cookies de analítica |
ad_user_data | Envio de dados do utilizador para o Google |
ad_personalization | Personalização de anúncios |
functionality_storage | Cookies funcionais |
personalization_storage | Cookies de personalização |
security_storage | Sempre granted |
Como funciona:
- O stub define todos os campos como
deniedde forma síncrona, comwait_for_update: 500. - Após a decisão do utilizador, o widget dispara
gtag('consent', 'update', {...})usando o mapeamento acima. - Para um visitante que regressa, o passo 2 dispara de imediato assim que o widget arranca, com base no cookie.
Configuração da aparência
No painel: Domínio → Configuração:
- Aparência: posição, cores, disposição (BAR / BOX / MODAL).
- Textos: cabeçalho, descrição, rótulos dos botões, descrições das categorias. 13 idiomas (EN, PL, DE, FR, ES, IT, NL, PT, SV, CS, RO, EL, HU).
- Botão de consentimento: um botão flutuante "Definições de cookies" mostrado após a primeira decisão (canto inferior esquerdo/direito).
- CSS personalizado: um campo para os seus próprios estilos. O widget renderiza no Shadow DOM, por isso os seletores CSS do documento principal não funcionam. Use apenas este campo.
Acessibilidade (WCAG 2.1 AA)
- ✅ Navegação por teclado (Tab, Shift+Tab, Enter, Escape).
- ✅ Etiquetas ARIA, role="dialog", aria-modal.
- ✅ Focus trap no modal.
- ✅ Suporte a leitores de ecrã (live regions na mudança de estado).
- ✅ Design responsivo.
Integrações
WordPress
Temos um plugin oficial: CookiePilot no WordPress.org.
- Administração do WordPress → Plugins → Adicionar novo → procure "CookiePilot".
- Instale e ative.
- Definições → CookiePilot → cole a chave da API a partir do painel.
O plugin insere ele próprio o stub e a tag no <head> (na ordem correta, à frente dos outros scripts) e disponibiliza um shortcode [cookiepilot_settings] para uma ligação "Gerir cookies" no rodapé.
Se preferir não usar o plugin, use o "Insert Headers and Footers" e cole o snippet do Passo 2 do Início rápido na secção Header.
Shopify
- Loja → Temas → Editar código.
- Em
theme.liquid, cole o snippet antes de</head>.
Next.js
// app/layout.tsx
import Script from 'next/script';
export default function RootLayout({ children }) {
return (
<html>
<head>
<Script
src="https://cdn.cookiepilot.io/cookiepilot.js"
data-cpkey="TWOJ_KLUCZ"
strategy="beforeInteractive"
/>
</head>
<body>{children}</body>
</html>
);
}
strategy="beforeInteractive" garante que o script do banner corre cedo. Lembre-se de que o stub inline do Passo 2a (consentimento por omissão) é adicionado à parte, no <head> à frente deste script, por exemplo através de next/script com dangerouslySetInnerHTML ou diretamente em app/layout.tsx.
FAQ
O script atrasa o site?
O bundle tem cerca de 12 KB comprimido em gzip e carrega de forma assíncrona. Sem impacto nos Core Web Vitals.
Durante quanto tempo é guardado o consentimento?
O cookie de decisão do utilizador: 365 dias por omissão (configurável no painel). Eventos de analítica: 2 anos (TTL do ClickHouse).
O evento cookiepilot_consent_update dispara para visitantes que regressam?
Sim. O widget lê o cookie no arranque e envia o evento para o dataLayer. O acionador Custom Event no GTM dispara em cada visita, não só na primeira decisão.
Onde reporto um problema?
kontakt@cookiepilot.io ou o chat no painel.
Lista de verificação de testes pós-instalação
Depois de instalar o CookiePilot, verifique a configuração antes de lançar campanhas publicitárias.
1. Teste antes de o utilizador dar consentimento
- Abra o site em modo de navegação anónima e limpe os cookies do domínio.
- Abra o DevTools → Network e recarregue a página.
- Antes de clicar em consentir, confirme que:
- não são criados cookies de analítica/marketing, p. ex.
_ga,_gcl_*,_fbp,_ttp, - as tags de marketing não enviam pedidos para o Meta/TikTok/LinkedIn antes do consentimento de marketing,
- o
dataLayertem o estado por omissãodeniedparaad_storage,ad_user_data,ad_personalizationeanalytics_storage.
- não são criados cookies de analítica/marketing, p. ex.
2. Teste depois de aceitar o consentimento
- Clique em "Aceitar tudo".
- No DevTools, verifique se o evento
cookiepilot_consent_updateapareceu. - Para as tags Google, verifique no GTM Preview / Tag Assistant se o Consent Mode mudou o estado para
grantednas categorias relevantes. - Para o GA4, verifique no DebugView se os eventos começam a chegar após o consentimento.
- Para o Meta Pixel / TikTok / LinkedIn, verifique se as tags disparam apenas após o evento
cookiepilot_consent_updatee a condição de consentimento de marketing.
3. Teste a rejeição do consentimento
- Limpe os cookies e recarregue a página.
- Clique em "Rejeitar tudo".
- Confirme que os cookies e pedidos de marketing continuam a não ser acionados.
- Confirme que as funcionalidades essenciais do site continuam a funcionar.
4. Erros comuns
- A tag do GA4/Google Ads dispara em
Consent Initializationem vez de um acionador posterior. - O Meta Pixel ou o TikTok Pixel não têm condição em
cookiepilot_consent.marketing. - Um rastreador antigo, codificado à mão, ainda está no
<head>antes do CookiePilot. - A documentação ou o modelo ainda têm um URL de script desatualizado ou um antigo atributo de identificador em vez do atual
cookiepilot.jscomdata-cpkey.
Evidência de consentimento, exportações e DSAR
O CookiePilot regista eventos de consentimento para que possa reconstruir o contexto de uma decisão do visitante. Um registo pode incluir a hora do evento, o tipo de evento, o domínio, o URL da página ou da origem, a versão do consentimento, as categorias e a consent string quando disponível, o endereço IP anonimizado, o hash do user-agent, o tipo de dispositivo e o navegador.
Exportações
- Prova de consentimento por visitante: JSON, CSV ou HTML imprimível.
- Registo de auditoria do domínio: CSV ou JSON para um intervalo de datas selecionado.
- As exportações estão limitadas à sua organização e aos domínios a que tem acesso.
Fluxo de DSAR
Um Owner ou Admin pode iniciar um pedido de acesso a dados a partir de uma linha de consentimento ou da página DSAR no painel. O painel encontra os eventos do visitante, mostra o intervalo e permite descarregar ficheiros de prova. Um pedido de eliminação exige um motivo e fica registado no rasto de atividade da organização.
Limites
As exportações de auditoria do domínio usam o intervalo de datas selecionado e podem ser truncadas para conjuntos de resultados muito grandes. A retenção do registo de consentimentos segue o plano ativo e a política da conta, por isso a documentação pública não promete um número fixo de anos.