Ferramenta gratuita

Gerador de banner de consentimento de cookies

Escolha suas categorias de cookies, escreva o texto, defina a aparência — e copie um banner de consentimento sem dependências para colar em qualquer site. Ele guarda a escolha do visitante, mantém os scripts marcados bloqueados até que a categoria seja aceita e pode ser reaberto por um link no rodapé.

Necessários para o site funcionar. Sempre ativos e nunca pedem consentimento.
Mede como o site é usado para que possa ser melhorado.
Usado para personalizar anúncios e medir campanhas.
Lembra escolhas como idioma, região e layout.

Seu banner de consentimento

Cole isto logo antes da tag de fechamento body, em todas as páginas.

<!-- Cookie consent banner - paste this just before </body> -->
<script>
(function () {
  var CFG = {
  "storageKey": "cookie_consent",
  "position": "bar",
  "theme": "light",
  "accent": "#a6144d",
  "title": "Usamos cookies",
  "message": "Usamos cookies para operar este site, entender como ele é usado e melhorá-lo. Você pode aceitar tudo, recusar o que é opcional ou escolher por categoria.",
  "policyUrl": "https://example.com/privacy",
  "policyLabel": "Leia nossa política de privacidade",
  "accept": "Aceitar tudo",
  "reject": "Recusar opcionais",
  "prefs": "Preferências",
  "save": "Salvar escolhas",
  "categories": [
    {
      "id": "necessary",
      "label": "Estritamente necessários",
      "desc": "Necessários para o site funcionar. Sempre ativos e nunca pedem consentimento.",
      "required": true
    },
    {
      "id": "analytics",
      "label": "Análise",
      "desc": "Mede como o site é usado para que possa ser melhorado.",
      "required": false
    },
    {
      "id": "marketing",
      "label": "Marketing",
      "desc": "Usado para personalizar anúncios e medir campanhas.",
      "required": false
    }
  ]
};
  var KEY = CFG.storageKey;
  var doc = document;
  var box = null;

  function read() {
    try { return JSON.parse(localStorage.getItem(KEY) || 'null'); } catch (e) { return null; }
  }

  function save(consent) {
    consent.necessary = true;
    consent.date = new Date().toISOString();
    try { localStorage.setItem(KEY, JSON.stringify(consent)); } catch (e) {}
    unblock(consent);
    window.dispatchEvent(new CustomEvent('consentchange', { detail: consent }));
    if (typeof window.onConsentChange === 'function') window.onConsentChange(consent);
  }

  // Scripts the site parked behind a category run only once it is granted. Park
  // one by giving its tag type="text/plain" and data-consent="analytics".
  // (Deliberately described, not shown: a literal script tag written out here
  // would close this one early and truncate everything below it.)
  function unblock(consent) {
    var parked = doc.querySelectorAll('script[type="text/plain"][data-consent]');
    for (var i = 0; i < parked.length; i++) {
      var old = parked[i];
      if (!consent[old.getAttribute('data-consent')]) continue;
      var next = doc.createElement('script');
      for (var a = 0; a < old.attributes.length; a++) {
        var at = old.attributes[a];
        if (at.name !== 'type' && at.name !== 'data-consent') next.setAttribute(at.name, at.value);
      }
      next.text = old.text;
      old.parentNode.replaceChild(next, old);
    }
  }

  function styles() {
    var dark = CFG.theme === 'dark';
    var bg = dark ? '#161622' : '#ffffff';
    var fg = dark ? '#f4f4f8' : '#141a47';
    var muted = dark ? 'rgba(244,244,248,.72)' : 'rgba(20,26,71,.7)';
    var line = dark ? 'rgba(255,255,255,.14)' : 'rgba(20,26,71,.12)';
    var el = doc.createElement('style');
    el.textContent = [
      '.cc-root{position:fixed;z-index:2147483000;font:400 14px/1.55 system-ui,-apple-system,Segoe UI,Roboto,sans-serif;color:' + fg + ';box-sizing:border-box}',
      '.cc-root *,.cc-root *::before,.cc-root *::after{box-sizing:inherit}',
      '.cc-card{background:' + bg + ';border:1px solid ' + line + ';box-shadow:0 18px 48px rgba(0,0,0,.18);border-radius:14px;padding:20px}',
      '.cc-bar{left:0;right:0;bottom:0;padding:16px}',
      '.cc-bar .cc-card{display:flex;flex-wrap:wrap;gap:16px;align-items:center;justify-content:space-between;max-width:1120px;margin:0 auto}',
      '.cc-box{left:16px;bottom:16px;max-width:400px}',
      '.cc-modal{inset:0;display:flex;align-items:center;justify-content:center;padding:16px;background:rgba(10,10,20,.5)}',
      '.cc-modal .cc-card{max-width:520px;width:100%}',
      '.cc-title{margin:0 0 6px;font-size:16px;font-weight:700}',
      '.cc-text{margin:0;color:' + muted + '}',
      '.cc-text a{color:' + CFG.accent + ';font-weight:600}',
      '.cc-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px}',
      '.cc-bar .cc-actions{margin-top:0}',
      '.cc-btn{appearance:none;cursor:pointer;border:1px solid ' + line + ';border-radius:999px;padding:9px 18px;font:600 14px inherit;background:transparent;color:' + fg + '}',
      '.cc-btn-main{background:' + CFG.accent + ';border-color:' + CFG.accent + ';color:#fff}',
      '.cc-btn:focus-visible{outline:2px solid ' + CFG.accent + ';outline-offset:2px}',
      '.cc-cats{display:none;margin:14px 0 0;padding:14px 0 0;border-top:1px solid ' + line + '}',
      '.cc-cats.cc-open{display:block}',
      '.cc-cat{display:flex;gap:10px;align-items:flex-start;margin-bottom:12px}',
      '.cc-cat input{margin:3px 0 0;accent-color:' + CFG.accent + '}',
      '.cc-cat strong{display:block;font-size:14px}',
      '.cc-cat span{display:block;color:' + muted + ';font-size:13px}',
      '@media(max-width:640px){.cc-bar .cc-card{display:block}.cc-bar .cc-actions{margin-top:14px}.cc-btn{flex:1 1 auto}}'
    ].join('');
    doc.head.appendChild(el);
  }

  function build() {
    var stored = read() || {};
    var root = doc.createElement('div');
    root.className = 'cc-root cc-' + CFG.position;
    root.setAttribute('role', CFG.position === 'modal' ? 'dialog' : 'region');
    root.setAttribute('aria-label', CFG.title);
    if (CFG.position === 'modal') root.setAttribute('aria-modal', 'true');

    var card = doc.createElement('div');
    card.className = 'cc-card';

    var copy = doc.createElement('div');
    var h = doc.createElement('p');
    h.className = 'cc-title';
    h.textContent = CFG.title;
    var p = doc.createElement('p');
    p.className = 'cc-text';
    p.textContent = CFG.message + ' ';
    if (CFG.policyUrl) {
      var link = doc.createElement('a');
      link.href = CFG.policyUrl;
      link.textContent = CFG.policyLabel;
      p.appendChild(link);
    }
    copy.appendChild(h);
    copy.appendChild(p);

    var cats = doc.createElement('div');
    cats.className = 'cc-cats';
    var inputs = {};
    for (var i = 0; i < CFG.categories.length; i++) {
      var c = CFG.categories[i];
      var row = doc.createElement('label');
      row.className = 'cc-cat';
      var cb = doc.createElement('input');
      cb.type = 'checkbox';
      cb.checked = c.required || stored[c.id] === true;
      cb.disabled = !!c.required;
      var txt = doc.createElement('div');
      var name = doc.createElement('strong');
      name.textContent = c.label;
      var desc = doc.createElement('span');
      desc.textContent = c.desc;
      txt.appendChild(name);
      txt.appendChild(desc);
      row.appendChild(cb);
      row.appendChild(txt);
      cats.appendChild(row);
      inputs[c.id] = cb;
    }
    copy.appendChild(cats);

    var actions = doc.createElement('div');
    actions.className = 'cc-actions';
    function button(label, main, onClick) {
      var b = doc.createElement('button');
      b.type = 'button';
      b.className = 'cc-btn' + (main ? ' cc-btn-main' : '');
      b.textContent = label;
      b.addEventListener('click', onClick);
      actions.appendChild(b);
      return b;
    }
    function decide(granted) {
      var consent = {};
      for (var i = 0; i < CFG.categories.length; i++) {
        var c = CFG.categories[i];
        consent[c.id] = c.required ? true : granted === null ? !!inputs[c.id].checked : granted;
      }
      save(consent);
      close();
    }
    var prefsBtn = button(CFG.prefs, false, function () {
      var open = cats.classList.toggle('cc-open');
      prefsBtn.setAttribute('aria-expanded', open ? 'true' : 'false');
      saveBtn.style.display = open ? '' : 'none';
    });
    prefsBtn.setAttribute('aria-expanded', 'false');
    button(CFG.reject, false, function () { decide(false); });
    button(CFG.accept, true, function () { decide(true); });
    var saveBtn = button(CFG.save, false, function () { decide(null); });
    saveBtn.style.display = 'none';

    card.appendChild(copy);
    card.appendChild(actions);
    root.appendChild(card);
    doc.body.appendChild(root);
    box = root;
  }

  function close() {
    if (box && box.parentNode) box.parentNode.removeChild(box);
    box = null;
  }

  function open() {
    if (!box) build();
  }

  function start() {
    styles();
    var stored = read();
    if (stored) unblock(stored);
    else build();
    window.showConsentPreferences = open;
  }

  if (doc.readyState === 'loading') doc.addEventListener('DOMContentLoaded', start);
  else start();
})();
</script>

Como usar

Três passos até um banner funcionando

1. Cole o trecho

Coloque o código gerado logo antes da tag de fechamento body em todas as páginas. Ele não tem dependências e não adiciona requisições de rede.

2. Deixe seus scripts de rastreamento em espera

Mude o tipo da tag de rastreamento para text/plain e adicione data-consent="analytics". O banner a executa assim que essa categoria for aceita — e nunca antes.

3. Deixe as pessoas mudarem de ideia

Adicione um link no rodapé que chame window.showConsentPreferences() para que os visitantes reabram o painel. Cada decisão também dispara um evento consentchange que você pode escutar.

Perguntas frequentes

Sobre consentimento de cookies

Este banner basta para a conformidade com o GDPR?

Ele entrega a mecânica que os reguladores esperam: nenhum cookie opcional antes do consentimento, recusar tão fácil quanto aceitar, escolha por categoria e um jeito de mudar de ideia depois. A conformidade também depende do que você realmente executa, do que sua política diz e de onde estão seus visitantes, então trate o código gerado como um bom ponto de partida, não como orientação jurídica.

Como impeço que scripts rodem antes do consentimento?

Dê à tag de script o type="text/plain" e um atributo data-consent com o nome da categoria. O navegador não a executa, e o banner a reescreve como uma tag de script real assim que a categoria for aceita — nesta visita ou na próxima, a partir da decisão salva.

Onde a escolha do visitante fica guardada?

No localStorage, sob a chave que você escolher, como um pequeno objeto JSON com um sinalizador por categoria e a data. Nenhum cookie é definido pelo próprio banner e nada é enviado a um servidor, então ele funciona em um site puramente estático.

Posso mudar o estilo?

Sim. Posição, tema e cor de destaque são opções aqui, e todo elemento do CSS gerado tem o prefixo cc-, então você pode sobrescrever as regras a partir da sua própria folha de estilos sem tocar no trecho.

Ainda preciso de uma plataforma de gestão de consentimento?

Para um site com poucas categorias, este trecho costuma bastar. Quando você precisar de registros de consentimento, vários domínios ou uma análise que respeite a escolha automaticamente, o gerenciador de consentimento embutido do PulsePanda assume o trabalho inteiro.

Relacionado

Mais do PulsePanda

Consentimento que sua análise realmente respeita

O PulsePanda já vem com um gerenciador de consentimento embutido — sem cookies por padrão, e ele para de coletar assim que alguém recusa. Sem um segundo fornecedor, sem código de cola.

Comece grátis