Medir anúncios do ChatGPT em Drupal, a partir do browser e a partir do servidor

Diagrama: um site Drupal envia a mesma encomenda a partir do browser, pelo Measurement Pixel, e a partir do servidor, pela Conversions API, ambas com o id order-1042, e o ChatGPT Ads conta uma só conversão

Desde setembro, os anunciantes na Europa podem comprar anúncios dentro do ChatGPT, e o Ads Manager pede duas coisas antes de te conseguir dizer se funcionam: um pixel de medição no browser e, idealmente, conversões enviadas a partir do teu servidor. Num site Drupal, isso costuma significar colar um snippet no tema, escrever à mão a chamada order_created num template e tentar esconder tudo atrás do banner de cookies. Depois, a encomenda paga por transferência ou por referência horas mais tarde, confirmada por um webhook, nunca aparece, porque não havia nenhum browser lá para a ver.

Mesmo quando há um browser, o pixel perde parte do quadro. Os ad blockers bloqueiam-no por completo, o Safari limita a sete dias os cookies escritos por scripts e o iOS remove parâmetros de tracking dos links partilhados no Messages e no Mail e dos links abertos em navegação privada. A própria documentação da OpenAI chama à Conversions API "a more reliable tracking source than the pixel alone".

Publicámos um módulo para isto no drupal.org: ChatGPT Ads, software livre sob GPL, para Drupal 10.3 e 11, coberto pela política de security advisories do Drupal. Liga-se ao Drupal Commerce, ao Webform e ao gestor de consentimento Klaro através de sub-módulos, e envia eventos tanto pelo Measurement Pixel da OpenAI como pela Conversions API. É um módulo da comunidade, sem qualquer ligação à OpenAI.

O que podes medir

  • Com o Drupal Commerce, cada produto adicionado ao carrinho, incluindo a partir de um botão de add-to-cart em AJAX, com o SKU, a quantidade e o preço.
  • O início do checkout, e a própria encomenda quando está paga, não apenas colocada, para que uma transferência por pagar ou uma referência expirada nunca contem como venda.
  • A encomenda paga mais tarde e fora do site, reportada a partir do servidor quando chega o webhook de pagamento, com o mesmo event id do browser, para que a OpenAI a conte uma só vez.
  • Com o Webform, um formulário de contacto, um pedido de orçamento ou uma subscrição de newsletter como lead: acrescenta o handler ChatGPT Ads a qualquer webform e mapeia os campos de email e telefone.
  • Registos de conta, a partir do browser e do servidor.
  • Qualquer outra coisa, com uma única chamada a Drupal.chatgptAds.measure() a partir do teu próprio script.

O pixel só vai para as páginas que escolheres, com as mesmas condições de visibilidade que os blocos usam: paths, roles, content types, idioma.

O que ele se recusa a fazer

Nada é pedido à OpenAI, e nenhum cookie é criado, até o visitante decidir. A documentação da OpenAI sugere carregar o pixel com o consentimento retido e concedê-lo mais tarde, mas o script cria cookies assim que carrega, por isso o módulo nem sequer o carrega enquanto não houver resposta.

Um visitante que ainda não respondeu não é um sim nem um não. Os seus eventos ficam à espera em memória e seguem se aceitar, para que a página de entrada não se perca; se recusar, são descartados. A integração com o Klaro só lê decisões que o visitante confirmou, porque o Klaro reporta o default de um serviço desde o momento em que a página carrega, e isso seria lido como uma recusa enquanto o banner ainda está no ecrã.

A mesma regra aplica-se no servidor. O email e o telefone com hash, o endereço IP e o user agent só vão para a Conversions API no caso de um visitante cujo consentimento ficou registado no momento do evento. Para todos os outros, a conversão segue na mesma, com o identificador do clique e nada sobre a pessoa.

O módulo nunca grava uma encomenda. Gravar dentro de uma transição do Commerce pode disparar essa transição duas vezes, o que numa loja em produção significa recibos duplicados e um erro no checkout; os identificadores do clique ficam guardados na encomenda quando o próprio fluxo de checkout a grava.

As páginas continuam em cache

O pixel e as definições que são iguais para toda a gente ficam em cache com a página. O que pertence a um visitante, os eventos recolhidos nessa página e, com o advanced matching ligado, os dados da conta com hash, chega através de um placeholder renderizado em cada pedido. Uma página com o pixel continua na Dynamic Page Cache do Drupal, em vez de todas as páginas do site deixarem de ser cacheáveis só para entregar a identidade de um visitante.

De onde veio

Foi construído para uma das lojas de e-commerce que desenvolvemos em Portugal, onde muitas encomendas são pagas por Multibanco ou MB WAY, métodos de pagamento portugueses cuja confirmação chega muitas vezes horas depois do checkout. As transferências e as referências de pagamento comportam-se da mesma forma em qualquer país, e é por isso que a Conversions API entra na primeira versão e não numa posterior: sem ela, essas vendas ficam invisíveis para a plataforma de anúncios. O pixel, o gate do Klaro e os eventos de carrinho estão a correr nessa loja desde meados de setembro.

O teu gestor de consentimento, à tua escolha

O Klaro tem um sub-módulo pronto a usar: instala-o e aparece um serviço ChatGPT Ads no banner, desligado por omissão. Qualquer outro gestor de consentimento reporta a decisão através de um pequeno contrato em JavaScript, e o README traz uma receita que funciona para o EU Cookie Compliance:

Drupal.chatgptAds.consent(true);   // granted, now or on a later page
Drupal.chatgptAds.consent(false);  // refused or withdrawn

Para veres o que mais no teu site contacta terceiros antes de o visitante decidir, o Consent Audit regista-o a partir de visitas reais.

Como obter

composer require drupal/chatgpt_ads

Precisas de uma conta no ChatGPT Ads Manager e do pixel id que está no separador Conversions. O sub-módulo da Conversions API guarda a chave através do módulo Key, por isso o segredo pode viver numa variável de ambiente em vez de ficar na tua configuração exportada. A página do projeto, a documentação e o issue queue estão no drupal.org. Bugs, perguntas e merge requests são bem-vindos.