cdp-edge 1.23.2 → 1.24.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 +82 -21
- package/bin/cdp-edge.js +10 -1
- package/contracts/agent-versions.json +42 -41
- package/contracts/types.ts +81 -0
- package/dist/commands/install.js +6 -1
- package/dist/commands/server.js +4 -4
- package/docs/whatsapp-ctwa.md +3 -2
- package/extracted-skill/tracking-events-generator/agents/database-agent.md +5 -4
- package/extracted-skill/tracking-events-generator/agents/fraud-detection-agent.md +0 -1
- package/extracted-skill/tracking-events-generator/agents/linkedin-agent.md +1 -1
- package/extracted-skill/tracking-events-generator/agents/ltv-predictor-agent.md +4 -4
- package/extracted-skill/tracking-events-generator/agents/ml-clustering-agent.md +81 -70
- package/extracted-skill/tracking-events-generator/agents/page-analyzer.md +6 -2
- package/extracted-skill/tracking-events-generator/cdpTrack.js +7 -0
- package/extracted-skill/tracking-events-generator/models/lancamento-imobiliario.md +344 -0
- package/extracted-skill/tracking-events-generator/route-intent-capture.js +222 -0
- package/package.json +9 -5
- package/server-edge-tracker/INSTALAR.md +5 -5
- package/server-edge-tracker/{index.js → index.ts} +186 -72
- package/server-edge-tracker/modules/{db.js → db.ts} +180 -69
- package/server-edge-tracker/modules/dispatch/{ga4.js → ga4.ts} +12 -10
- package/server-edge-tracker/modules/dispatch/meta.ts +138 -0
- package/server-edge-tracker/modules/dispatch/{platforms.js → platforms.ts} +58 -56
- package/server-edge-tracker/modules/dispatch/{tiktok.js → tiktok.ts} +22 -20
- package/server-edge-tracker/modules/dispatch/{whatsapp.js → whatsapp.ts} +59 -25
- package/server-edge-tracker/modules/{intelligence.js → intelligence.ts} +175 -60
- package/server-edge-tracker/modules/ml/{bidding.js → bidding.ts} +37 -35
- package/server-edge-tracker/modules/ml/{fraud.js → fraud.ts} +49 -56
- package/server-edge-tracker/modules/ml/{logistic.js → logistic.ts} +44 -19
- package/server-edge-tracker/modules/ml/{ltv.js → ltv.ts} +179 -83
- package/server-edge-tracker/modules/ml/{matchquality.js → matchquality.ts} +70 -26
- package/server-edge-tracker/modules/ml/segmentation.ts +407 -0
- package/server-edge-tracker/modules/utils.ts +186 -0
- package/server-edge-tracker/schema-ltv-feedback.sql +11 -0
- package/server-edge-tracker/types.ts +251 -0
- package/server-edge-tracker/wrangler.toml +24 -6
- package/templates/lancamento-imobiliario.md +344 -0
- package/docs/PixelBuilder-Documentacao-Completa (2).docx +0 -0
- package/server-edge-tracker/modules/dispatch/meta.js +0 -119
- package/server-edge-tracker/modules/ml/segmentation.js +0 -316
- package/server-edge-tracker/modules/utils.js +0 -89
- package/server-edge-tracker/worker.js +0 -4577
|
@@ -14,7 +14,7 @@ Sua única responsabilidade é instruir o Cloudflare Architect a imbuir modelos
|
|
|
14
14
|
|
|
15
15
|
## 📦 O PACOTE DE ENTREGA OBRIGATÓRIO
|
|
16
16
|
Sempre que o Orquestrador invocar a Otimização de Baleias (LTV Prediction):
|
|
17
|
-
1. **Snippet de Injeção de ML**: Entregue ao Server Architect o bloco `await env.AI.run('@cf/
|
|
17
|
+
1. **Snippet de Injeção de ML**: Entregue ao Server Architect o bloco `await env.AI.run('@cf/ibm-granite/granite-4.0-h-micro', ...)` ajustado para predição puramente matemática.
|
|
18
18
|
2. **Override de Event Valuation**: Modifique como o evento `Lead` ou `Purchase` é envernizado com lucro preditivo antes do dispatch da CAPI.
|
|
19
19
|
|
|
20
20
|
> 👁️ "Não pague por cliques hoje. Compre os clientes de amanhã. Faça o algoritmo apostar sempre nas suas fichas vencedoras."
|
|
@@ -27,7 +27,7 @@ Sempre que o Orquestrador invocar a Otimização de Baleias (LTV Prediction):
|
|
|
27
27
|
- Dados de UTM: `utm_source`, `utm_medium`, `utm_campaign`
|
|
28
28
|
- `request.cf.asOrganization` e `request.cf.country` (sinais de qualidade do tráfego)
|
|
29
29
|
- Histórico D1 do `_cdp_uid`: páginas visitadas, tempo na página, eventos anteriores
|
|
30
|
-
- Binding `env.AI` (Cloudflare Workers AI — `@cf/
|
|
30
|
+
- Binding `env.AI` (Cloudflare Workers AI — `@cf/ibm-granite/granite-4.0-h-micro`)
|
|
31
31
|
|
|
32
32
|
## RESPONSABILIDADE
|
|
33
33
|
|
|
@@ -35,7 +35,7 @@ Sempre que o Orquestrador invocar a Otimização de Baleias (LTV Prediction):
|
|
|
35
35
|
- Classificar o lead em `predicted_ltv_class: 'High' | 'Medium' | 'Low'`
|
|
36
36
|
- Substituir `value: 0` do evento `Lead` pelo valor preditivo antes do dispatch CAPI/GA4/TikTok
|
|
37
37
|
- Registrar no D1 `identity_graph`: `predicted_ltv`, `predicted_ltv_class`
|
|
38
|
-
- Consumo
|
|
38
|
+
- Consumo: ~20–35 neurônios/request com Granite 4.0 Micro (~350 predições/dia no free tier, ilimitado no paid)
|
|
39
39
|
|
|
40
40
|
## SAÍDA
|
|
41
41
|
|
|
@@ -44,7 +44,7 @@ Sempre que o Orquestrador invocar a Otimização de Baleias (LTV Prediction):
|
|
|
44
44
|
"arquivos_criados": [
|
|
45
45
|
"cloudflare/ltv-predictor.js"
|
|
46
46
|
],
|
|
47
|
-
"modelo_ai": "@cf/
|
|
47
|
+
"modelo_ai": "@cf/ibm-granite/granite-4.0-h-micro",
|
|
48
48
|
"campo_substituido": "value",
|
|
49
49
|
"exemplo": {
|
|
50
50
|
"evento": "Lead",
|
|
@@ -128,74 +128,74 @@ is_business_hours = 1 if 9 <= hour_of_day <= 18 else 0
|
|
|
128
128
|
|
|
129
129
|
---
|
|
130
130
|
|
|
131
|
-
## Fase 2 — K-Means
|
|
131
|
+
## Fase 2 — K-Means Vetorial Real (embeddinggemma-300m + K-means em JS)
|
|
132
132
|
|
|
133
|
-
|
|
133
|
+
> **Arquitetura atual:** O clustering não usa LLM para fazer os cálculos matemáticos.
|
|
134
|
+
> Em vez disso, usa **embeddings semânticos reais** + **K-means implementado em JavaScript**,
|
|
135
|
+
> com o Granite usado **apenas para nomear** os clusters resultantes.
|
|
134
136
|
|
|
135
|
-
|
|
136
|
-
# Enviar para: env.AI.run('@cf/meta/llama-3.1-8b-instruct', ...)
|
|
137
|
+
### 2.1 Pipeline de Clustering
|
|
137
138
|
|
|
138
|
-
|
|
139
|
-
|
|
139
|
+
```
|
|
140
|
+
100 leads (sample) → perfil textual → embeddinggemma-300m → vetores 768d
|
|
141
|
+
↓
|
|
142
|
+
K-means++ (cosine distance, JS puro)
|
|
143
|
+
↓
|
|
144
|
+
silhouette score real calculado em JS
|
|
145
|
+
↓
|
|
146
|
+
Granite 4.0 Micro nomeia cada cluster (1 call de LLM)
|
|
147
|
+
```
|
|
140
148
|
|
|
141
|
-
|
|
142
|
-
Your task: Perform K-means clustering to group customers into {n_clusters} segments.
|
|
149
|
+
### 2.2 Modelos Workers AI utilizados
|
|
143
150
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
-
|
|
147
|
-
|
|
151
|
+
| Modelo | ID | Uso |
|
|
152
|
+
|---|---|---|
|
|
153
|
+
| **Granite 4.0 Micro** | `@cf/ibm-granite/granite-4.0-h-micro` | LTV Prediction + Naming de clusters |
|
|
154
|
+
| **EmbeddingGemma 300M** | `@cf/baai/bge-m3` | Embeddings semânticos para K-means |
|
|
148
155
|
|
|
149
|
-
|
|
150
|
-
1. Normalize all features to 0-1 range (min-max normalization)
|
|
151
|
-
2. Initialize K-means centroids randomly
|
|
152
|
-
3. Assign each lead to nearest centroid (Euclidean distance)
|
|
153
|
-
4. Recalculate centroids as mean of assigned points
|
|
154
|
-
5. Iterate until convergence (max 100 iterations)
|
|
155
|
-
6. Calculate Silhouette Score for each cluster (cohesion vs separation)
|
|
156
|
+
### 2.3 Perfil textual por lead (input para embedding)
|
|
156
157
|
|
|
157
|
-
|
|
158
|
-
{
|
|
159
|
-
|
|
160
|
-
{
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
"top_features": ["ltv", "behavior_score", "engagement_score"]
|
|
173
|
-
}},
|
|
174
|
-
"centroid": {{
|
|
175
|
-
"ltv": 0.75,
|
|
176
|
-
"behavior_score": 0.80,
|
|
177
|
-
"engagement_score": 0.85
|
|
178
|
-
}},
|
|
179
|
-
"sample_leads": [lead_id_1, lead_id_2, lead_id_3]
|
|
180
|
-
}},
|
|
181
|
-
...
|
|
182
|
-
],
|
|
183
|
-
"silhouette_scores": {{
|
|
184
|
-
"overall": 0.62,
|
|
185
|
-
"by_cluster": [0.71, 0.58, 0.65, ...]
|
|
186
|
-
}},
|
|
187
|
-
"convergence": {{
|
|
188
|
-
"iterations": 47,
|
|
189
|
-
"final_inertia": 1523.45
|
|
190
|
-
}}
|
|
191
|
-
}}
|
|
158
|
+
```javascript
|
|
159
|
+
function _buildLeadProfile(l) {
|
|
160
|
+
return [
|
|
161
|
+
`LTV: ${l.predicted_ltv_class || 'desconhecido'}`,
|
|
162
|
+
`engajamento: ${Math.round(l.engagement_score || 0)}`,
|
|
163
|
+
`intenção: ${l.intention_level || 'desconhecida'}`,
|
|
164
|
+
`origem: ${l.utm_source || 'direto'}`,
|
|
165
|
+
`canal: ${l.utm_medium || 'desconhecido'}`,
|
|
166
|
+
`país: ${l.country || 'BR'}`,
|
|
167
|
+
`hora: ${l.hour_of_day || 12}h`,
|
|
168
|
+
(l.is_weekend ? 'fim-de-semana' : 'dia-útil'),
|
|
169
|
+
`recência: ${l.days_since_lead || 0} dias`,
|
|
170
|
+
].filter(Boolean).join(', ');
|
|
171
|
+
}
|
|
172
|
+
```
|
|
192
173
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
174
|
+
### 2.4 Chamada de embeddings em batch
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
// Embeds até 100 perfis em uma única chamada
|
|
178
|
+
const embRes = await env.AI.run('@cf/baai/bge-m3', { text: profiles });
|
|
179
|
+
const vectors = embRes.data; // float32[][] — shape [N, 768]
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### 2.5 K-means vetorial (cosine distance)
|
|
183
|
+
|
|
184
|
+
```javascript
|
|
185
|
+
// Inicialização K-means++ → iterações até convergência → assignments finais
|
|
186
|
+
const { assignments } = _kmeansRun(vectors, nClusters); // implementado em worker.js
|
|
187
|
+
const silhouetteScore = _silhouette(vectors, assignments, nClusters); // score real
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### 2.6 Naming dos clusters via Granite (único uso de LLM)
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
// Granite recebe apenas as estatísticas agregadas por cluster
|
|
194
|
+
// Retorna nome descritivo + recomendação de campanha em português
|
|
195
|
+
const nameRes = await env.AI.run('@cf/ibm-granite/granite-4.0-h-micro', {
|
|
196
|
+
messages: [{ role: 'user', content: namingPrompt }],
|
|
197
|
+
max_tokens: 800
|
|
198
|
+
});
|
|
199
199
|
```
|
|
200
200
|
|
|
201
201
|
### 2.2 Features para K-Means
|
|
@@ -484,20 +484,30 @@ export async function onRequestGet(context: EventContext<Env>) {
|
|
|
484
484
|
// Feature Engineering
|
|
485
485
|
const features = extractFeatures(leads);
|
|
486
486
|
|
|
487
|
-
//
|
|
488
|
-
const
|
|
489
|
-
|
|
490
|
-
|
|
487
|
+
// 1. Embeddings reais via embeddinggemma-300m
|
|
488
|
+
const profiles = sample.map(_buildLeadProfile);
|
|
489
|
+
const embRes = await context.env.AI.run('@cf/baai/bge-m3', { text: profiles });
|
|
490
|
+
const vectors = embRes.data; // vetores 768d
|
|
491
|
+
|
|
492
|
+
// 2. K-means vetorial real (JS puro, cosine distance)
|
|
493
|
+
const { assignments } = _kmeansRun(vectors, nClusters);
|
|
494
|
+
const silhouetteScore = _silhouette(vectors, assignments, nClusters);
|
|
495
|
+
|
|
496
|
+
// 3. Granite apenas para nomear clusters
|
|
497
|
+
const nameRes = await context.env.AI.run('@cf/ibm-granite/granite-4.0-h-micro',
|
|
498
|
+
{ messages: [{ role: 'user', content: getNamingPrompt(clusterStats) }], max_tokens: 800 }
|
|
491
499
|
);
|
|
492
|
-
|
|
493
|
-
// Persistir no D1
|
|
500
|
+
|
|
501
|
+
// 4. Persistir no D1
|
|
494
502
|
await saveClusters(context.env.DB, clusters, algorithm);
|
|
495
|
-
|
|
503
|
+
|
|
496
504
|
return Response.json({
|
|
497
505
|
success: true,
|
|
498
506
|
algorithm,
|
|
507
|
+
engine: 'embeddinggemma-300m + kmeans vetorial',
|
|
499
508
|
n_clusters: nClusters,
|
|
500
|
-
|
|
509
|
+
silhouette_score: silhouetteScore,
|
|
510
|
+
clusters,
|
|
501
511
|
generated_at: new Date().toISOString()
|
|
502
512
|
});
|
|
503
513
|
}
|
|
@@ -658,7 +668,7 @@ interface SegmentationAPI {
|
|
|
658
668
|
|
|
659
669
|
```
|
|
660
670
|
[ ] Feature Engineering Pipeline implementada
|
|
661
|
-
[ ] K-means Clustering
|
|
671
|
+
[ ] K-means Clustering vetorial (embeddinggemma-300m + JS)
|
|
662
672
|
[ ] DBSCAN Clustering para anomalias
|
|
663
673
|
[ ] Hierarchical Clustering (drill-down)
|
|
664
674
|
[ ] Auto-Interpretação de segmentos
|
|
@@ -679,7 +689,8 @@ interface SegmentationAPI {
|
|
|
679
689
|
| `Clusters vazios` | Menos de `min_data_points` no D1 | Aumentar `max_data_age_months` ou aguardar mais dados |
|
|
680
690
|
| `Silhouette Score < 0.3` | Clusters não são separáveis | Aumentar `n_clusters` ou usar features melhores |
|
|
681
691
|
| `Outliers excessivos` | Epsilon/MinPts muito agressivos no DBSCAN | Ajustar parâmetros de detecção de anomalias |
|
|
682
|
-
| `
|
|
692
|
+
| `embeddinggemma timeout` | Batch maior que 100 perfis | Limitar sample a 100 leads (padrão atual) |
|
|
693
|
+
| `vectors insuficientes` | embeddinggemma retornou menos vetores que nClusters | Reduzir nClusters ou verificar resposta da API |
|
|
683
694
|
|
|
684
695
|
---
|
|
685
696
|
|
|
@@ -26,6 +26,9 @@ Toda a sua análise deve ser baseada na infraestrutura nativa da Cloudflare.
|
|
|
26
26
|
| Página de obrigado | `Purchase_Success` | 🔴 crítico |
|
|
27
27
|
| **Preço Formatado (R$, $, €)** | `value_extraction` (Atrelado ao CTA) | 🔴 crítico |
|
|
28
28
|
| **Campo de Formulário Oculto (CSS hide/opacity 0)** | `honeypot_field` | 🔴 crítico |
|
|
29
|
+
| **[IMÓVEIS] Mapa / botão "Ver localização" / iframe Google Maps** | `FindLocation` | 🔴 crítico imobiliário |
|
|
30
|
+
| **[IMÓVEIS] Simulador de financiamento / parcelas / FGTS / Caixa** | `CustomizeProduct` | 🔴 crítico imobiliário |
|
|
31
|
+
| **[IMÓVEIS] Botão "Favoritar" / ícone de coração / "Salvar imóvel"** | `AddToWishlist` | 🟡 essencial imobiliário |
|
|
29
32
|
| **Aparecimento de Botão Atrasado (Timer)** | `pitch_seen` | 🟡 essencial |
|
|
30
33
|
| **Classe de Erro CSS (.error, .invalid)** | `form_error_detected` | 🟡 essencial |
|
|
31
34
|
| **Micro-Evento: Rage Click** | `rage_click` | 🟡 essencial |
|
|
@@ -39,8 +42,9 @@ Toda a sua análise deve ser baseada na infraestrutura nativa da Cloudflare.
|
|
|
39
42
|
Antes de mapear elementos, identifique o **modelo de negócio** da página para ativar protocolos específicos:
|
|
40
43
|
|
|
41
44
|
1. **Lançamento Imobiliário**:
|
|
42
|
-
* Sinais: Galeria de fotos de imóveis, botões WhatsApp, formulário curto, mapas
|
|
43
|
-
* Protocolo: Ativar `geolocation`
|
|
45
|
+
* Sinais: Galeria de fotos de imóveis, botões WhatsApp, formulário curto, mapas, simulador de financiamento, botão favoritar, calendário de agendamento, tour 360°.
|
|
46
|
+
* Protocolo: Ativar `geolocation`, `lead_lock_whatsapp`, `real_estate_events`.
|
|
47
|
+
* Eventos obrigatórios extras: `FindLocation` (mapa/localização), `CustomizeProduct` (simulação financiamento), `AddToWishlist` (favoritar), `Schedule` (agendamento de visita), `Contact` (WhatsApp/telefone), `video_25/50/75/complete` (tour virtual/VSL).
|
|
44
48
|
2. **Página de Vendas (Infoproduto)**:
|
|
45
49
|
* Sinais: Botões Hotmart/Kiwify/Ticto, Vídeo (VSL), Depoimentos, Preço.
|
|
46
50
|
* Protocolo: Ativar `checkout_passthrough` e `vsl_retention`.
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
initAntiBlocking,
|
|
26
26
|
ANTI_BLOCKING_CONFIG
|
|
27
27
|
} from './anti-blocking.js';
|
|
28
|
+
import { initRouteIntentCapture } from './route-intent-capture.js';
|
|
28
29
|
|
|
29
30
|
// ── Guards — segurança em SSR e SDK não carregado ──
|
|
30
31
|
const isBrowser = typeof window !== 'undefined';
|
|
@@ -631,6 +632,12 @@ export async function init() {
|
|
|
631
632
|
passCheckoutParams({ platforms: CONFIG.platforms });
|
|
632
633
|
}
|
|
633
634
|
|
|
635
|
+
// 7. Route Intent Capture — widget pós-clique de rota para imóveis
|
|
636
|
+
// Ativa quando CONFIG.routeIntent.whatsappNumber estiver configurado.
|
|
637
|
+
if (CONFIG.routeIntent?.whatsappNumber) {
|
|
638
|
+
initRouteIntentCapture(CONFIG.routeIntent);
|
|
639
|
+
}
|
|
640
|
+
|
|
634
641
|
if (CONFIG.debug) console.log('✅ cdpTrack SDK inicializado (Quantum Tier)');
|
|
635
642
|
}
|
|
636
643
|
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
# Modelo: Lançamento Imobiliário (Cloudflare Native)
|
|
2
|
+
|
|
3
|
+
Template para páginas de lançamento imobiliário com formulário de interesse, galeria, mapa/localização, simulador de financiamento, vídeo de tour, calendário de agendamento e botão WhatsApp.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🏗️ ARQUITETURA TÉCNICA (Quantum Tier)
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Browser (cdpTrack.js)
|
|
11
|
+
├─ PageView → ao carregar
|
|
12
|
+
├─ ViewContent → ao entrar na galeria
|
|
13
|
+
├─ FindLocation → ao interagir com mapa/localização
|
|
14
|
+
├─ video_25/50/75/complete → ao assistir tour virtual
|
|
15
|
+
├─ CustomizeProduct → ao usar simulador de financiamento
|
|
16
|
+
├─ AddToWishlist → ao favoritar imóvel
|
|
17
|
+
├─ Contact → ao clicar em WhatsApp/telefone
|
|
18
|
+
├─ Schedule → ao confirmar agendamento de visita
|
|
19
|
+
└─ Lead → ao enviar formulário (PII completo)
|
|
20
|
+
│
|
|
21
|
+
▼
|
|
22
|
+
Cloudflare Worker (same-domain /track)
|
|
23
|
+
├─ Fraud Gate
|
|
24
|
+
├─ LTV Prediction (Granite 4.0 Micro) + score por eventType
|
|
25
|
+
├─ D1: upsertProfile, identity graph, distanceKm
|
|
26
|
+
└─ CAPI dispatch: Meta v22.0 + GA4 + TikTok v1.3
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 📘 MAPA DE EVENTOS
|
|
32
|
+
|
|
33
|
+
| Evento | Gatilho | Sinal para as plataformas |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| `PageView` | Carregamento | Topo do funil |
|
|
36
|
+
| `ViewContent` | Entra na galeria de fotos | Interesse no produto |
|
|
37
|
+
| `FindLocation` | Clica em mapa / "Como chegar" / abre localização | Intenção de visita física — +10 LTV |
|
|
38
|
+
| `video_25` / `video_50` / `video_75` / `video_complete` | Tour virtual / VSL em % assistido | Engajamento profundo |
|
|
39
|
+
| `CustomizeProduct` | Usa simulador de financiamento/parcelas/FGTS | Intenção de compra máxima — +15 LTV |
|
|
40
|
+
| `AddToWishlist` | Clica em "Favoritar" / coração | Interesse persistente — +8 LTV |
|
|
41
|
+
| `Contact` | Clica em WhatsApp ou telefone | Alta intenção de contato |
|
|
42
|
+
| `Schedule` | Confirma agendamento de visita | Conversão de visita |
|
|
43
|
+
| `Lead` | Envia formulário (nome/email/telefone) | Conversão principal com PII |
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 🛠️ PASSO 1: CONFIGURAÇÃO DO SDK
|
|
48
|
+
|
|
49
|
+
### 1.1 Header
|
|
50
|
+
```html
|
|
51
|
+
<script src="/js/cdpTrack.js" async></script>
|
|
52
|
+
<script>
|
|
53
|
+
window.cdpConfig = {
|
|
54
|
+
metaId: 'SEU_PIXEL_ID',
|
|
55
|
+
ttId: 'SEU_TIKTOK_ID',
|
|
56
|
+
trackEndpoint: '/track'
|
|
57
|
+
};
|
|
58
|
+
</script>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 🛠️ PASSO 2: EVENTOS DE COMPORTAMENTO
|
|
64
|
+
|
|
65
|
+
### 2.1 PageView (automático via SDK)
|
|
66
|
+
O SDK dispara automaticamente. Não precisa de código adicional.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
### 2.2 ViewContent — Galeria de fotos
|
|
71
|
+
```javascript
|
|
72
|
+
// Dispara quando usuário abre/rola a galeria de imagens
|
|
73
|
+
document.querySelector('.galeria-imovel, [data-section="gallery"]')?.addEventListener('click', () => {
|
|
74
|
+
cdpTrack.track('ViewContent', {
|
|
75
|
+
contentName: 'Galeria — [NOME DO EMPREENDIMENTO]',
|
|
76
|
+
contentCategory: 'imovel',
|
|
77
|
+
funnel_stage: 'gallery_view',
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
### 2.3 FindLocation — Mapa / Localização
|
|
85
|
+
```javascript
|
|
86
|
+
// Dispara quando usuário clica no mapa, "Como chegar" ou "Ver localização"
|
|
87
|
+
document.querySelectorAll(
|
|
88
|
+
'a[href*="maps"], a[href*="waze"], [data-section="localizacao"], #mapa, .btn-localizacao, .btn-como-chegar'
|
|
89
|
+
).forEach(el => {
|
|
90
|
+
el.addEventListener('click', () => {
|
|
91
|
+
cdpTrack.track('FindLocation', {
|
|
92
|
+
contentName: 'Localização — [NOME DO EMPREENDIMENTO]',
|
|
93
|
+
contentCategory: 'imovel',
|
|
94
|
+
funnel_stage: 'map_view',
|
|
95
|
+
// Coordenadas do empreendimento (preencher):
|
|
96
|
+
property_lat: -23.5505, // latitude
|
|
97
|
+
property_lng: -46.6333, // longitude
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
### 2.4 Vídeo / Tour Virtual
|
|
106
|
+
```javascript
|
|
107
|
+
// Para vídeo HTML5 nativo:
|
|
108
|
+
const video = document.querySelector('video#tour-virtual, video.tour-360');
|
|
109
|
+
if (video) {
|
|
110
|
+
const fired = new Set();
|
|
111
|
+
video.addEventListener('timeupdate', () => {
|
|
112
|
+
const pct = Math.floor((video.currentTime / video.duration) * 100);
|
|
113
|
+
if (pct >= 25 && !fired.has(25)) {
|
|
114
|
+
fired.add(25);
|
|
115
|
+
cdpTrack.track('video_25', { contentName: 'Tour Virtual — [NOME DO EMPREENDIMENTO]' });
|
|
116
|
+
}
|
|
117
|
+
if (pct >= 50 && !fired.has(50)) {
|
|
118
|
+
fired.add(50);
|
|
119
|
+
cdpTrack.track('video_50', { contentName: 'Tour Virtual — [NOME DO EMPREENDIMENTO]' });
|
|
120
|
+
}
|
|
121
|
+
if (pct >= 75 && !fired.has(75)) {
|
|
122
|
+
fired.add(75);
|
|
123
|
+
cdpTrack.track('video_75', { contentName: 'Tour Virtual — [NOME DO EMPREENDIMENTO]' });
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
video.addEventListener('ended', () => {
|
|
127
|
+
cdpTrack.track('video_complete', { contentName: 'Tour Virtual — [NOME DO EMPREENDIMENTO]' });
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Para YouTube embed (via YouTube API):
|
|
132
|
+
// Adicionar ?enablejsapi=1 na URL do iframe e usar onStateChange
|
|
133
|
+
// Ver: https://developers.google.com/youtube/iframe_api_reference
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
### 2.5 CustomizeProduct — Simulador de Financiamento
|
|
139
|
+
```javascript
|
|
140
|
+
// Dispara quando usuário interage com o simulador de parcelas/FGTS/Caixa
|
|
141
|
+
const simulador = document.querySelector(
|
|
142
|
+
'#simulador, .simulador-financiamento, [data-section="simulacao"], form.simulador'
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
if (simulador) {
|
|
146
|
+
// Dispara ao 1º interact (foco em qualquer campo do simulador)
|
|
147
|
+
let simuladorFired = false;
|
|
148
|
+
simulador.addEventListener('focusin', () => {
|
|
149
|
+
if (simuladorFired) return;
|
|
150
|
+
simuladorFired = true;
|
|
151
|
+
cdpTrack.track('CustomizeProduct', {
|
|
152
|
+
contentName: 'Simulador de Financiamento — [NOME DO EMPREENDIMENTO]',
|
|
153
|
+
contentCategory: 'imovel',
|
|
154
|
+
funnel_stage: 'financing_simulation',
|
|
155
|
+
intentionLevel: 'comprador',
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// Dispara também ao clicar em "Simular" / "Calcular"
|
|
160
|
+
simulador.querySelector('button[type="submit"], .btn-simular, .btn-calcular')?.addEventListener('click', () => {
|
|
161
|
+
const valorImovel = simulador.querySelector('input[name="valor"], #valor-imovel')?.value;
|
|
162
|
+
cdpTrack.track('CustomizeProduct', {
|
|
163
|
+
contentName: 'Simulação Concluída — [NOME DO EMPREENDIMENTO]',
|
|
164
|
+
contentCategory: 'imovel',
|
|
165
|
+
funnel_stage: 'financing_simulation',
|
|
166
|
+
intentionLevel: 'comprador',
|
|
167
|
+
value: valorImovel ? parseFloat(valorImovel.replace(/\D/g, '')) : undefined,
|
|
168
|
+
currency: 'BRL',
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
### 2.6 AddToWishlist — Favoritar Imóvel
|
|
177
|
+
```javascript
|
|
178
|
+
// Dispara quando usuário clica em favoritar / ícone de coração
|
|
179
|
+
document.querySelectorAll('.btn-favoritar, .icon-heart, [data-action="favoritar"], .favorito').forEach(el => {
|
|
180
|
+
el.addEventListener('click', () => {
|
|
181
|
+
cdpTrack.track('AddToWishlist', {
|
|
182
|
+
contentName: '[NOME DO EMPREENDIMENTO]',
|
|
183
|
+
contentCategory: 'imovel',
|
|
184
|
+
funnel_stage: 'wishlist',
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
### 2.7 Contact — WhatsApp / Telefone
|
|
193
|
+
```javascript
|
|
194
|
+
// WhatsApp
|
|
195
|
+
document.querySelectorAll('a[href*="wa.me"], a[href*="whatsapp.com"], .btn-whatsapp').forEach(el => {
|
|
196
|
+
el.addEventListener('click', () => {
|
|
197
|
+
cdpTrack.track('Contact', {
|
|
198
|
+
contentName: 'WhatsApp — [NOME DO EMPREENDIMENTO]',
|
|
199
|
+
contentCategory: 'imovel_whatsapp',
|
|
200
|
+
funnel_stage: 'whatsapp_click',
|
|
201
|
+
intentionLevel: 'comprador',
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Telefone
|
|
207
|
+
document.querySelectorAll('a[href^="tel:"], .btn-ligar, .btn-telefone').forEach(el => {
|
|
208
|
+
el.addEventListener('click', () => {
|
|
209
|
+
cdpTrack.track('Contact', {
|
|
210
|
+
contentName: 'Telefone — [NOME DO EMPREENDIMENTO]',
|
|
211
|
+
contentCategory: 'imovel_telefone',
|
|
212
|
+
funnel_stage: 'phone_click',
|
|
213
|
+
intentionLevel: 'comprador',
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
### 2.8 Schedule — Calendário de Agendamento de Visita
|
|
222
|
+
```javascript
|
|
223
|
+
// Dispara quando usuário CONFIRMA o agendamento (não ao abrir o calendário)
|
|
224
|
+
// Adaptar ao provider: Calendly, Google Calendar, formulário próprio
|
|
225
|
+
|
|
226
|
+
// Exemplo com Calendly:
|
|
227
|
+
window.addEventListener('message', (e) => {
|
|
228
|
+
if (e.data?.event === 'calendly.event_scheduled') {
|
|
229
|
+
cdpTrack.track('Schedule', {
|
|
230
|
+
contentName: 'Visita Agendada — [NOME DO EMPREENDIMENTO]',
|
|
231
|
+
contentCategory: 'imovel',
|
|
232
|
+
funnel_stage: 'schedule_confirmed',
|
|
233
|
+
intentionLevel: 'comprador',
|
|
234
|
+
// Dados do lead do Calendly (se disponíveis via payload):
|
|
235
|
+
email: e.data?.payload?.invitee?.email,
|
|
236
|
+
firstName: e.data?.payload?.invitee?.first_name,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Exemplo com formulário próprio de agendamento:
|
|
242
|
+
document.querySelector('#form-agendamento')?.addEventListener('submit', async (e) => {
|
|
243
|
+
e.preventDefault();
|
|
244
|
+
const data = new FormData(e.target);
|
|
245
|
+
await cdpTrack.track('Schedule', {
|
|
246
|
+
contentName: 'Visita Agendada — [NOME DO EMPREENDIMENTO]',
|
|
247
|
+
contentCategory: 'imovel',
|
|
248
|
+
funnel_stage: 'schedule_confirmed',
|
|
249
|
+
intentionLevel: 'comprador',
|
|
250
|
+
email: data.get('email'),
|
|
251
|
+
phone: data.get('phone'),
|
|
252
|
+
firstName: data.get('nome')?.split(' ')[0],
|
|
253
|
+
});
|
|
254
|
+
e.target.submit();
|
|
255
|
+
});
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
### 2.9 Lead — Formulário Principal de Interesse
|
|
261
|
+
```javascript
|
|
262
|
+
document.querySelector('#form-interesse, #form-lead, form.form-contato')?.addEventListener('submit', async (e) => {
|
|
263
|
+
e.preventDefault();
|
|
264
|
+
|
|
265
|
+
await cdpTrack.track('Lead', {
|
|
266
|
+
// PII — enviados hasheados pelo Worker
|
|
267
|
+
email: e.target.email?.value?.trim(),
|
|
268
|
+
phone: e.target.phone?.value?.trim() || e.target.telefone?.value?.trim(),
|
|
269
|
+
firstName: e.target.nome?.value?.split(' ')[0]?.trim(),
|
|
270
|
+
lastName: e.target.nome?.value?.split(' ').slice(1).join(' ')?.trim(),
|
|
271
|
+
|
|
272
|
+
// Contexto
|
|
273
|
+
contentName: '[NOME DO EMPREENDIMENTO]',
|
|
274
|
+
contentCategory: 'imovel',
|
|
275
|
+
intentionLevel: 'comprador',
|
|
276
|
+
funnel_stage: 'lead_form',
|
|
277
|
+
|
|
278
|
+
// UTMs capturados pelo SDK automaticamente
|
|
279
|
+
// Coordenadas do imóvel para distância geoespacial no Worker:
|
|
280
|
+
property_lat: -23.5505,
|
|
281
|
+
property_lng: -46.6333,
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
// Redirecionar para obrigado
|
|
285
|
+
window.location.href = '/obrigado';
|
|
286
|
+
});
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## 📊 LTV por Evento — O que o Worker calcula
|
|
292
|
+
|
|
293
|
+
| Evento | Bonus LTV Score | Multiplicador Valor |
|
|
294
|
+
|---|---|---|
|
|
295
|
+
| `Lead` (utm_source=facebook, intention=comprador) | ~65–80 pts | 3.5× → **High** |
|
|
296
|
+
| `CustomizeProduct` | +15 pts automático | Score sobe para High |
|
|
297
|
+
| `FindLocation` | +10 pts automático | Puxa Medium → High |
|
|
298
|
+
| `AddToWishlist` | +8 pts automático | Sinal de retargeting |
|
|
299
|
+
| `Schedule` (visita confirmada) | intention=comprador → +20 pts | Máximo High |
|
|
300
|
+
| `Contact` (WhatsApp) | Sem LTV (evento de sinal) | — |
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## 🔄 FLUXO COMPLETO DO LEAD IMOBILIÁRIO
|
|
305
|
+
|
|
306
|
+
```
|
|
307
|
+
Usuário chega na landing
|
|
308
|
+
│
|
|
309
|
+
├─ PageView → sinal de alcance
|
|
310
|
+
├─ ViewContent (galeria) → interesse qualificado
|
|
311
|
+
├─ video_50 (tour) → engajamento profundo
|
|
312
|
+
├─ FindLocation (mapa) → intenção de visita física (+10 LTV)
|
|
313
|
+
├─ CustomizeProduct (simulador) → intenção máxima (+15 LTV)
|
|
314
|
+
├─ Contact (WhatsApp) → ação de contato
|
|
315
|
+
├─ Schedule (agendamento) → visita confirmada
|
|
316
|
+
└─ Lead (formulário) → conversão principal
|
|
317
|
+
│
|
|
318
|
+
▼
|
|
319
|
+
Worker: LTV score ~75-90 → High → valor 3.5× injetado
|
|
320
|
+
│
|
|
321
|
+
▼
|
|
322
|
+
Meta CAPI + GA4 + TikTok recebem Lead com value=R$689
|
|
323
|
+
│
|
|
324
|
+
▼
|
|
325
|
+
Algoritmo de Meta aprende a buscar mais leads de alto valor
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## 📋 CHECKLIST DE IMPLEMENTAÇÃO
|
|
331
|
+
|
|
332
|
+
- [ ] SDK `cdpTrack.js` carregando no `<head>`
|
|
333
|
+
- [ ] `PageView` disparando (automático)
|
|
334
|
+
- [ ] `ViewContent` na galeria
|
|
335
|
+
- [ ] `FindLocation` no mapa e botão "Como chegar"
|
|
336
|
+
- [ ] Vídeo/tour instrumentado (`video_25`, `video_75`, `video_complete`)
|
|
337
|
+
- [ ] `CustomizeProduct` no simulador de financiamento
|
|
338
|
+
- [ ] `AddToWishlist` no botão de favoritar
|
|
339
|
+
- [ ] `Contact` nos botões de WhatsApp e telefone
|
|
340
|
+
- [ ] `Schedule` no calendário (Calendly ou formulário próprio)
|
|
341
|
+
- [ ] `Lead` no formulário principal com PII e `property_lat/lng`
|
|
342
|
+
- [ ] Verificar `/health` retornando `d1: ok, kv: ok, ai: ok`
|
|
343
|
+
- [ ] Testar evento `Lead` no Meta Events Manager → Test Events
|
|
344
|
+
- [ ] Confirmar LTV na resposta JSON do `/track` (`class: "High"`)
|