teqo-backup/docs/plans/pixel-meta-abaixo-assinado.md
Francisco Ignácio Fontoura Solla be1106f887 Add Meta Pixel tracking to public petition pages.
Let marketing configure a numeric facebookPixelId per petition in Payload, fire PageView on load and Lead after a successful signature, and mark the roadmap item delivered with deferred follow-ups documented.
2026-07-21 10:51:47 -03:00

13 KiB
Raw Permalink Blame History

Pixel do Meta (Facebook) nos abaixo-assinados

Status: entregue 2026-07-21 Atualizado em: 2026-07-21 Item do roadmap: docs/roadmap.md (Site público — entregue) Impeccable: B — encaixe no admin Petition + script na página /abaixo-assinado/[id] e no sucesso do PetitionForm Appetite: ~0,5–1 dia eng; migration + 1 campo admin + componente de script + disparo Lead no sucesso Responsável: —

Revisão 2026-07-21: implementação + /simplify + capture-review-debts — status entregue; unicidade travada; gatilho S10 (fila/retry de Lead) em Adiado; débitos de triage registrados em Explicitamente fora.

Design (Impeccable)

Âncoras: PRODUCT.md / DESIGN.md (register brand no site público; tema data-theme='petition' na página). Admin Payload usa labels pt-BR do grupo Abaixo-assinados — sem redesign de paleta.

Na implementação (implement-roadmap-item): craft compacto → critique → polish (superfície mínima; sem shape longo).

Brief compacto:

  • Persona / contexto: marketing digital monta campanha de ads no Meta e precisa ver assinaturas como conversões; editor no /admin cola o ID do Pixel no abaixo-assinado.
  • Job principal: atribuir assinaturas reais a um Pixel por petição, sem o editor colar JavaScript arbitrário.
  • Estratégia de cor: Restrained (tokens petition / admin Payload existentes).
  • Anti-goals: textarea de snippet HTML; GTM/multi-vendor; cookie banner completo; CAPI/Advanced Matching nesta fatia.

Contexto

A página pública /abaixo-assinado/[id] renderiza o documento petition e o formulário cliente PetitionForm. Assinatura bem-sucedida chama submitPetitionSignature e abre PetitionSuccessDialog. Com Pixel configurado: MetaPixel dispara PageView no load; trackMetaLead dispara Lead após assinatura ok.

A collection Petition (src/collections/Petition.ts) expõe o grupo tracking.facebookPixelId (admin “Rastreamento / Ads”) além do grupo form.

O time de marketing digital pediu (2026-07-21) um campo no formulário do abaixo-assinado no Payload para “adicionar o snippet do Pixel do Facebook” e acompanhar assinaturas no Events Manager / otimizar campanhas.

O que o Meta Pixel exige (pesquisa)

Fontes: Meta Pixel Get Started (atualizado 2026-06-30), Conversion tracking, Deduplicate Pixel + CAPI.

  1. Base code no <head> (ou via next/script): carrega fbevents.js, chama fbq('init', PIXEL_ID) e fbq('track', 'PageView'). O único dado que o editor precisa fornecer é o Pixel ID (número do Dataset no Events Manager) — o restante do “snippet” é boilerplate fixo.
  2. Evento de conversão para lead-gen: fbq('track', 'Lead', {…}) somente após a assinatura bem-sucedida — nunca no carregamento da página do formulário (erro clássico que infla leads 5–10× e corrompe o otimizador).
  3. Parâmetros úteis no Lead: content_name (título/id da petição). eventID opcional agora; obrigatório se/quando houver Conversions API (CAPI) para deduplicação.
  4. CAPI + Advanced Matching (e-mail/telefone hasheados no servidor) melhoram Event Match Quality (~6.0+), mas exigem secret de access token, hashing LGPD-consciente e dedup — fora do appetite desta fatia.
  5. LGPD: o Pixel define cookies Meta (_fbp etc.) e envia sinais de navegação/conversão. Transparência em /privacidade (e, se o jurídico pedir, no texto de Consent da petição) é requisito de produto; cookie banner site-wide fica adiado.

Objetivos

  • Campo opcional no admin de petition para o marketing configurar o Pixel por abaixo-assinado.
  • Na página pública: carregar base code + PageView quando o ID estiver presente.
  • No sucesso da assinatura: disparar exatamente um Lead (não no page load).
  • Guardrails: nunca persistir nem executar HTML/JS colado pelo editor; validar ID numérico; sem env var obrigatória (config por documento); migration com push: false; cache já revalidado por revalidateDocumentById no afterChange existente.
  • Sem novo Consent key nesta fatia (petição já exige Consent de assinatura); sem CAPI.

Decisões travadas

  • Persistir só facebookPixelId (texto, dígitos), não o snippet HTML. O “snippet” que o Meta mostra no Events Manager é boilerplate + ID; colar HTML no admin é XSS / injection e quebra CSP. O app injeta o base code controlado em código. Rejeitado: textarea/code com snippet livre; campo html/richText de tracking; GTM container ID como substituto nesta fatia.
  • Pixel por petição (campo no documento petition), não global do site. Campanhas de ads costumam ser por abaixo-assinado/URL; evita Pixel único vazar PageViews de notícias/home. Rejeitado: só env NEXT_PUBLIC_FACEBOOK_PIXEL_ID site-wide; Global SiteSettings único (pode ser fill-in futuro se marketing unificar Dataset).
  • v1 = browser Pixel only, com os dois eventos: PageView no load da página da petição e Lead no sucesso do form (confirmado com produto 2026-07-21). Padrão Meta: retargeting de visitantes + conversão de assinatura. Transparência de cookies/Meta fica no polish de /privacidade (dependência suave). Rejeitado nesta fatia: só Lead sem PageView; Conversions API; Advanced Matching com e-mail/telefone no browser/servidor; eventos CompleteRegistration/Contact além de Lead; cookie banner / CMP.
  • Lead só após submitPetitionSignature ok (mesmo caminho que abre o diálogo de sucesso). Rejeitado: Lead no onSubmit antes da resposta; Lead no page load; thank-you page dedicada (não existe hoje — o sucesso é modal same-page).
  • Mesmo Dataset em N petições permitido. O mesmo facebookPixelId pode aparecer em várias petições; content_name no Lead carrega o título da petição para diferenciar no Events Manager. Rejeitado: uniqueness forçada no admin.
  • i18n e naming seguem o AGENTS.md: identificadores em inglês (facebookPixelId, MetaPixel, trackMetaLead); labels admin e copy em pt-BR (“ID do Pixel do Meta (Facebook)”).

Abordagem proposta

flowchart LR
  Admin["Payload admin<br/>tracking.facebookPixelId"]
  Page["abaixo-assinado/[id]<br/>Server Component"]
  Pixel["MetaPixel client<br/>next/script + fbq init/PageView"]
  Form["PetitionForm"]
  Action["submitPetitionSignature"]
  Lead["trackMetaLead<br/>fbq track Lead"]
  Meta["Meta Events Manager"]

  Admin --> Page
  Page --> Pixel
  Pixel --> Meta
  Form --> Action
  Action -->|sucesso--> Lead
  Lead --> Meta

Componentes:

  • Campo facebookPixelId em src/collections/Petition.ts (irmão do grupo form ou dentro de um group tracking com label “Rastreamento / Ads”): type: 'text', opcional, admin.description explicando “cole só o ID numérico do Events Manager (ex.: 123456789012345), não o snippet HTML completo”. validate rejeita não-dígitos / comprimento fora de ~5–20. Sem required.
  • isValidFacebookPixelId / normalizeFacebookPixelId (em src/lib/facebookPixel.ts ou src/utilities/facebookPixel.ts): helper puro testável (unit) — depth check: um módulo pequeno que esconde a regex e a montagem do init; não inventar “AnalyticsService”.
  • MetaPixel (client, src/components/MetaPixel.tsx): se pixelId válido, renderiza next/script (strategy="afterInteractive") que carrega o padrão Meta (fbevents.js + fbq('init', id) + fbq('track', 'PageView')) e noscript img opcional. Tipar window.fbq localmente (sem @types de terceiros se não existir no repo).
  • trackMetaLead (mesmo módulo lib/utilities ou export do componente): fbq('track', 'Lead', { content_name }, { eventID? }) se window.fbq existir; no-op seguro se Pixel não carregou / adblock.
  • PetitionForm: após sucesso de submitPetitionSignature, chamar trackMetaLead com content_name = título ou id da petição (e eventID = UUID gerado no cliente só se quisermos preparar CAPI depois — nesta fatia opcional; preferir gerar UUID e passar já, custo zero, facilita fatia futura).
  • Página abaixo-assinado/[id]/page.tsx: passar petition.facebookPixelId para <MetaPixel /> quando presente; incluir o campo no select/cache se a leitura de documento filtrar campos (hoje getCachedDocumentById carrega o doc — confirmar após generate:types).
  • Migration 20260721_133531_add_petition_facebook_pixel_id — colunas tracking_facebook_pixel_id / version_tracking_facebook_pixel_id; sem backfill.
  • Testes: tests/unit/facebookPixel.unit.spec.ts (validador + trackMetaLead); smoke manual com Meta Pixel Helper.

Já resolvido no simplify/critique (não reabrir)

  • Normalização única na página (normalizeFacebookPixelId) + prop facebookPixelId para PetitionForm (sem re-normalizar no form).
  • validate admin e beforeChange em Petition reutilizam normalizeFacebookPixelId.
  • Validação duplicada removida de MetaPixel (prop pré-validada).
  • Tipos one-off removidos (TrackMetaLeadInput, MetaPixelProps); trackMetaLead com assinatura posicional.
  • Blockquote da página da petição suavizado (Impeccable side-tab); impeccable detect limpo na superfície.

Dependências

  • Nenhuma de outro plano de trilha A/B/C/D.
  • Suave: polish do Aviso de Privacidade (Site público / Onda 0 textos finais) deve mencionar cookies/ferramentas de ads (Meta) quando Pixel estiver em uso — não bloqueia a engenharia do campo.
  • Reusa: revalidateDocumentById já no afterChange de Petition; PetitionForm success path; next/script.

Não escopo

  • Conversions API (CAPI) / access token / Event Match Quality server-side → fatia futura com gatilho abaixo.
  • Google Tag Manager, TikTok Pixel, Google Ads gtag — outro item se marketing pedir.
  • Cookie consent banner site-wide / CMP.
  • Pixel no layout global do site (home, notícias, /campanha).
  • Thank-you page dedicada / redirect pós-assinatura.
  • Alterar schema de signature/contact para guardar event_id Meta.

Rabbit holes

  • Colar snippet HTML “como o Meta manda”. Se alguém “só completar” o pedido literal do marketing: XSS + HTML no CMS. Mitigação: campo só ID + description no admin + validação server-side.
  • CAPI “já que estamos no servidor”. Explode em secrets, hashing PII, dedup, retries. Mitigação: defer com gatilho.
  • Cookie banner completo por causa deste campo. Projeto de CMP. Mitigação: transparência em /privacidade + decisão jurídica sobre PageView; não construir banner aqui.
  • Advanced Matching no browser com e-mail/telefone em claro. Vazamento + LGPD. Mitigação: fora; CAPI hasheado só em fatia futura.

Adiado com gatilho

  • Fila/retry de Lead quando window.fbq ainda não carregou (race submit rápido vs. afterInteractive). Revisitar quando smoke com Meta Pixel Helper mostrar conversão Lead ausente após assinatura bem-sucedida em produção.
  • Conversions API + dedup com event_id compartilhado. Revisitar quando: marketing reportar perda material de atribuição (iOS/adblock) ou Event Match Quality < 6 no Dataset em uso com volume real de ads.
  • Pixel / Dataset global em SiteSettings. Revisitar quando: o mesmo ID for colado em ≥3 petições e o admin reclamar de repetição.
  • Cookie banner / CMP. Revisitar quando: jurídico exigir bloqueio pré-consent de cookies de ads (não só transparência).

Explicitamente fora (triage capture-review-debts 2026-07-21)

  • Re-validação em trackMetaLead — defesa em profundidade intencional (custo zero).
  • Flatten tracking → campo top-level — grupo reservado para futuros campos de ads.
  • eslint @next/next/no-img-element no <noscript> 1×1 — padrão Meta; next/image inadequado.
  • Int test de Petition.validate — opcional no appetite original; sem evidência de regressão.
  • Mencionar cookies/Meta em /privacidade — absorvido no item existente do roadmap (Site público / O0+); não duplicar plano.

Referências

  • docs/roadmap.md (Site público)
  • src/collections/Petition.ts — schema admin do abaixo-assinado
  • src/app/(frontend)/abaixo-assinado/[id]/page.tsx — página pública
  • src/components/PetitionForm.tsx — sucesso da assinatura
  • src/app/(frontend)/actions/submitPetitionSignature.ts — escrita transacional (inalterada no fluxo de tracking cliente)
  • Meta: Get Started · Conversion tracking · Deduplication
  • Next.js: next/script + strategy="afterInteractive" (App Router)
  • AGENTS.md — naming, migrations push: false, Consent por chave (não inventar paralelo aqui), revalidate de documentos
  • PRODUCT.md / DESIGN.md — canal público / tema petition