cdp-edge 1.0.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.
- package/README.md +324 -0
- package/bin/cdp-edge.js +71 -0
- package/contracts/agent-versions.json +679 -0
- package/contracts/api-versions.json +372 -0
- package/contracts/types.ts +81 -0
- package/dist/commands/analyze.js +52 -0
- package/dist/commands/infra.js +54 -0
- package/dist/commands/install.js +191 -0
- package/dist/commands/server.js +174 -0
- package/dist/commands/setup.js +355 -0
- package/dist/commands/validate.js +248 -0
- package/dist/index.js +12 -0
- package/dist/sdk/cdpTrack.js +2095 -0
- package/dist/sdk/cdpTrack.min.js +64 -0
- package/dist/sdk/install-snippet.html +10 -0
- package/docs/CI-CD-SETUP.md +217 -0
- package/docs/events-reference.md +359 -0
- package/docs/installation.md +155 -0
- package/docs/quick-start.md +185 -0
- package/docs/sdk-reference.md +371 -0
- package/docs/whatsapp-ctwa.md +210 -0
- package/extracted-skill/tracking-events-generator/INDEX.md +94 -0
- package/extracted-skill/tracking-events-generator/INSTALACAO-CDPEDGE.md +58 -0
- package/extracted-skill/tracking-events-generator/INTEGRACAO-COMPLETA.md +683 -0
- package/extracted-skill/tracking-events-generator/MELHORIAS-IMPLEMENTADAS.md +513 -0
- package/extracted-skill/tracking-events-generator/Premium-Tracking-Intelligence-Resumo.md +333 -0
- package/extracted-skill/tracking-events-generator/SKILL.md +257 -0
- package/extracted-skill/tracking-events-generator/advanced-matching.js +364 -0
- package/extracted-skill/tracking-events-generator/agents/ab-ltv-agent.md +196 -0
- package/extracted-skill/tracking-events-generator/agents/ab-testing-agent.md +54 -0
- package/extracted-skill/tracking-events-generator/agents/attribution-agent.md +1304 -0
- package/extracted-skill/tracking-events-generator/agents/bidding-agent.md +347 -0
- package/extracted-skill/tracking-events-generator/agents/bing-agent.md +66 -0
- package/extracted-skill/tracking-events-generator/agents/browser-tracking.md +364 -0
- package/extracted-skill/tracking-events-generator/agents/code-guardian-agent.md +149 -0
- package/extracted-skill/tracking-events-generator/agents/compliance-agent.md +2097 -0
- package/extracted-skill/tracking-events-generator/agents/crm-integration-agent.md +1459 -0
- package/extracted-skill/tracking-events-generator/agents/dashboard-agent.md +456 -0
- package/extracted-skill/tracking-events-generator/agents/database-agent.md +668 -0
- package/extracted-skill/tracking-events-generator/agents/debug-agent.md +1455 -0
- package/extracted-skill/tracking-events-generator/agents/devops-agent.md +232 -0
- package/extracted-skill/tracking-events-generator/agents/domain-setup-agent.md +238 -0
- package/extracted-skill/tracking-events-generator/agents/email-agent.md +88 -0
- package/extracted-skill/tracking-events-generator/agents/fingerprint-agent.md +257 -0
- package/extracted-skill/tracking-events-generator/agents/fraud-detection-agent.md +143 -0
- package/extracted-skill/tracking-events-generator/agents/google-agent.md +235 -0
- package/extracted-skill/tracking-events-generator/agents/intelligence-agent.md +525 -0
- package/extracted-skill/tracking-events-generator/agents/lead-scoring-agent.md +282 -0
- package/extracted-skill/tracking-events-generator/agents/linkedin-agent.md +173 -0
- package/extracted-skill/tracking-events-generator/agents/localization-agent.md +55 -0
- package/extracted-skill/tracking-events-generator/agents/ltv-predictor-agent.md +59 -0
- package/extracted-skill/tracking-events-generator/agents/master-feedback-loop.md +960 -0
- package/extracted-skill/tracking-events-generator/agents/master-orchestrator.md +2154 -0
- package/extracted-skill/tracking-events-generator/agents/match-quality-agent.md +304 -0
- package/extracted-skill/tracking-events-generator/agents/memory-agent.json +25 -0
- package/extracted-skill/tracking-events-generator/agents/memory-agent.md +878 -0
- package/extracted-skill/tracking-events-generator/agents/meta-agent.md +118 -0
- package/extracted-skill/tracking-events-generator/agents/ml-clustering-agent.md +749 -0
- package/extracted-skill/tracking-events-generator/agents/page-analyzer.md +272 -0
- package/extracted-skill/tracking-events-generator/agents/performance-agent.md +1167 -0
- package/extracted-skill/tracking-events-generator/agents/performance-optimization-agent.md +1442 -0
- package/extracted-skill/tracking-events-generator/agents/pinterest-agent.md +318 -0
- package/extracted-skill/tracking-events-generator/agents/premium-tracking-intelligence-agent.md +849 -0
- package/extracted-skill/tracking-events-generator/agents/r2-setup-agent.md +258 -0
- package/extracted-skill/tracking-events-generator/agents/reddit-agent.md +321 -0
- package/extracted-skill/tracking-events-generator/agents/security-enterprise-agent.md +1861 -0
- package/extracted-skill/tracking-events-generator/agents/server-tracking.md +1188 -0
- package/extracted-skill/tracking-events-generator/agents/spotify-agent.md +391 -0
- package/extracted-skill/tracking-events-generator/agents/tiktok-agent.md +182 -0
- package/extracted-skill/tracking-events-generator/agents/tracking-plan-agent.md +459 -0
- package/extracted-skill/tracking-events-generator/agents/utm-agent.md +322 -0
- package/extracted-skill/tracking-events-generator/agents/validator-agent.md +271 -0
- package/extracted-skill/tracking-events-generator/agents/webhook-agent.md +177 -0
- package/extracted-skill/tracking-events-generator/agents/whatsapp-agent.md +129 -0
- package/extracted-skill/tracking-events-generator/agents/whatsapp-ctwa-setup-agent.md +707 -0
- package/extracted-skill/tracking-events-generator/agents/youtube-agent.md +537 -0
- package/extracted-skill/tracking-events-generator/anti-blocking.js +285 -0
- package/extracted-skill/tracking-events-generator/cdpTrack.js +640 -0
- package/extracted-skill/tracking-events-generator/contracts/api-versions.json +372 -0
- package/extracted-skill/tracking-events-generator/docs/guia-cloudflare-iniciante.md +107 -0
- package/extracted-skill/tracking-events-generator/engagement-scoring.js +226 -0
- package/extracted-skill/tracking-events-generator/evals/evals.json +235 -0
- package/extracted-skill/tracking-events-generator/integration-test.js +497 -0
- package/extracted-skill/tracking-events-generator/knowledge-base.md +3066 -0
- package/extracted-skill/tracking-events-generator/micro-events.js +992 -0
- package/extracted-skill/tracking-events-generator/models/captura-de-lead.md +78 -0
- package/extracted-skill/tracking-events-generator/models/captura-lead-evento-externo.md +99 -0
- package/extracted-skill/tracking-events-generator/models/checkout-proprio.md +111 -0
- package/extracted-skill/tracking-events-generator/models/lancamento-imobiliario.md +344 -0
- package/extracted-skill/tracking-events-generator/models/multi-step-checkout.md +672 -0
- package/extracted-skill/tracking-events-generator/models/pagina-obrigado.md +55 -0
- package/extracted-skill/tracking-events-generator/models/pinterest/conversions-api-template.js +144 -0
- package/extracted-skill/tracking-events-generator/models/pinterest/event-mappings.json +48 -0
- package/extracted-skill/tracking-events-generator/models/pinterest/tag-template.js +28 -0
- package/extracted-skill/tracking-events-generator/models/quiz-funnel.md +132 -0
- package/extracted-skill/tracking-events-generator/models/reddit/conversions-api-template.js +205 -0
- package/extracted-skill/tracking-events-generator/models/reddit/event-mappings.json +56 -0
- package/extracted-skill/tracking-events-generator/models/reddit/pixel-template.js +19 -0
- package/extracted-skill/tracking-events-generator/models/scenarios/behavior-engine.js +425 -0
- package/extracted-skill/tracking-events-generator/models/scenarios/real-estate-logic.md +50 -0
- package/extracted-skill/tracking-events-generator/models/scenarios/sales-page-logic.md +50 -0
- package/extracted-skill/tracking-events-generator/models/trafego-direto.md +582 -0
- package/extracted-skill/tracking-events-generator/models/webinar-registration.md +63 -0
- package/extracted-skill/tracking-events-generator/route-intent-capture.js +222 -0
- package/extracted-skill/tracking-events-generator/tracking.config.js +46 -0
- package/extracted-skill/tracking-events-generator/walkthrough.md +26 -0
- package/package.json +89 -0
- package/scripts/build-sdk.js +106 -0
- package/server-edge-tracker/.client.env.example +14 -0
- package/server-edge-tracker/INSTALAR.md +527 -0
- package/server-edge-tracker/SEGMENTATION-DOCS.md +513 -0
- package/server-edge-tracker/config/utm-mapping.json +64 -0
- package/server-edge-tracker/deploy-client.cjs +76 -0
- package/server-edge-tracker/index.ts +1164 -0
- package/server-edge-tracker/migrate-new-db.sql +137 -0
- package/server-edge-tracker/migrate-v2.sql +16 -0
- package/server-edge-tracker/migrate-v3.sql +6 -0
- package/server-edge-tracker/migrate-v4.sql +18 -0
- package/server-edge-tracker/migrate-v5.sql +17 -0
- package/server-edge-tracker/migrate-v6.sql +24 -0
- package/server-edge-tracker/migrate-v7.sql +64 -0
- package/server-edge-tracker/migrate.sql +111 -0
- package/server-edge-tracker/modules/db.ts +702 -0
- package/server-edge-tracker/modules/dispatch/ga4.ts +72 -0
- package/server-edge-tracker/modules/dispatch/meta.ts +143 -0
- package/server-edge-tracker/modules/dispatch/platforms.ts +255 -0
- package/server-edge-tracker/modules/dispatch/tiktok.ts +107 -0
- package/server-edge-tracker/modules/dispatch/whatsapp.ts +279 -0
- package/server-edge-tracker/modules/intelligence.ts +589 -0
- package/server-edge-tracker/modules/ml/bidding.ts +247 -0
- package/server-edge-tracker/modules/ml/fraud.ts +302 -0
- package/server-edge-tracker/modules/ml/logistic.ts +226 -0
- package/server-edge-tracker/modules/ml/ltv.ts +531 -0
- package/server-edge-tracker/modules/ml/matchquality.ts +232 -0
- package/server-edge-tracker/modules/ml/quiz.ts +343 -0
- package/server-edge-tracker/modules/ml/roas.ts +255 -0
- package/server-edge-tracker/modules/ml/segmentation.ts +407 -0
- package/server-edge-tracker/modules/nurture.ts +257 -0
- package/server-edge-tracker/modules/utils.ts +311 -0
- package/server-edge-tracker/modules/utm/utm-enricher.ts +231 -0
- package/server-edge-tracker/schema-ab-ltv.sql +97 -0
- package/server-edge-tracker/schema-bidding.sql +86 -0
- package/server-edge-tracker/schema-fraud.sql +90 -0
- package/server-edge-tracker/schema-indexes.sql +67 -0
- package/server-edge-tracker/schema-ltv-feedback.sql +11 -0
- package/server-edge-tracker/schema-quiz.sql +52 -0
- package/server-edge-tracker/schema-sales-engine.sql +113 -0
- package/server-edge-tracker/schema-segmentation.sql +219 -0
- package/server-edge-tracker/schema-utm.sql +82 -0
- package/server-edge-tracker/schema.sql +265 -0
- package/server-edge-tracker/types.ts +258 -0
- package/server-edge-tracker/wrangler.toml +136 -0
- package/templates/afiliado-sem-landing.md +312 -0
- package/templates/captura-de-lead.md +78 -0
- package/templates/captura-lead-evento-externo.md +99 -0
- package/templates/checkout-proprio.md +111 -0
- package/templates/install/.claude/commands/cdp.md +1 -0
- package/templates/install/CLAUDE.md +65 -0
- package/templates/lancamento-imobiliario.md +344 -0
- package/templates/linkedin/tag-template.js +46 -0
- package/templates/multi-step-checkout.md +672 -0
- package/templates/pagina-obrigado.md +55 -0
- package/templates/pinterest/conversions-api-template.js +144 -0
- package/templates/pinterest/event-mappings.json +48 -0
- package/templates/pinterest/tag-template.js +28 -0
- package/templates/quiz-funnel.md +132 -0
- package/templates/reddit/conversions-api-template.js +205 -0
- package/templates/reddit/event-mappings.json +56 -0
- package/templates/reddit/pixel-template.js +19 -0
- package/templates/scenarios/behavior-engine.js +425 -0
- package/templates/scenarios/real-estate-logic.md +50 -0
- package/templates/scenarios/sales-page-logic.md +50 -0
- package/templates/spotify/pixel-template.js +46 -0
- package/templates/trafego-direto.md +582 -0
- package/templates/vsl-page.md +292 -0
- package/templates/webinar-registration.md +63 -0
|
@@ -0,0 +1,537 @@
|
|
|
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
|
+
```typescript
|
|
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_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 — YouTube IFrame API
|
|
93
|
+
|
|
94
|
+
Para usar, o iframe deve ter `enablejsapi=1`:
|
|
95
|
+
|
|
96
|
+
```html
|
|
97
|
+
<!-- Embed YouTube com JS API habilitada (obrigatório) -->
|
|
98
|
+
<iframe
|
|
99
|
+
id="video-tour-imovel"
|
|
100
|
+
src="https://www.youtube.com/embed/VIDEO_ID?enablejsapi=1&origin=https://seudominio.com.br"
|
|
101
|
+
allow="autoplay"
|
|
102
|
+
></iframe>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
#### Implementação real do YouTube IFrame API listener
|
|
106
|
+
|
|
107
|
+
```javascript
|
|
108
|
+
/**
|
|
109
|
+
* YouTube IFrame API Listener — injeta no behavior-engine.js ou tracking.js
|
|
110
|
+
* Rastreia: video_start, video_25, video_50, video_75, video_complete
|
|
111
|
+
* Dispara via cdpTrack.track() para o Worker → GA4 MP + demais plataformas
|
|
112
|
+
*/
|
|
113
|
+
|
|
114
|
+
// Carregar YouTube IFrame API (uma vez por página)
|
|
115
|
+
(function initYouTubeTracking() {
|
|
116
|
+
if (window._ytTrackingInitialized) return;
|
|
117
|
+
window._ytTrackingInitialized = true;
|
|
118
|
+
|
|
119
|
+
// Mapa de iframes já trackeados
|
|
120
|
+
const trackedPlayers = new Map();
|
|
121
|
+
|
|
122
|
+
// Injetar API script do YouTube (não carrega 2x se já existe)
|
|
123
|
+
if (!document.getElementById('youtube-iframe-api')) {
|
|
124
|
+
const tag = document.createElement('script');
|
|
125
|
+
tag.id = 'youtube-iframe-api';
|
|
126
|
+
tag.src = 'https://www.youtube.com/iframe_api';
|
|
127
|
+
document.head.appendChild(tag);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Callback global chamado pelo YouTube quando API estiver pronta
|
|
131
|
+
window.onYouTubeIframeAPIReady = function() {
|
|
132
|
+
// Auto-detectar todos os iframes com enablejsapi=1
|
|
133
|
+
document.querySelectorAll('iframe[src*="youtube.com/embed"]').forEach(iframe => {
|
|
134
|
+
if (trackedPlayers.has(iframe.id)) return;
|
|
135
|
+
|
|
136
|
+
const videoTitle = iframe.title || iframe.id || 'YouTube Video';
|
|
137
|
+
|
|
138
|
+
const player = new YT.Player(iframe.id, {
|
|
139
|
+
events: {
|
|
140
|
+
onStateChange: (event) => handlePlayerStateChange(event, player, videoTitle),
|
|
141
|
+
onReady: (event) => handlePlayerReady(event, player, videoTitle)
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
trackedPlayers.set(iframe.id, { player, milestone: new Set() });
|
|
146
|
+
});
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// Se API já carregada (SPA reload), inicializar diretamente
|
|
150
|
+
if (typeof YT !== 'undefined' && YT.Player) {
|
|
151
|
+
window.onYouTubeIframeAPIReady();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function handlePlayerReady(event, player, videoTitle) {
|
|
155
|
+
// Iniciar polling de progresso
|
|
156
|
+
const iframeId = player.getIframe().id;
|
|
157
|
+
const state = trackedPlayers.get(iframeId);
|
|
158
|
+
|
|
159
|
+
const interval = setInterval(() => {
|
|
160
|
+
if (!player.getDuration) return;
|
|
161
|
+
const duration = player.getDuration();
|
|
162
|
+
const current = player.getCurrentTime();
|
|
163
|
+
if (duration <= 0) return;
|
|
164
|
+
|
|
165
|
+
const percent = Math.floor((current / duration) * 100);
|
|
166
|
+
|
|
167
|
+
// Disparar milestones: 25, 50, 75 (100% é coberto pelo estado ENDED)
|
|
168
|
+
const milestoneEvents = { 25: 'video_25', 50: 'video_50', 75: 'video_75' };
|
|
169
|
+
[25, 50, 75].forEach(milestone => {
|
|
170
|
+
if (percent >= milestone && !state.milestone.has(milestone)) {
|
|
171
|
+
state.milestone.add(milestone);
|
|
172
|
+
|
|
173
|
+
window.cdpTrack?.track(milestoneEvents[milestone], {
|
|
174
|
+
content_name: videoTitle,
|
|
175
|
+
video_percent: milestone,
|
|
176
|
+
video_duration: Math.round(duration),
|
|
177
|
+
video_provider: 'youtube',
|
|
178
|
+
value: 0,
|
|
179
|
+
currency: 'BRL'
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}, 1000); // checar a cada 1s
|
|
184
|
+
|
|
185
|
+
state.progressInterval = interval;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function handlePlayerStateChange(event, player, videoTitle) {
|
|
189
|
+
const iframeId = player.getIframe().id;
|
|
190
|
+
const state = trackedPlayers.get(iframeId);
|
|
191
|
+
|
|
192
|
+
// YT.PlayerState: PLAYING=1, PAUSED=2, ENDED=0, BUFFERING=3
|
|
193
|
+
switch (event.data) {
|
|
194
|
+
case YT.PlayerState.PLAYING:
|
|
195
|
+
if (!state.started) {
|
|
196
|
+
state.started = true;
|
|
197
|
+
window.cdpTrack?.track('video_start', {
|
|
198
|
+
content_name: videoTitle,
|
|
199
|
+
video_duration: Math.round(player.getDuration() || 0),
|
|
200
|
+
video_provider: 'youtube'
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
break;
|
|
204
|
+
|
|
205
|
+
case YT.PlayerState.ENDED:
|
|
206
|
+
clearInterval(state.progressInterval);
|
|
207
|
+
window.cdpTrack?.track('video_complete', {
|
|
208
|
+
content_name: videoTitle,
|
|
209
|
+
video_duration: Math.round(player.getDuration() || 0),
|
|
210
|
+
video_provider: 'youtube'
|
|
211
|
+
});
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
})();
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
O listener dispara via `cdpTrack.track()`:
|
|
219
|
+
- `video_start` — primeiros 2s de play
|
|
220
|
+
- `video_25`, `video_50`, `video_75` — marcos de progresso (25/50/75%)
|
|
221
|
+
- `video_complete` — 100% assistido
|
|
222
|
+
|
|
223
|
+
### 3. Evento de Lead após assistir vídeo (imóveis)
|
|
224
|
+
|
|
225
|
+
```javascript
|
|
226
|
+
// Disparar Lead qualificado quando usuário assiste 75%+ do tour
|
|
227
|
+
// Adicionar dentro do callback de milestoneEvents no IFrame API listener:
|
|
228
|
+
// milestoneEvents[75] → 'video_75' — adicionar lógica abaixo no bloco forEach
|
|
229
|
+
if (milestone === 75) {
|
|
230
|
+
window.cdpTrack?.track('InitiateCheckout', {
|
|
231
|
+
content_name: 'Tour_Virtual_Empreendimento',
|
|
232
|
+
value: 0,
|
|
233
|
+
currency: 'BRL',
|
|
234
|
+
// Sinaliza alta intenção para Meta + Google
|
|
235
|
+
meta_intensity: 'high',
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### 4. Consent Mode v2 — OBRIGATÓRIO para YouTube/Google Ads
|
|
241
|
+
|
|
242
|
+
YouTube Ads usa sinais de consent para modelagem de conversão.
|
|
243
|
+
Sem isso, Google desativa modelagem e conversões ficam subnotificadas.
|
|
244
|
+
|
|
245
|
+
```javascript
|
|
246
|
+
// Já implementado em cdpTrack.js via initConsentMode()
|
|
247
|
+
// Para banners de cookies — chamar após aceite:
|
|
248
|
+
cdpTrack.updateConsent({ analytics: true, ads: true });
|
|
249
|
+
|
|
250
|
+
// Para usuários que recusam — manter negado (padrão)
|
|
251
|
+
// cdpTrack.updateConsent({ analytics: false, ads: false }); // já é o default
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## 🛠️ IMPLEMENTAÇÃO SERVER — index.ts
|
|
257
|
+
|
|
258
|
+
### 1. Extrair e persistir Click IDs do YouTube
|
|
259
|
+
|
|
260
|
+
No handler `/track`, os click IDs já chegam no payload via `cdpTrack.js`.
|
|
261
|
+
O `upsertProfile()` já persiste `gclid`, `wbraid`, `gbraid` no D1.
|
|
262
|
+
|
|
263
|
+
Para verificar persistência correta:
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
// D1: user_profiles — colunas já existentes
|
|
267
|
+
// gclid TEXT — Google Ads standard click ID
|
|
268
|
+
// wbraid TEXT — iOS privacy-preserving (YouTube)
|
|
269
|
+
// gbraid TEXT — App campaigns privacy-preserving
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### 2. GA4 Measurement Protocol — Eventos de Vídeo
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
// No sendGA4Mp() — adicionar mapeamento de eventos YouTube
|
|
276
|
+
const VIDEO_GA4_MAP = {
|
|
277
|
+
video_start: 'video_start',
|
|
278
|
+
video_25: 'video_progress', // GA4 usa video_progress com percent
|
|
279
|
+
video_50: 'video_progress',
|
|
280
|
+
video_75: 'video_progress',
|
|
281
|
+
video_complete: 'video_complete',
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
// Params obrigatórios para video_progress (GA4)
|
|
285
|
+
const videoParams = {
|
|
286
|
+
video_title: contentName || '',
|
|
287
|
+
video_duration: payload.videoDuration || 0,
|
|
288
|
+
video_percent: payload.videoPercent || 0, // 25, 50, 75, 100
|
|
289
|
+
video_provider: 'youtube',
|
|
290
|
+
visible: true,
|
|
291
|
+
};
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### 3. Google Ads Enhanced Conversions — Lead de Vídeo
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
// Conversão de Lead gerada por campanha YouTube
|
|
298
|
+
// Envia para GA4 MP com user_data para Enhanced Conversions
|
|
299
|
+
const enhancedConversionPayload = {
|
|
300
|
+
client_id: payload.gaClientId, // _ga cookie — obrigatório
|
|
301
|
+
user_data: {
|
|
302
|
+
email_address: payload.email, // não hashear — GA4 MP faz internamente
|
|
303
|
+
phone_number: payload.phone,
|
|
304
|
+
address: {
|
|
305
|
+
first_name: payload.firstName,
|
|
306
|
+
last_name: payload.lastName,
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
events: [{
|
|
310
|
+
name: 'generate_lead',
|
|
311
|
+
params: {
|
|
312
|
+
value: payload.value || 0,
|
|
313
|
+
currency: 'BRL',
|
|
314
|
+
transaction_id: payload.eventId, // deduplicação
|
|
315
|
+
// Atribuição YouTube
|
|
316
|
+
gclid: payload.gclid || undefined,
|
|
317
|
+
wbraid: payload.wbraid || undefined,
|
|
318
|
+
gbraid: payload.gbraid || undefined,
|
|
319
|
+
}
|
|
320
|
+
}]
|
|
321
|
+
};
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### 4. View-Through Conversion (VTC) — Bumpers
|
|
325
|
+
|
|
326
|
+
Para campanhas Bumper/Non-skip, o usuário converte DEPOIS sem clicar.
|
|
327
|
+
O Worker detecta isso quando um Lead chega SEM gclid mas com histórico de impressão YouTube:
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
// No upsertProfile() — verificar se perfil tem impressão YouTube recente
|
|
331
|
+
// (requer webhook do Google Ads — avançado, Fase 5)
|
|
332
|
+
// Por ora: registrar ausência de gclid + utm_source=youtube como view-through candidate
|
|
333
|
+
if (!payload.gclid && payload.utmSource === 'youtube') {
|
|
334
|
+
payload.vtcCandidate = true;
|
|
335
|
+
// Logar para análise manual no D1
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## 📊 EVENTOS PADRÃO — YouTube Campaigns
|
|
342
|
+
|
|
343
|
+
| Evento cdpTrack | Mapeamento GA4 | Mapeamento Google Ads | Quando Disparar |
|
|
344
|
+
|---|---|---|---|
|
|
345
|
+
| `video_start` | `video_start` | — | Primeiros 2s de reprodução |
|
|
346
|
+
| `video_25` | `video_progress` | — | 25% assistido |
|
|
347
|
+
| `video_50` | `video_progress` | `engaged_view` candidate | 50% assistido |
|
|
348
|
+
| `video_75` | `video_progress` | `engaged_view` | 75% assistido — alta intenção |
|
|
349
|
+
| `video_complete` | `video_complete` | `video_view_complete` | 100% assistido |
|
|
350
|
+
| `Lead` (após vídeo) | `generate_lead` | Conversão primária | Formulário submetido |
|
|
351
|
+
| `InitiateCheckout` | `begin_checkout` | Conversão micro | Clique em "Quero saber mais" |
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## 🏠 ESTRATÉGIA ESPECÍFICA — IMÓVEIS
|
|
356
|
+
|
|
357
|
+
### Funil recomendado para lançamentos
|
|
358
|
+
|
|
359
|
+
```
|
|
360
|
+
FASE 1: AWARENESS (YouTube TrueView 30s)
|
|
361
|
+
↓ Tour aéreo do empreendimento / lifestyle do bairro
|
|
362
|
+
↓ Rastrear: video_50 + video_75 → score alto no LTV
|
|
363
|
+
↓ Remarketing: quem assistiu 50%+ vira audiência no Google Ads
|
|
364
|
+
|
|
365
|
+
FASE 2: CONSIDERAÇÃO (YouTube Non-skip 15s + Display)
|
|
366
|
+
↓ Planta do apartamento / diferenciais / construtora
|
|
367
|
+
↓ Rastrear: clique no CTA → pageview da página de lançamento
|
|
368
|
+
↓ Conectar: gclid → D1 → Meta CAPI (cross-platform attribution)
|
|
369
|
+
|
|
370
|
+
FASE 3: DECISÃO (Search + YouTube Discovery)
|
|
371
|
+
↓ "Apartamento [bairro] lançamento" — intenção ativa
|
|
372
|
+
↓ Rastrear: Lead com gclid → Enhanced Conversions
|
|
373
|
+
↓ LTV Prediction: leads com gclid YouTube têm multiplicador 2.2x
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### UTM padrão para campanhas YouTube Imóveis
|
|
377
|
+
|
|
378
|
+
```
|
|
379
|
+
utm_source=youtube
|
|
380
|
+
utm_medium=video
|
|
381
|
+
utm_campaign=lancamento-{nome-empreendimento}-{cidade}
|
|
382
|
+
utm_content=tour-aereo-30s | planta-apartamento-15s | depoimento-morador
|
|
383
|
+
utm_term={tipo-imovel}-{metragem}-{bairro}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### Audiências recomendadas (Google Ads)
|
|
387
|
+
|
|
388
|
+
```javascript
|
|
389
|
+
// Audiências de alta intenção para imóveis — configurar no Google Ads
|
|
390
|
+
const YOUTUBE_AUDIENCES_IMOVEIS = {
|
|
391
|
+
// In-Market (Google detecta comportamento de compra)
|
|
392
|
+
inMarket: [
|
|
393
|
+
'Real Estate > Residential Properties > For Sale',
|
|
394
|
+
'Real Estate > For Rent > Apartments & Condos',
|
|
395
|
+
'Financial Services > Mortgages',
|
|
396
|
+
],
|
|
397
|
+
|
|
398
|
+
// Custom Intent (palavras que o usuário pesquisou)
|
|
399
|
+
customIntent: [
|
|
400
|
+
'apartamento na planta comprar',
|
|
401
|
+
'lançamento imóvel [cidade]',
|
|
402
|
+
'construtora [nome] apartamentos',
|
|
403
|
+
'financiamento imóvel caixa',
|
|
404
|
+
],
|
|
405
|
+
|
|
406
|
+
// Remarketing CDP Edge (audiência first-party via D1)
|
|
407
|
+
firstParty: {
|
|
408
|
+
source: 'D1 user_profiles WHERE cohort_label IN ("high_intent", "buyer_lookalike")',
|
|
409
|
+
upload: 'Google Ads Customer Match (email + phone)',
|
|
410
|
+
refresh: 'semanal via Intelligence Agent',
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
---
|
|
416
|
+
|
|
417
|
+
## 🔗 INTEGRAÇÃO COM CDPEDGE
|
|
418
|
+
|
|
419
|
+
### Customer Match — Exportar leads do D1 para Google Ads
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
// Endpoint no Worker: GET /export/customer-match
|
|
423
|
+
// Gera CSV criptografado para upload no Google Ads
|
|
424
|
+
|
|
425
|
+
async function exportCustomerMatchList(env) {
|
|
426
|
+
const highIntentLeads = await env.DB.prepare(`
|
|
427
|
+
SELECT email, phone, first_name, last_name
|
|
428
|
+
FROM user_profiles
|
|
429
|
+
WHERE cohort_label IN ('high_intent', 'buyer_lookalike')
|
|
430
|
+
AND updated_at > datetime('now', '-30 days')
|
|
431
|
+
AND email IS NOT NULL
|
|
432
|
+
`).all();
|
|
433
|
+
|
|
434
|
+
// Google Ads aceita SHA-256 de email e phone
|
|
435
|
+
const rows = await Promise.all(
|
|
436
|
+
highIntentLeads.results.map(async (lead) => ({
|
|
437
|
+
hashed_email: await sha256(lead.email),
|
|
438
|
+
hashed_phone: lead.phone ? await sha256(lead.phone) : '',
|
|
439
|
+
first_name: lead.first_name || '',
|
|
440
|
+
last_name: lead.last_name || '',
|
|
441
|
+
}))
|
|
442
|
+
);
|
|
443
|
+
|
|
444
|
+
return rows; // Upload manual no Google Ads > Ferramentas > Audiências > Customer Match
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### Intelligence Agent — Monitorar performance de vídeo
|
|
449
|
+
|
|
450
|
+
O Intelligence Agent (cron semanal) deve incluir check de YouTube:
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
// Adicionar ao checkApiVersionsIntelligence():
|
|
454
|
+
// Verificar se wbraid/gbraid estão chegando nos leads
|
|
455
|
+
// (indica que campanhas YouTube iOS estão funcionando)
|
|
456
|
+
const youtubeMobileLeads = await env.DB.prepare(`
|
|
457
|
+
SELECT COUNT(*) as count
|
|
458
|
+
FROM user_profiles
|
|
459
|
+
WHERE (wbraid IS NOT NULL OR gbraid IS NOT NULL)
|
|
460
|
+
AND updated_at > datetime('now', '-7 days')
|
|
461
|
+
`).first();
|
|
462
|
+
|
|
463
|
+
if (youtubeMobileLeads.count === 0) {
|
|
464
|
+
await sendIntelligenceAlert(env, 'warning', 'YouTube Mobile Attribution',
|
|
465
|
+
'⚠️ Nenhum wbraid/gbraid nos últimos 7 dias. Campanhas YouTube iOS podem estar sem rastreamento.');
|
|
466
|
+
}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## 🛠️ REQUISITOS TÉCNICOS
|
|
472
|
+
|
|
473
|
+
- **Consent Mode v2**: OBRIGATÓRIO — sem ele Google desativa modelagem de conversão
|
|
474
|
+
- **ga_client_id**: Persistir `_ga` cookie no D1 — necessário para GA4 MP + Enhanced Conversions
|
|
475
|
+
- **gclid / wbraid / gbraid**: Todos já capturados por `cdpTrack.js` — nunca hashear
|
|
476
|
+
- **url_passthrough**: Habilitado por padrão no `initConsentMode()` — preserva click IDs
|
|
477
|
+
- **IFrame API**: Embeds YouTube devem ter `?enablejsapi=1` para o BehaviorEngine funcionar
|
|
478
|
+
- **Customer Match**: Listas exportadas do D1 devem ter email e phone hasheados em SHA-256
|
|
479
|
+
- **VTC Window**: Configurar janela de view-through de 7 dias para Bumpers no Google Ads
|
|
480
|
+
|
|
481
|
+
---
|
|
482
|
+
|
|
483
|
+
## ⚠️ ERROS COMUNS — YouTube Tracking
|
|
484
|
+
|
|
485
|
+
| Erro | Causa | Solução |
|
|
486
|
+
|---|---|---|
|
|
487
|
+
| Conversões sem atribuição YouTube | `ga_client_id` não persistido | Verificar D1: `SELECT ga_client_id FROM user_profiles` |
|
|
488
|
+
| wbraid/gbraid não chegando | cdpTrack não inicializado antes do click | Garantir DOMContentLoaded antes do clique |
|
|
489
|
+
| video_progress não disparando | IFrame sem `enablejsapi=1` | Adicionar parâmetro na URL do embed |
|
|
490
|
+
| Consent Mode bloqueando hits | Banner de cookies sem integração | Implementar `cdpTrack.updateConsent()` no callback de aceite |
|
|
491
|
+
| Customer Match baixa taxa de match | Email não normalizado | Usar `normalizeEmail()` antes do SHA-256 |
|
|
492
|
+
| LTV subnotificado para YouTube | utm_source não mapeado | Adicionar 'youtube' ao `utm_score_map` no `predictLtv()` |
|
|
493
|
+
|
|
494
|
+
---
|
|
495
|
+
|
|
496
|
+
## INPUTS RECEBIDOS
|
|
497
|
+
|
|
498
|
+
- JSON do Page Analyzer Agent (vídeos embeds detectados, CTAs, tipo de página)
|
|
499
|
+
- JSON do Premium Tracking Intelligence Agent (eventos prioritários, estratégia de VSL)
|
|
500
|
+
- `contracts/api-versions.json` → `google.versions.ga4.current` e `consent_mode.current`
|
|
501
|
+
- `GA4_MEASUREMENT_ID` — já coletado pelo Google Agent
|
|
502
|
+
- Secret `GA4_API_SECRET` — já configurado pelo Google Agent
|
|
503
|
+
- Perfil D1: `ga_client_id` (cookie `_ga`), `gclid`, `wbraid`, `gbraid` — para atribuição YouTube
|
|
504
|
+
- Status de iframes: verificar se embeds têm `?enablejsapi=1` para BehaviorEngine
|
|
505
|
+
|
|
506
|
+
## RESPONSABILIDADE
|
|
507
|
+
|
|
508
|
+
- Gerar eventos de progresso de vídeo (`video_start`, `video_25`, `video_50`, `video_75`, `video_complete`) via GA4
|
|
509
|
+
- Implementar YouTube IFrame API listener para rastreamento de VSL no browser
|
|
510
|
+
- Garantir `gclid`, `wbraid`, `gbraid` chegando ao Worker (nunca hashear estes campos)
|
|
511
|
+
- Persistir `ga_client_id` no D1 para cruzamento com conversões YouTube Ads
|
|
512
|
+
- Ativar Consent Mode v2 com `url_passthrough: true` (obrigatório para modelagem de conversão)
|
|
513
|
+
- Orientar Customer Match: exportar emails/phones do D1 com SHA-256 para Google Ads
|
|
514
|
+
|
|
515
|
+
## SAÍDA
|
|
516
|
+
|
|
517
|
+
```json
|
|
518
|
+
{
|
|
519
|
+
"arquivos_gerados": {
|
|
520
|
+
"browser": "cdpTrack.js (eventos YouTube + IFrame API listener)",
|
|
521
|
+
"server": "modules/dispatch/ga4.ts (já inclui YouTube via GA4)"
|
|
522
|
+
},
|
|
523
|
+
"eventos_implementados": [
|
|
524
|
+
"video_start",
|
|
525
|
+
"video_25", "video_50", "video_75",
|
|
526
|
+
"video_complete",
|
|
527
|
+
"generate_lead",
|
|
528
|
+
"purchase"
|
|
529
|
+
],
|
|
530
|
+
"requisitos_iframe": "?enablejsapi=1 obrigatório nos embeds YouTube",
|
|
531
|
+
"consent_mode_v2": true,
|
|
532
|
+
"url_passthrough": true,
|
|
533
|
+
"click_ids_capturados": ["gclid", "wbraid", "gbraid"],
|
|
534
|
+
"d1_persiste": ["ga_client_id", "gclid", "wbraid", "gbraid"],
|
|
535
|
+
"customer_match": "emails/phones exportados do D1 com SHA-256"
|
|
536
|
+
}
|
|
537
|
+
```
|