Usando os event listeners do __tcfapi: tutorial para desenvolvedores de scripts que respeitam o consentimento
Por que seus scripts devem escutar, não fazer polling
Qualquer script que dependa de consentimento — uma tag de anúncio, um loader de analytics, um wrapper de header bidding — precisa saber duas coisas: se o CMP já tem uma decisão e qual é ela. Um erro comum é ler um cookie ao carregar a página, ou fazer polling no CMP com um temporizador até que algo apareça. As duas abordagens falham de maneiras previsíveis: o formato do cookie é interno ao CMP e pode mudar, e o polling ou dispara cedo demais ou desperdiça tempo esperando.
O IAB TCF define uma interface JavaScript padrão para exatamente esse trabalho: a função __tcfapi. Este tutorial percorre os comandos de que você realmente precisa, os eventos que receberá e os bugs que mais aparecem em produção.
O stub e a fila
Espera-se que um CMP TCF coloque um pequeno stub na página o mais cedo possível, antes de o script completo do CMP carregar. O stub define window.__tcfapi e enfileira as chamadas feitas antes de o CMP estar pronto. Quando o CMP termina de carregar, ele processa a fila e responde a cada chamada.
É isso que torna seguro outros scripts chamarem __tcfapi imediatamente: desde que o stub esteja na página antes deles, suas chamadas não se perdem. Se um script lança um erro porque __tcfapi está indefinido, o stub está ausente ou carregando tarde demais — corrija a ordem de carregamento em vez de adicionar novas tentativas.
Os comandos que importam
ping
__tcfapi('ping', 2, callback) retorna o status básico sem esperar pela decisão do usuário. A resposta inclui cmpLoaded, um cmpStatus como stub, loading, loaded ou error e um displayStatus com valor visible, hidden ou disabled. Também informa gdprApplies quando conhecido. Use-o para diagnóstico e para decidir se o TCF é relevante para esse visitante.
addEventListener
__tcfapi('addEventListener', 2, callback) é o comando que a maioria das integrações deve usar. O callback recebe um objeto tcData e um indicador de sucesso, e é chamado novamente toda vez que o estado do consentimento muda. Desde o TCF v2.2, essa é a forma recomendada de obter os dados de consentimento; o antigo comando getTCData foi descontinuado.
removeEventListener
Cada objeto tcData carrega um listenerId. Passe-o para __tcfapi('removeEventListener', 2, callback, listenerId) quando seu script não precisar mais de atualizações — por exemplo, um loader de uso único que já tomou sua decisão.
Lendo o eventStatus
O campo principal em tcData é eventStatus. Há três valores:
tcloaded— o CMP encontrou uma decisão armazenada válida e nenhum banner será exibido. Você pode agir imediatamente sobre os dados.cmpuishown— o banner está sendo exibido. Os dados refletem qualquer estado anterior, mas o usuário pode estar prestes a alterá-lo.useractioncomplete— o usuário acabou de fazer ou confirmar uma escolha. Aja sobre os novos dados.
Um loader típico espera por tcloaded ou useractioncomplete e então verifica as finalidades e os fornecedores de que precisa. Ele ignora cmpuishown, exceto talvez para registrar que um banner apareceu.
Verificando finalidades e fornecedores
Dentro de tcData, consentimento e legítimo interesse são expostos como objetos indexados por ID:
tcData.purpose.consents[1]— consentimento para a finalidade 1 (armazenamento no dispositivo).tcData.purpose.legitimateInterests[7]— status do legítimo interesse para a finalidade 7.tcData.vendor.consents[ID]etcData.vendor.legitimateInterests[ID]— status por fornecedor, usando o ID do fornecedor na Global Vendor List.tcData.gdprApplies— se o CMP determinou que o GDPR se aplica a esse visitante. Se forfalse, seu script deve seguir sua lógica fora do TCF.tcData.tcString— a string codificada, que você repassa aos parceiros que a esperam.
Verifique tanto a finalidade quanto o fornecedor. Um consentimento de finalidade sem consentimento de fornecedor, ou o inverso, não basta para a maioria dos fornecedores processar dados.
Iframes e chamadas entre frames
Anúncios e widgets costumam rodar dentro de iframes que não enxergam o __tcfapi da página pai. O TCF resolve isso com um protocolo postMessage: o CMP adiciona à página principal um frame chamado __tcfapiLocator, e o código dentro de um iframe pode localizá-lo, enviar uma mensagem __tcfapiCall e receber uma resposta __tcfapiReturn. A maioria dos SDKs de anúncios já faz isso. Se você escreve seu próprio código de iframe, implemente o mesmo padrão em vez de ler cookies entre frames.
Bugs comuns e como identificá-los
- Agir sobre
cmpuishown. Scripts que carregam assim que qualquer callback dispara serão executados antes de o usuário decidir. Filtre poreventStatus. - Remover o listener cedo demais. Se você o remover após o primeiro callback, perderá um
useractioncompleteposterior e nunca carregará. - Ignorar retiradas. Scripts persistentes devem continuar escutando e parar ou se reconfigurar quando o consentimento for retirado.
- Ignorar
gdprApplies. Fora das regiões TCF, os objetos de finalidades podem estar vazios; tratá-los como “sem consentimento” pode desligar receita que você tem permissão para gerar. - Não verificar o indicador de sucesso. Quando
successé false, registre isso; normalmente sinaliza uma configuração quebrada do CMP.
Testando sua integração
No console do navegador, chame __tcfapi('ping', 2, console.log) para confirmar que o CMP está presente, depois registre um listener com console.log como callback e percorra o banner. Você deve ver cmpuishown seguido de useractioncomplete na primeira visita, e tcloaded ao recarregar. Repita com aceitar tudo, rejeitar tudo e uma seleção personalizada, e confirme que seu script se comporta corretamente em cada caso.
Principais conclusões
- Use
__tcfapiem vez de ler cookies do CMP ou fazer polling. - Garanta que o stub do CMP carregue antes de qualquer script que chame a API.
- Use
addEventListenere aja apenas emtcloadedouuseractioncomplete. - Verifique tanto o status da finalidade quanto o do fornecedor e respeite
gdprApplies. - Use o padrão postMessage do
__tcfapiLocatordentro de iframes.