cdp-edge 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +367 -0
  2. package/bin/cdp-edge.js +61 -0
  3. package/contracts/api-versions.json +368 -0
  4. package/dist/commands/analyze.js +52 -0
  5. package/dist/commands/infra.js +54 -0
  6. package/dist/commands/install.js +168 -0
  7. package/dist/commands/server.js +174 -0
  8. package/dist/commands/setup.js +123 -0
  9. package/dist/commands/validate.js +84 -0
  10. package/dist/index.js +12 -0
  11. package/docs/CI-CD-SETUP.md +217 -0
  12. package/docs/PixelBuilder-Documentacao-Completa (2).docx +0 -0
  13. package/docs/events-reference.md +359 -0
  14. package/docs/installation.md +155 -0
  15. package/docs/quick-start.md +185 -0
  16. package/docs/sdk-reference.md +371 -0
  17. package/docs/whatsapp-ctwa.md +209 -0
  18. package/extracted-skill/tracking-events-generator/INDEX.md +94 -0
  19. package/extracted-skill/tracking-events-generator/INSTALACAO-CDPEDGE.md +58 -0
  20. package/extracted-skill/tracking-events-generator/INTEGRACAO-COMPLETA.md +594 -0
  21. package/extracted-skill/tracking-events-generator/MELHORIAS-IMPLEMENTADAS.md +412 -0
  22. package/extracted-skill/tracking-events-generator/Premium-Tracking-Intelligence-Resumo.md +333 -0
  23. package/extracted-skill/tracking-events-generator/SKILL.md +257 -0
  24. package/extracted-skill/tracking-events-generator/advanced-matching.js +364 -0
  25. package/extracted-skill/tracking-events-generator/agents/ab-testing-agent.md +54 -0
  26. package/extracted-skill/tracking-events-generator/agents/attribution-agent.md +1304 -0
  27. package/extracted-skill/tracking-events-generator/agents/bing-agent.md +76 -0
  28. package/extracted-skill/tracking-events-generator/agents/browser-tracking.md +264 -0
  29. package/extracted-skill/tracking-events-generator/agents/code-guardian-agent.md +149 -0
  30. package/extracted-skill/tracking-events-generator/agents/compliance-agent.md +2077 -0
  31. package/extracted-skill/tracking-events-generator/agents/crm-integration-agent.md +1419 -0
  32. package/extracted-skill/tracking-events-generator/agents/dashboard-agent.md +456 -0
  33. package/extracted-skill/tracking-events-generator/agents/database-agent.md +667 -0
  34. package/extracted-skill/tracking-events-generator/agents/debug-agent.md +1455 -0
  35. package/extracted-skill/tracking-events-generator/agents/domain-setup-agent.md +224 -0
  36. package/extracted-skill/tracking-events-generator/agents/email-agent.md +61 -0
  37. package/extracted-skill/tracking-events-generator/agents/fingerprint-agent.md +52 -0
  38. package/extracted-skill/tracking-events-generator/agents/google-agent.md +109 -0
  39. package/extracted-skill/tracking-events-generator/agents/intelligence-agent.md +365 -0
  40. package/extracted-skill/tracking-events-generator/agents/intelligence-scheduling.md +643 -0
  41. package/extracted-skill/tracking-events-generator/agents/linkedin-agent.md +62 -0
  42. package/extracted-skill/tracking-events-generator/agents/localization-agent.md +55 -0
  43. package/extracted-skill/tracking-events-generator/agents/ltv-predictor-agent.md +59 -0
  44. package/extracted-skill/tracking-events-generator/agents/master-feedback-loop.md +900 -0
  45. package/extracted-skill/tracking-events-generator/agents/master-orchestrator.md +1922 -0
  46. package/extracted-skill/tracking-events-generator/agents/memory-agent.json +109 -0
  47. package/extracted-skill/tracking-events-generator/agents/memory-agent.md +703 -0
  48. package/extracted-skill/tracking-events-generator/agents/meta-agent.md +110 -0
  49. package/extracted-skill/tracking-events-generator/agents/page-analyzer.md +255 -0
  50. package/extracted-skill/tracking-events-generator/agents/performance-agent.md +1157 -0
  51. package/extracted-skill/tracking-events-generator/agents/performance-optimization-agent.md +1432 -0
  52. package/extracted-skill/tracking-events-generator/agents/pinterest-agent.md +310 -0
  53. package/extracted-skill/tracking-events-generator/agents/premium-tracking-intelligence-agent.md +849 -0
  54. package/extracted-skill/tracking-events-generator/agents/r2-setup-agent.md +250 -0
  55. package/extracted-skill/tracking-events-generator/agents/reddit-agent.md +313 -0
  56. package/extracted-skill/tracking-events-generator/agents/security-enterprise-agent.md +1752 -0
  57. package/extracted-skill/tracking-events-generator/agents/server-tracking.md +1188 -0
  58. package/extracted-skill/tracking-events-generator/agents/spotify-agent.md +383 -0
  59. package/extracted-skill/tracking-events-generator/agents/tiktok-agent.md +111 -0
  60. package/extracted-skill/tracking-events-generator/agents/tracking-plan-agent.md +364 -0
  61. package/extracted-skill/tracking-events-generator/agents/validator-agent.md +267 -0
  62. package/extracted-skill/tracking-events-generator/agents/webhook-agent.md +69 -0
  63. package/extracted-skill/tracking-events-generator/agents/whatsapp-agent.md +76 -0
  64. package/extracted-skill/tracking-events-generator/agents/whatsapp-ctwa-setup-agent.md +699 -0
  65. package/extracted-skill/tracking-events-generator/agents/youtube-agent.md +422 -0
  66. package/extracted-skill/tracking-events-generator/anti-blocking.js +285 -0
  67. package/extracted-skill/tracking-events-generator/cdpTrack.js +641 -0
  68. package/extracted-skill/tracking-events-generator/contracts/api-versions.json +368 -0
  69. package/extracted-skill/tracking-events-generator/docs/guia-cloudflare-iniciante.md +107 -0
  70. package/extracted-skill/tracking-events-generator/engagement-scoring.js +226 -0
  71. package/extracted-skill/tracking-events-generator/evals/evals.json +235 -0
  72. package/extracted-skill/tracking-events-generator/integration-test.js +497 -0
  73. package/extracted-skill/tracking-events-generator/knowledge-base.md +2894 -0
  74. package/extracted-skill/tracking-events-generator/micro-events.js +992 -0
  75. package/extracted-skill/tracking-events-generator/models/captura-de-lead.md +78 -0
  76. package/extracted-skill/tracking-events-generator/models/captura-lead-evento-externo.md +99 -0
  77. package/extracted-skill/tracking-events-generator/models/checkout-proprio.md +111 -0
  78. package/extracted-skill/tracking-events-generator/models/multi-step-checkout.md +672 -0
  79. package/extracted-skill/tracking-events-generator/models/pagina-obrigado.md +55 -0
  80. package/extracted-skill/tracking-events-generator/models/pinterest/conversions-api-template.js +144 -0
  81. package/extracted-skill/tracking-events-generator/models/pinterest/event-mappings.json +48 -0
  82. package/extracted-skill/tracking-events-generator/models/pinterest/tag-template.js +28 -0
  83. package/extracted-skill/tracking-events-generator/models/quiz-funnel.md +68 -0
  84. package/extracted-skill/tracking-events-generator/models/reddit/conversions-api-template.js +205 -0
  85. package/extracted-skill/tracking-events-generator/models/reddit/event-mappings.json +56 -0
  86. package/extracted-skill/tracking-events-generator/models/reddit/pixel-template.js +19 -0
  87. package/extracted-skill/tracking-events-generator/models/scenarios/behavior-engine.js +425 -0
  88. package/extracted-skill/tracking-events-generator/models/scenarios/real-estate-logic.md +50 -0
  89. package/extracted-skill/tracking-events-generator/models/scenarios/sales-page-logic.md +50 -0
  90. package/extracted-skill/tracking-events-generator/models/trafego-direto.md +582 -0
  91. package/extracted-skill/tracking-events-generator/models/webinar-registration.md +63 -0
  92. package/extracted-skill/tracking-events-generator/tracking.config.js +46 -0
  93. package/extracted-skill/tracking-events-generator/walkthrough.md +26 -0
  94. package/package.json +75 -0
  95. package/server-edge-tracker/INSTALAR.md +328 -0
  96. package/server-edge-tracker/migrate-new-db.sql +137 -0
  97. package/server-edge-tracker/migrate-v2.sql +16 -0
  98. package/server-edge-tracker/migrate-v3.sql +6 -0
  99. package/server-edge-tracker/migrate-v4.sql +18 -0
  100. package/server-edge-tracker/migrate-v5.sql +17 -0
  101. package/server-edge-tracker/migrate-v6.sql +24 -0
  102. package/server-edge-tracker/migrate.sql +111 -0
  103. package/server-edge-tracker/schema.sql +265 -0
  104. package/server-edge-tracker/worker.js +2574 -0
  105. package/server-edge-tracker/wrangler.toml +85 -0
  106. package/templates/afiliado-sem-landing.md +312 -0
  107. package/templates/captura-de-lead.md +78 -0
  108. package/templates/captura-lead-evento-externo.md +99 -0
  109. package/templates/checkout-proprio.md +111 -0
  110. package/templates/install/.claude/commands/cdp.md +1 -0
  111. package/templates/install/CLAUDE.md +65 -0
  112. package/templates/linkedin/tag-template.js +46 -0
  113. package/templates/multi-step-checkout.md +673 -0
  114. package/templates/pagina-obrigado.md +55 -0
  115. package/templates/pinterest/conversions-api-template.js +144 -0
  116. package/templates/pinterest/event-mappings.json +48 -0
  117. package/templates/pinterest/tag-template.js +28 -0
  118. package/templates/quiz-funnel.md +68 -0
  119. package/templates/reddit/conversions-api-template.js +205 -0
  120. package/templates/reddit/event-mappings.json +56 -0
  121. package/templates/reddit/pixel-template.js +46 -0
  122. package/templates/scenarios/behavior-engine.js +402 -0
  123. package/templates/scenarios/real-estate-logic.md +50 -0
  124. package/templates/scenarios/sales-page-logic.md +50 -0
  125. package/templates/spotify/pixel-template.js +46 -0
  126. package/templates/trafego-direto.md +582 -0
  127. package/templates/vsl-page.md +292 -0
  128. package/templates/webinar-registration.md +63 -0
@@ -0,0 +1,422 @@
1
+ # Agente: YouTube Ads — CDP Edge (Quantum Tier)
2
+
3
+ Especialista em rastreamento de campanhas de vídeo do YouTube via Google Ads (Video Campaigns),
4
+ integrado ao GA4 Measurement Protocol + Enhanced Conversions + Cloudflare Workers.
5
+
6
+ Inclui estratégias específicas para **imóveis, lançamentos e produtos de alto ticket**,
7
+ onde o vídeo é o principal driver de awareness e intenção de compra.
8
+
9
+ ---
10
+
11
+ ## 🏗️ ARQUITETURA Quantum Tier — YouTube
12
+
13
+ ```
14
+ YouTube Ad (TrueView / Bumper / Non-skip)
15
+ ↓ clique / view
16
+ gclid | wbraid | gbraid
17
+ ↓ capturado por cdpTrack.js
18
+ Cloudflare Worker (/track)
19
+ ↓ ctx.waitUntil
20
+ GA4 MP (video_engagement) + Google Ads Enhanced Conversions
21
+
22
+ D1: user_profiles (ga_client_id, gclid, wbraid, gbraid)
23
+ ```
24
+
25
+ - **Browser**: `cdpTrack.js` captura `gclid`, `wbraid`, `gbraid` da URL automaticamente
26
+ - **Vídeos na página**: `behavior-engine.js` rastreia progresso via postMessage (YouTube IFrame API)
27
+ - **Server**: Cloudflare Worker envia conversões para GA4 MP + Google Ads API
28
+ - **Database**: D1 persiste `ga_client_id`, `gclid`, `wbraid`, `gbraid` no perfil do usuário
29
+
30
+ ---
31
+
32
+ ## ACESSO À VERSÕES DE API (OBRIGATÓRIO)
33
+
34
+ ### PASSO 0 — Ler Versões Atuais
35
+
36
+ ```javascript
37
+ const apiVersions = await readJSON('contracts/api-versions.json');
38
+ const googleVersions = apiVersions.google;
39
+
40
+ const ga4Endpoint = googleVersions.versions.ga4.endpoint_pattern;
41
+ const consentModeVersion = googleVersions.versions.consent_mode.current; // "v2"
42
+ const urlPassthrough = googleVersions.versions.consent_mode.flags.url_passthrough; // true
43
+
44
+ // Verificar Consent Mode v2 (obrigatório para YouTube/Google Ads)
45
+ if (consentModeVersion !== 'v2') {
46
+ throw new Error('Google Consent Mode v2 é obrigatório para campanhas YouTube. Atualizar IMEDIATAMENTE.');
47
+ }
48
+ ```
49
+
50
+ ---
51
+
52
+ ## 📺 TIPOS DE CAMPANHA E O QUE RASTREAR
53
+
54
+ ### TrueView In-Stream (pulável após 5s)
55
+ - **Evento de billing**: view confirmada após 30s ou clique
56
+ - **Rastrear**: `video_start`, `video_progress_30s`, `video_complete`, clique no CTA
57
+ - **Conversão Google Ads**: `engaged_view` (30s assistidos = 1 conversão de vídeo)
58
+
59
+ ### Bumper Ads (6s não-puláveis)
60
+ - **Objetivo**: awareness puro — sem clique direto
61
+ - **Rastrear**: impressão → remarketing na rede Display + YouTube
62
+ - **Conversão Google Ads**: view-through conversion (VTC) — configura janela de 1-7 dias
63
+
64
+ ### Non-skip In-Stream (15s não-puláveis)
65
+ - **Evento de billing**: sempre cobrado (100% view)
66
+ - **Rastrear**: `video_complete`, clique no CTA overlay
67
+ - **Conversão Google Ads**: view-through + click-through
68
+
69
+ ### Video Discovery (aparece em resultados de busca YouTube)
70
+ - **Evento de billing**: clique na miniatura
71
+ - **Rastrear**: clique → pageview → Lead/Purchase
72
+ - **Click ID**: `gclid` padrão (mesma janela que Search)
73
+
74
+ ---
75
+
76
+ ## 🛠️ IMPLEMENTAÇÃO BROWSER — cdpTrack.js
77
+
78
+ ### 1. Click IDs capturados automaticamente
79
+
80
+ `cdpTrack.js` já captura na chegada do usuário via URL:
81
+
82
+ ```javascript
83
+ // Já implementado em cdpTrack.js — não duplicar
84
+ const _gclid = _urlParams.get('gclid') || ''; // Google Ads standard
85
+ const _wbraid = _urlParams.get('wbraid') || ''; // iOS web-to-app (privacy)
86
+ const _gbraid = _urlParams.get('gbraid') || ''; // App campaigns (privacy)
87
+ ```
88
+
89
+ **ATENÇÃO wbraid/gbraid**: São os click IDs para campanhas YouTube em iOS (pós ATT).
90
+ Nunca hashear — enviar como texto plano para Google Ads API.
91
+
92
+ ### 2. Rastreamento de vídeo YouTube na página
93
+
94
+ O `behavior-engine.js` já implementa rastreamento de vídeos via YouTube IFrame API.
95
+ Para usar, o iframe deve ter `enablejsapi=1`:
96
+
97
+ ```html
98
+ <!-- Embed YouTube com JS API habilitada -->
99
+ <iframe
100
+ id="video-tour-imovel"
101
+ src="https://www.youtube.com/embed/VIDEO_ID?enablejsapi=1"
102
+ allow="autoplay"
103
+ ></iframe>
104
+ ```
105
+
106
+ O BehaviorEngine detecta automaticamente e dispara via `cdpTrack.track()`:
107
+ - `video_milestone` com `percent: 25, 50, 75, 100`
108
+ - Score: +10 (25%), +15 (50%), +25 (75%/100%)
109
+
110
+ ### 3. Evento de Lead após assistir vídeo (imóveis)
111
+
112
+ ```javascript
113
+ // Disparar Lead qualificado quando usuário assiste 75%+ do tour
114
+ document.addEventListener('pb:video_milestone', (e) => {
115
+ if (e.detail.percent >= 75) {
116
+ cdpTrack.track('InitiateCheckout', {
117
+ content_name: 'Tour_Virtual_Empreendimento',
118
+ value: 0,
119
+ currency: 'BRL',
120
+ // Sinaliza alta intenção para Meta + Google
121
+ meta_intensity: 'high',
122
+ });
123
+ }
124
+ });
125
+ ```
126
+
127
+ ### 4. Consent Mode v2 — OBRIGATÓRIO para YouTube/Google Ads
128
+
129
+ YouTube Ads usa sinais de consent para modelagem de conversão.
130
+ Sem isso, Google desativa modelagem e conversões ficam subnotificadas.
131
+
132
+ ```javascript
133
+ // Já implementado em cdpTrack.js via initConsentMode()
134
+ // Para banners de cookies — chamar após aceite:
135
+ cdpTrack.updateConsent({ analytics: true, ads: true });
136
+
137
+ // Para usuários que recusam — manter negado (padrão)
138
+ // cdpTrack.updateConsent({ analytics: false, ads: false }); // já é o default
139
+ ```
140
+
141
+ ---
142
+
143
+ ## 🛠️ IMPLEMENTAÇÃO SERVER — worker.js
144
+
145
+ ### 1. Extrair e persistir Click IDs do YouTube
146
+
147
+ No handler `/track`, os click IDs já chegam no payload via `cdpTrack.js`.
148
+ O `upsertProfile()` já persiste `gclid`, `wbraid`, `gbraid` no D1.
149
+
150
+ Para verificar persistência correta:
151
+
152
+ ```javascript
153
+ // D1: user_profiles — colunas já existentes
154
+ // gclid TEXT — Google Ads standard click ID
155
+ // wbraid TEXT — iOS privacy-preserving (YouTube)
156
+ // gbraid TEXT — App campaigns privacy-preserving
157
+ ```
158
+
159
+ ### 2. GA4 Measurement Protocol — Eventos de Vídeo
160
+
161
+ ```javascript
162
+ // No sendGA4Mp() — adicionar mapeamento de eventos YouTube
163
+ const VIDEO_GA4_MAP = {
164
+ video_start: 'video_start',
165
+ video_milestone: 'video_progress', // GA4 usa video_progress com percent
166
+ video_complete: 'video_complete',
167
+ };
168
+
169
+ // Params obrigatórios para video_progress (GA4)
170
+ const videoParams = {
171
+ video_title: contentName || '',
172
+ video_duration: payload.videoDuration || 0,
173
+ video_percent: payload.videoPercent || 0, // 25, 50, 75, 100
174
+ video_provider: 'youtube',
175
+ visible: true,
176
+ };
177
+ ```
178
+
179
+ ### 3. Google Ads Enhanced Conversions — Lead de Vídeo
180
+
181
+ ```javascript
182
+ // Conversão de Lead gerada por campanha YouTube
183
+ // Envia para GA4 MP com user_data para Enhanced Conversions
184
+ const enhancedConversionPayload = {
185
+ client_id: payload.gaClientId, // _ga cookie — obrigatório
186
+ user_data: {
187
+ email_address: payload.email, // não hashear — GA4 MP faz internamente
188
+ phone_number: payload.phone,
189
+ address: {
190
+ first_name: payload.firstName,
191
+ last_name: payload.lastName,
192
+ }
193
+ },
194
+ events: [{
195
+ name: 'generate_lead',
196
+ params: {
197
+ value: payload.value || 0,
198
+ currency: 'BRL',
199
+ transaction_id: payload.eventId, // deduplicação
200
+ // Atribuição YouTube
201
+ gclid: payload.gclid || undefined,
202
+ wbraid: payload.wbraid || undefined,
203
+ gbraid: payload.gbraid || undefined,
204
+ }
205
+ }]
206
+ };
207
+ ```
208
+
209
+ ### 4. View-Through Conversion (VTC) — Bumpers
210
+
211
+ Para campanhas Bumper/Non-skip, o usuário converte DEPOIS sem clicar.
212
+ O Worker detecta isso quando um Lead chega SEM gclid mas com histórico de impressão YouTube:
213
+
214
+ ```javascript
215
+ // No upsertProfile() — verificar se perfil tem impressão YouTube recente
216
+ // (requer webhook do Google Ads — avançado, Fase 5)
217
+ // Por ora: registrar ausência de gclid + utm_source=youtube como view-through candidate
218
+ if (!payload.gclid && payload.utmSource === 'youtube') {
219
+ payload.vtcCandidate = true;
220
+ // Logar para análise manual no D1
221
+ }
222
+ ```
223
+
224
+ ---
225
+
226
+ ## 📊 EVENTOS PADRÃO — YouTube Campaigns
227
+
228
+ | Evento cdpTrack | Mapeamento GA4 | Mapeamento Google Ads | Quando Disparar |
229
+ |---|---|---|---|
230
+ | `video_start` | `video_start` | — | Primeiros 2s de reprodução |
231
+ | `video_milestone` (25%) | `video_progress` | — | 25% assistido |
232
+ | `video_milestone` (50%) | `video_progress` | `engaged_view` candidate | 50% assistido |
233
+ | `video_milestone` (75%) | `video_progress` | `engaged_view` | 75% assistido — alta intenção |
234
+ | `video_complete` | `video_complete` | `video_view_complete` | 100% assistido |
235
+ | `Lead` (após vídeo) | `generate_lead` | Conversão primária | Formulário submetido |
236
+ | `InitiateCheckout` | `begin_checkout` | Conversão micro | Clique em "Quero saber mais" |
237
+
238
+ ---
239
+
240
+ ## 🏠 ESTRATÉGIA ESPECÍFICA — IMÓVEIS
241
+
242
+ ### Funil recomendado para lançamentos
243
+
244
+ ```
245
+ FASE 1: AWARENESS (YouTube TrueView 30s)
246
+ ↓ Tour aéreo do empreendimento / lifestyle do bairro
247
+ ↓ Rastrear: video_milestone 50% + 75% → score alto no LTV
248
+ ↓ Remarketing: quem assistiu 50%+ vira audiência no Google Ads
249
+
250
+ FASE 2: CONSIDERAÇÃO (YouTube Non-skip 15s + Display)
251
+ ↓ Planta do apartamento / diferenciais / construtora
252
+ ↓ Rastrear: clique no CTA → pageview da página de lançamento
253
+ ↓ Conectar: gclid → D1 → Meta CAPI (cross-platform attribution)
254
+
255
+ FASE 3: DECISÃO (Search + YouTube Discovery)
256
+ ↓ "Apartamento [bairro] lançamento" — intenção ativa
257
+ ↓ Rastrear: Lead com gclid → Enhanced Conversions
258
+ ↓ LTV Prediction: leads com gclid YouTube têm multiplicador 2.2x
259
+ ```
260
+
261
+ ### UTM padrão para campanhas YouTube Imóveis
262
+
263
+ ```
264
+ utm_source=youtube
265
+ utm_medium=video
266
+ utm_campaign=lancamento-{nome-empreendimento}-{cidade}
267
+ utm_content=tour-aereo-30s | planta-apartamento-15s | depoimento-morador
268
+ utm_term={tipo-imovel}-{metragem}-{bairro}
269
+ ```
270
+
271
+ ### Audiências recomendadas (Google Ads)
272
+
273
+ ```javascript
274
+ // Audiências de alta intenção para imóveis — configurar no Google Ads
275
+ const YOUTUBE_AUDIENCES_IMOVEIS = {
276
+ // In-Market (Google detecta comportamento de compra)
277
+ inMarket: [
278
+ 'Real Estate > Residential Properties > For Sale',
279
+ 'Real Estate > For Rent > Apartments & Condos',
280
+ 'Financial Services > Mortgages',
281
+ ],
282
+
283
+ // Custom Intent (palavras que o usuário pesquisou)
284
+ customIntent: [
285
+ 'apartamento na planta comprar',
286
+ 'lançamento imóvel [cidade]',
287
+ 'construtora [nome] apartamentos',
288
+ 'financiamento imóvel caixa',
289
+ ],
290
+
291
+ // Remarketing CDP Edge (audiência first-party via D1)
292
+ firstParty: {
293
+ source: 'D1 user_profiles WHERE cohort_label IN ("high_intent", "buyer_lookalike")',
294
+ upload: 'Google Ads Customer Match (email + phone)',
295
+ refresh: 'semanal via Intelligence Agent',
296
+ }
297
+ };
298
+ ```
299
+
300
+ ---
301
+
302
+ ## 🔗 INTEGRAÇÃO COM CDPEDGE
303
+
304
+ ### Customer Match — Exportar leads do D1 para Google Ads
305
+
306
+ ```javascript
307
+ // Endpoint no Worker: GET /export/customer-match
308
+ // Gera CSV criptografado para upload no Google Ads
309
+
310
+ async function exportCustomerMatchList(env) {
311
+ const highIntentLeads = await env.DB.prepare(`
312
+ SELECT email, phone, first_name, last_name
313
+ FROM user_profiles
314
+ WHERE cohort_label IN ('high_intent', 'buyer_lookalike')
315
+ AND updated_at > datetime('now', '-30 days')
316
+ AND email IS NOT NULL
317
+ `).all();
318
+
319
+ // Google Ads aceita SHA-256 de email e phone
320
+ const rows = await Promise.all(
321
+ highIntentLeads.results.map(async (lead) => ({
322
+ hashed_email: await sha256(lead.email),
323
+ hashed_phone: lead.phone ? await sha256(lead.phone) : '',
324
+ first_name: lead.first_name || '',
325
+ last_name: lead.last_name || '',
326
+ }))
327
+ );
328
+
329
+ return rows; // Upload manual no Google Ads > Ferramentas > Audiências > Customer Match
330
+ }
331
+ ```
332
+
333
+ ### Intelligence Agent — Monitorar performance de vídeo
334
+
335
+ O Intelligence Agent (cron semanal) deve incluir check de YouTube:
336
+
337
+ ```javascript
338
+ // Adicionar ao checkApiVersionsIntelligence():
339
+ // Verificar se wbraid/gbraid estão chegando nos leads
340
+ // (indica que campanhas YouTube iOS estão funcionando)
341
+ const youtubeMobileLeads = await env.DB.prepare(`
342
+ SELECT COUNT(*) as count
343
+ FROM user_profiles
344
+ WHERE (wbraid IS NOT NULL OR gbraid IS NOT NULL)
345
+ AND updated_at > datetime('now', '-7 days')
346
+ `).first();
347
+
348
+ if (youtubeMobileLeads.count === 0) {
349
+ await sendIntelligenceAlert(env, 'warning', 'YouTube Mobile Attribution',
350
+ '⚠️ Nenhum wbraid/gbraid nos últimos 7 dias. Campanhas YouTube iOS podem estar sem rastreamento.');
351
+ }
352
+ ```
353
+
354
+ ---
355
+
356
+ ## 🛠️ REQUISITOS TÉCNICOS
357
+
358
+ - **Consent Mode v2**: OBRIGATÓRIO — sem ele Google desativa modelagem de conversão
359
+ - **ga_client_id**: Persistir `_ga` cookie no D1 — necessário para GA4 MP + Enhanced Conversions
360
+ - **gclid / wbraid / gbraid**: Todos já capturados por `cdpTrack.js` — nunca hashear
361
+ - **url_passthrough**: Habilitado por padrão no `initConsentMode()` — preserva click IDs
362
+ - **IFrame API**: Embeds YouTube devem ter `?enablejsapi=1` para o BehaviorEngine funcionar
363
+ - **Customer Match**: Listas exportadas do D1 devem ter email e phone hasheados em SHA-256
364
+ - **VTC Window**: Configurar janela de view-through de 7 dias para Bumpers no Google Ads
365
+
366
+ ---
367
+
368
+ ## ⚠️ ERROS COMUNS — YouTube Tracking
369
+
370
+ | Erro | Causa | Solução |
371
+ |---|---|---|
372
+ | Conversões sem atribuição YouTube | `ga_client_id` não persistido | Verificar D1: `SELECT ga_client_id FROM user_profiles` |
373
+ | wbraid/gbraid não chegando | cdpTrack não inicializado antes do click | Garantir DOMContentLoaded antes do clique |
374
+ | video_progress não disparando | IFrame sem `enablejsapi=1` | Adicionar parâmetro na URL do embed |
375
+ | Consent Mode bloqueando hits | Banner de cookies sem integração | Implementar `cdpTrack.updateConsent()` no callback de aceite |
376
+ | Customer Match baixa taxa de match | Email não normalizado | Usar `normalizeEmail()` antes do SHA-256 |
377
+ | LTV subnotificado para YouTube | utm_source não mapeado | Adicionar 'youtube' ao `utm_score_map` no `predictLtv()` |
378
+
379
+ ---
380
+
381
+ ## INPUTS RECEBIDOS
382
+
383
+ - JSON do Page Analyzer Agent (vídeos embeds detectados, CTAs, tipo de página)
384
+ - JSON do Premium Tracking Intelligence Agent (eventos prioritários, estratégia de VSL)
385
+ - `contracts/api-versions.json` → `google.versions.ga4.current` e `consent_mode.current`
386
+ - `GA4_MEASUREMENT_ID` — já coletado pelo Google Agent
387
+ - Secret `GA4_API_SECRET` — já configurado pelo Google Agent
388
+ - Perfil D1: `ga_client_id` (cookie `_ga`), `gclid`, `wbraid`, `gbraid` — para atribuição YouTube
389
+ - Status de iframes: verificar se embeds têm `?enablejsapi=1` para BehaviorEngine
390
+
391
+ ## RESPONSABILIDADE
392
+
393
+ - Gerar eventos de progresso de vídeo (`video_start`, `video_progress_25/50/75/90`, `video_complete`) via GA4
394
+ - Implementar YouTube IFrame API listener para rastreamento de VSL no browser
395
+ - Garantir `gclid`, `wbraid`, `gbraid` chegando ao Worker (nunca hashear estes campos)
396
+ - Persistir `ga_client_id` no D1 para cruzamento com conversões YouTube Ads
397
+ - Ativar Consent Mode v2 com `url_passthrough: true` (obrigatório para modelagem de conversão)
398
+ - Orientar Customer Match: exportar emails/phones do D1 com SHA-256 para Google Ads
399
+
400
+ ## SAÍDA
401
+
402
+ ```json
403
+ {
404
+ "arquivos_gerados": {
405
+ "browser": "cdpTrack.js (eventos YouTube + IFrame API listener)",
406
+ "server": "cloudflare/google-mp.js (já inclui YouTube via GA4)"
407
+ },
408
+ "eventos_implementados": [
409
+ "video_start",
410
+ "video_progress_25", "video_progress_50", "video_progress_75", "video_progress_90",
411
+ "video_complete",
412
+ "generate_lead",
413
+ "purchase"
414
+ ],
415
+ "requisitos_iframe": "?enablejsapi=1 obrigatório nos embeds YouTube",
416
+ "consent_mode_v2": true,
417
+ "url_passthrough": true,
418
+ "click_ids_capturados": ["gclid", "wbraid", "gbraid"],
419
+ "d1_persiste": ["ga_client_id", "gclid", "wbraid", "gbraid"],
420
+ "customer_match": "emails/phones exportados do D1 com SHA-256"
421
+ }
422
+ ```
@@ -0,0 +1,285 @@
1
+ /**
2
+ * ANTI-BLOCKING STRATEGY - CDP Edge (Quantum Tier)
3
+ *
4
+ * Sistema para maximizar resiliência contra ad-blockers e garantir
5
+ * que o tracking funcione mesmo em ambientes hostis.
6
+ *
7
+ * @version 1.0.0
8
+ */
9
+
10
+ // ── Guards ────────────────────────────────────────────────
11
+ const isBrowser = typeof window !== 'undefined';
12
+
13
+ // ── Configurações de Anti-Blocking ─────────────────────
14
+
15
+ const ANTI_BLOCKING_CONFIG = {
16
+ // Mesmo domínio evita bloqueios de CORS e ad-blockers
17
+ endpoint: '/api/tracking',
18
+
19
+ // Retries com exponential backoff
20
+ maxRetries: 3,
21
+ retryDelays: [1000, 3000, 6000], // 1s, 3s, 6s
22
+
23
+ // Fallback para Beacon API (quando fetch falha)
24
+ useBeaconFallback: true,
25
+
26
+ // First-party cookies (ad-block proof)
27
+ cookieDuration: 60 * 60 * 24 * 365, // 365 dias
28
+ cookieDomain: '', // Será definido dinamicamente
29
+
30
+ // Detectar ad-blockers
31
+ detectAdBlocker: true,
32
+ adBlockerBaitClass: 'adsbox adbanner pub_300x250',
33
+
34
+ // Lightweight code (evitar patterns de bloqueio)
35
+ minify: false, // Opcional: usar código minificado em produção
36
+ noConsoleLogs: false, // Opcional: remover console.logs em produção
37
+ };
38
+
39
+ // ── Detecção de Ad-Blocker ─────────────────────────
40
+
41
+ /**
42
+ * Detecta se um ad-blocker está ativo
43
+ *
44
+ * @returns {boolean} True se ad-blocker detectado
45
+ */
46
+ function detectAdBlocker() {
47
+ if (!isBrowser || !ANTI_BLOCKING_CONFIG.detectAdBlocker) return false;
48
+
49
+ // Método 1: Criar elemento com classe comum de ads
50
+ const baitElement = document.createElement('div');
51
+ baitElement.innerHTML = '&nbsp;';
52
+ baitElement.className = ANTI_BLOCKING_CONFIG.adBlockerBaitClass;
53
+ baitElement.style.cssText = 'position: absolute; top: -1000px; left: -1000px;';
54
+ document.body.appendChild(baitElement);
55
+
56
+ const isBlocked = getComputedStyle(baitElement).display === 'none';
57
+
58
+ document.body.removeChild(baitElement);
59
+
60
+ // Método 2: Verificar se bloqueia requests de tracking
61
+ try {
62
+ const testPixel = new Image();
63
+ testPixel.src = '/pixel-test.png?t=' + Date.now();
64
+ testPixel.onload = () => console.log('✅ Pixel não bloqueado');
65
+ testPixel.onerror = () => console.warn('⚠️ Pixel pode estar bloqueado');
66
+ } catch (error) {
67
+ console.warn('⚠️ Erro ao testar pixel:', error);
68
+ }
69
+
70
+ return isBlocked;
71
+ }
72
+
73
+ // ── Resiliência de Envio ─────────────────────────────
74
+
75
+ /**
76
+ * Envia dados com retry automático (exponential backoff)
77
+ *
78
+ * @param {object} data - Dados para enviar
79
+ * @param {string} endpoint - Endpoint de destino
80
+ * @returns {Promise} Promise com resultado
81
+ */
82
+ async function sendWithRetry(data, endpoint = ANTI_BLOCKING_CONFIG.endpoint) {
83
+ if (!isBrowser) return { success: false, error: 'Not in browser' };
84
+
85
+ let lastError = null;
86
+
87
+ for (let attempt = 0; attempt < ANTI_BLOCKING_CONFIG.maxRetries; attempt++) {
88
+ try {
89
+ // Tenta enviar via fetch
90
+ const response = await fetch(endpoint, {
91
+ method: 'POST',
92
+ headers: {
93
+ 'Content-Type': 'application/json',
94
+ },
95
+ body: JSON.stringify(data),
96
+ keepalive: true, // Garante envio mesmo se usuário fechar aba
97
+ credentials: 'same-origin', // First-party cookies
98
+ cache: 'no-cache' // Evitar cache de requests de tracking
99
+ });
100
+
101
+ if (response.ok) {
102
+ console.log(`✅ Envio bem-sucedido (tentativa ${attempt + 1})`);
103
+ return await response.json();
104
+ } else {
105
+ const errorText = await response.text();
106
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
107
+ }
108
+ } catch (error) {
109
+ lastError = error;
110
+ console.warn(`⚠️ Tentativa ${attempt + 1} falhou:`, error.message);
111
+
112
+ // Se não for a última tentativa, aguarda antes de retry
113
+ if (attempt < ANTI_BLOCKING_CONFIG.maxRetries - 1) {
114
+ const delay = ANTI_BLOCKING_CONFIG.retryDelays[attempt];
115
+ console.log(`⏳ Aguardando ${delay}ms antes de retry...`);
116
+ await sleep(delay);
117
+ }
118
+ }
119
+ }
120
+
121
+ // Todas as tentativas falharam
122
+ console.error('❌ Todas as tentativas de envio falharam:', lastError);
123
+
124
+ // Fallback: Beacon API
125
+ if (ANTI_BLOCKING_CONFIG.useBeaconFallback && navigator.sendBeacon) {
126
+ console.log('🔄 Tentando Beacon API como fallback...');
127
+ const beaconSuccess = navigator.sendBeacon(endpoint, JSON.stringify(data));
128
+
129
+ if (beaconSuccess) {
130
+ console.log('✅ Beacon API bem-sucedido');
131
+ return { success: true, method: 'beacon' };
132
+ } else {
133
+ console.error('❌ Beacon API também falhou');
134
+ }
135
+ }
136
+
137
+ return { success: false, error: lastError?.message, attempts: ANTI_BLOCKING_CONFIG.maxRetries };
138
+ }
139
+
140
+ /**
141
+ * Função utilitária de delay
142
+ */
143
+ function sleep(ms) {
144
+ return new Promise(resolve => setTimeout(resolve, ms));
145
+ }
146
+
147
+ // ── First-Party Cookies (Ad-Block Proof) ───────────────
148
+
149
+ /**
150
+ * Define cookie first-party (não bloqueado por ad-blockers)
151
+ *
152
+ * @param {string} name - Nome do cookie
153
+ * @param {string} value - Valor do cookie
154
+ * @param {number} maxAge - Tempo de vida em segundos
155
+ */
156
+ function setFirstPartyCookie(name, value, maxAge = ANTI_BLOCKING_CONFIG.cookieDuration) {
157
+ if (!isBrowser) return;
158
+
159
+ // Extrair domínio atual (para umbrella domain)
160
+ const currentDomain = window.location.hostname;
161
+ const rootDomain = currentDomain.split('.').slice(-2).join('.'); // ex: example.com
162
+
163
+ const cookieOptions = [
164
+ `${name}=${value}`,
165
+ `max-age=${maxAge}`,
166
+ 'path=/',
167
+ `domain=.${rootDomain}`, // Umbrella domain para subdomínios
168
+ 'SameSite=Lax',
169
+ 'Secure'
170
+ ].join('; ');
171
+
172
+ document.cookie = cookieOptions;
173
+ }
174
+
175
+ /**
176
+ * Obtém cookie first-party
177
+ *
178
+ * @param {string} name - Nome do cookie
179
+ * @returns {string|null} Valor do cookie ou null
180
+ */
181
+ function getFirstPartyCookie(name) {
182
+ if (!isBrowser) return null;
183
+
184
+ const value = `; ${document.cookie}`;
185
+ const parts = value.split(`; ${name}=`);
186
+
187
+ if (parts.length === 2) {
188
+ return parts.pop().split(';').shift();
189
+ }
190
+
191
+ return null;
192
+ }
193
+
194
+ // ── Lightweight Code (Evitar Patterns de Bloqueio) ─────────
195
+
196
+ /**
197
+ * Verifica se código deve ser minificado (evitar palavras-chave de ad-blockers)
198
+ *
199
+ * @returns {boolean} True se deve minificar
200
+ */
201
+ function shouldMinifyCode() {
202
+ return ANTI_BLOCKING_CONFIG.minify && isBrowser;
203
+ }
204
+
205
+ /**
206
+ * Remove console.logs se configurado (evitar detecção)
207
+ *
208
+ * @param {boolean} remove - Remove console.logs?
209
+ */
210
+ function configureConsoleLogs(remove = ANTI_BLOCKING_CONFIG.noConsoleLogs) {
211
+ if (!isBrowser || !remove) return;
212
+
213
+ // Sobrescrever console com funções vazias
214
+ const noop = () => {};
215
+ console.log = noop;
216
+ console.warn = noop;
217
+ console.error = noop;
218
+ }
219
+
220
+ // ── Same-Domain Protocol (Anti-Adblock) ─────────────
221
+
222
+ /**
223
+ * Verifica se endpoint está no mesmo domínio
224
+ *
225
+ * @param {string} endpoint - Endpoint para verificar
226
+ * @returns {boolean} True se mesmo domínio
227
+ */
228
+ function isSameDomain(endpoint) {
229
+ if (!isBrowser) return true;
230
+
231
+ const endpointUrl = new URL(endpoint, window.location.href);
232
+ return endpointUrl.hostname === window.location.hostname;
233
+ }
234
+
235
+ // ── Inicialização ────────────────────────────────────────────
236
+
237
+ /**
238
+ * Inicializa sistema de anti-blocking
239
+ */
240
+ function initAntiBlocking() {
241
+ if (!isBrowser) return;
242
+
243
+ console.log('🛡️ Inicializando Anti-Blocking System...');
244
+
245
+ // 1. Detectar ad-blocker
246
+ const adBlockerActive = detectAdBlocker();
247
+ if (adBlockerActive) {
248
+ console.warn('⚠️ Ad-Blocker detectado - usando estratégias de resiliência');
249
+ // Enviar evento de ad-blocker detectado
250
+ if (typeof cdpTrack !== 'undefined' && cdpTrack.track) {
251
+ cdpTrack.track('adblocker_detected', {
252
+ user_agent: navigator.userAgent,
253
+ timestamp: Date.now()
254
+ });
255
+ }
256
+ }
257
+
258
+ // 2. Configurar first-party cookies
259
+ const userId = getFirstPartyCookie('_cdp_uid');
260
+ if (!userId) {
261
+ const newUserId = `${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
262
+ setFirstPartyCookie('_cdp_uid', newUserId);
263
+ }
264
+
265
+ // 3. Configurar console logs (se necessário)
266
+ if (ANTI_BLOCKING_CONFIG.noConsoleLogs) {
267
+ configureConsoleLogs(true);
268
+ }
269
+
270
+ console.log('✅ Anti-Blocking System inicializado');
271
+ }
272
+
273
+ // ── Exportações ────────────────────────────────────────────────
274
+
275
+ export {
276
+ sendWithRetry,
277
+ detectAdBlocker,
278
+ setFirstPartyCookie,
279
+ getFirstPartyCookie,
280
+ isSameDomain,
281
+ configureConsoleLogs,
282
+ shouldMinifyCode,
283
+ ANTI_BLOCKING_CONFIG,
284
+ initAntiBlocking
285
+ };