cdp-edge 2.2.1 → 2.2.3
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 +2 -2
- package/dist/commands/server.js +4 -4
- package/extracted-skill/tracking-events-generator/agents/page-analyzer.md +6 -2
- package/extracted-skill/tracking-events-generator/models/lancamento-imobiliario.md +344 -0
- package/package.json +3 -2
- package/server-edge-tracker/INSTALAR.md +5 -5
- package/server-edge-tracker/modules/ml/ltv.js +6 -0
- package/server-edge-tracker/modules/utils.js +5 -3
- package/server-edge-tracker/wrangler.toml +10 -9
- package/templates/lancamento-imobiliario.md +344 -0
- package/server-edge-tracker/worker.js +0 -4635
package/README.md
CHANGED
|
@@ -103,8 +103,8 @@ Meu ecossistema opera como um Cérebro de Conversão Privado na borda. Quando um
|
|
|
103
103
|
|
|
104
104
|
### 🔧 Fix: `wrangler.toml` atualizado
|
|
105
105
|
- Todos os placeholders (`SEU_D1_DATABASE_ID`, `SEU_KV_NAMESPACE_ID`) substituídos pelos IDs reais da conta Cloudflare
|
|
106
|
-
- D1: `
|
|
107
|
-
- KV: `
|
|
106
|
+
- D1: `SEU_DATABASE_ID`
|
|
107
|
+
- KV: `SEU_KV_ID`
|
|
108
108
|
|
|
109
109
|
---
|
|
110
110
|
|
package/dist/commands/server.js
CHANGED
|
@@ -13,7 +13,7 @@ export async function runServer(dir) {
|
|
|
13
13
|
const spinner = ora('Gerando infraestrutura...').start();
|
|
14
14
|
|
|
15
15
|
try {
|
|
16
|
-
// Gerar
|
|
16
|
+
// Gerar index.js
|
|
17
17
|
await generateWorker(dir);
|
|
18
18
|
|
|
19
19
|
// Gerar schema.sql
|
|
@@ -25,7 +25,7 @@ export async function runServer(dir) {
|
|
|
25
25
|
spinner.succeed(chalk.green('Infraestrutura gerada!'));
|
|
26
26
|
|
|
27
27
|
console.log('\n' + chalk.yellow('Arquivos gerados:'));
|
|
28
|
-
console.log(` ${chalk.gray('├─')}
|
|
28
|
+
console.log(` ${chalk.gray('├─')} index.js`);
|
|
29
29
|
console.log(` ${chalk.gray('├─')} schema.sql`);
|
|
30
30
|
console.log(` ${chalk.gray('└─')} wrangler.toml`);
|
|
31
31
|
|
|
@@ -44,7 +44,7 @@ export async function runServer(dir) {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
async function generateWorker(dir) {
|
|
47
|
-
const workerPath = join(dir, '
|
|
47
|
+
const workerPath = join(dir, 'index.js');
|
|
48
48
|
await fs.writeFile(workerPath, generateWorkerCode());
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -163,7 +163,7 @@ function generateWranglerCode() {
|
|
|
163
163
|
# Auto-generated by cdp-edge npx
|
|
164
164
|
|
|
165
165
|
name = "cdp-edge-worker"
|
|
166
|
-
main = "
|
|
166
|
+
main = "index.js"
|
|
167
167
|
compatibility_date = "2024-01-01"
|
|
168
168
|
|
|
169
169
|
[[d1_databases]]
|
|
@@ -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`.
|
|
@@ -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"`)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cdp-edge",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.3",
|
|
4
4
|
"description": "CDP Edge - Quantum Tracking - Sistema multi-agente para tracking digital Cloudflare Native (Workers + D1)",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -23,11 +23,12 @@
|
|
|
23
23
|
"build": "node build.js",
|
|
24
24
|
"dev": "node build.js --watch",
|
|
25
25
|
"test": "node test.js",
|
|
26
|
-
"test:unit": "node tests/unit/normalization.test.js && node tests/unit/hashing.test.js && node tests/unit/deduplication.test.js && node tests/unit/payload-validation.test.js && node tests/unit/new-features.test.js",
|
|
26
|
+
"test:unit": "node tests/unit/normalization.test.js && node tests/unit/hashing.test.js && node tests/unit/deduplication.test.js && node tests/unit/payload-validation.test.js && node tests/unit/new-features.test.js && node tests/unit/utils.test.js",
|
|
27
27
|
"test:unit:normalize": "node tests/unit/normalization.test.js",
|
|
28
28
|
"test:unit:hash": "node tests/unit/hashing.test.js",
|
|
29
29
|
"test:unit:dedup": "node tests/unit/deduplication.test.js",
|
|
30
30
|
"test:unit:payload": "node tests/unit/payload-validation.test.js",
|
|
31
|
+
"test:unit:utils": "node tests/unit/utils.test.js",
|
|
31
32
|
"test:all": "npm run test:unit",
|
|
32
33
|
"test:integration": "cd tests/integration && npx vitest run",
|
|
33
34
|
"agents:check": "node scripts/validate-agents.js",
|
|
@@ -298,7 +298,7 @@ wrangler d1 execute cdp-edge-db --remote --command="SELECT event_name, email, ci
|
|
|
298
298
|
```
|
|
299
299
|
ERROR: Can't deploy routes that are assigned to another worker.
|
|
300
300
|
"server-edge-tracker" is already assigned to routes:
|
|
301
|
-
-
|
|
301
|
+
- SEU_DOMINIO/track*
|
|
302
302
|
```
|
|
303
303
|
|
|
304
304
|
### SOLUÇÃO 1 — Via Painel Cloudflare (RECOMENDADO):
|
|
@@ -306,7 +306,7 @@ ERROR: Can't deploy routes that are assigned to another worker.
|
|
|
306
306
|
1. Acesse: https://dash.cloudflare.com/[ID_DA_CONTA]/workers/overview
|
|
307
307
|
2. Clique no worker que está usando as rotas do seu domínio
|
|
308
308
|
3. Vá em Settings → Triggers → Routes
|
|
309
|
-
4. Clique "Delete" nas rotas do domínio `
|
|
309
|
+
4. Clique "Delete" nas rotas do domínio `SEU_DOMINIO`
|
|
310
310
|
5. Repita o `wrangler deploy`
|
|
311
311
|
|
|
312
312
|
### SOLUÇÃO 2 — Via Wrangler CLI:
|
|
@@ -325,11 +325,11 @@ Se não quiser remover rotas existentes, use sufixo:
|
|
|
325
325
|
|
|
326
326
|
```toml
|
|
327
327
|
[[routes]]
|
|
328
|
-
pattern = "
|
|
329
|
-
zone_name = "
|
|
328
|
+
pattern = "SEU_DOMINIO/track-worker-novo*"
|
|
329
|
+
zone_name = "SEU_DOMINIO"
|
|
330
330
|
```
|
|
331
331
|
|
|
332
|
-
**URL do tracking:** `https://
|
|
332
|
+
**URL do tracking:** `https://SEU_DOMINIO/track-worker-novo`
|
|
333
333
|
|
|
334
334
|
---
|
|
335
335
|
|
|
@@ -100,6 +100,12 @@ export async function predictLtv(env, payload, request, customSystemPrompt = nul
|
|
|
100
100
|
if (payload.phone) score += 4;
|
|
101
101
|
if (payload.firstName) score += 2;
|
|
102
102
|
|
|
103
|
+
// 5b. Tipo de evento imobiliário (0–15) — sinais de intenção de compra física
|
|
104
|
+
const evType = (payload.eventType || '').toLowerCase();
|
|
105
|
+
if (evType === 'customizeproduct') score += 15; // simulação de financiamento → intenção máxima
|
|
106
|
+
else if (evType === 'findlocation') score += 10; // viu mapa/localização → visita física iminente
|
|
107
|
+
else if (evType === 'addtowishlist') score += 8; // favoritou → interesse persistente
|
|
108
|
+
|
|
103
109
|
// 6. Proximidade ao imóvel físico (0–15) — apenas quando distância calculada
|
|
104
110
|
const distKm = parseFloat(payload.distanceKm ?? payload.user_distance_km ?? -1);
|
|
105
111
|
if (distKm >= 0) {
|
|
@@ -86,14 +86,16 @@ export const VALID_EVENT_NAMES = new Set([
|
|
|
86
86
|
'AddToCart','CompleteRegistration','Contact','Schedule',
|
|
87
87
|
'StartTrial','Subscribe','SubmitApplication','Search',
|
|
88
88
|
'video_start','video_25','video_50','video_75','video_complete',
|
|
89
|
+
// Imóveis — intenção de visita física, financiamento e favoritar
|
|
90
|
+
'FindLocation','CustomizeProduct','AddToWishlist',
|
|
89
91
|
]);
|
|
90
92
|
|
|
91
93
|
// ── Taxonomia de funil (funnel_stage → profundidade semântica) ────────────────
|
|
92
94
|
// Fonte de verdade para interpretar funnel_stage em qualquer ponto do sistema.
|
|
93
95
|
export const FUNNEL_TAXONOMY = {
|
|
94
|
-
top: ['scroll_50', 'time_30s', 'page_view', 'gallery_view'],
|
|
95
|
-
mid: ['map_view', 'gallery_click', 'price_hover', 'time_3min'],
|
|
96
|
-
bottom: ['route_click', 'whatsapp_click', 'cta_hover'],
|
|
96
|
+
top: ['scroll_50', 'time_30s', 'page_view', 'gallery_view', 'AddToWishlist'],
|
|
97
|
+
mid: ['map_view', 'gallery_click', 'price_hover', 'time_3min', 'FindLocation'],
|
|
98
|
+
bottom: ['route_click', 'whatsapp_click', 'cta_hover', 'CustomizeProduct'],
|
|
97
99
|
conversion: ['schedule_confirmed', 'lead_form', 'purchase', 'visit_booked'],
|
|
98
100
|
};
|
|
99
101
|
|
|
@@ -4,6 +4,7 @@ name = "server-edge-tracker"
|
|
|
4
4
|
main = "index.js"
|
|
5
5
|
compatibility_date = "2025-01-01"
|
|
6
6
|
compatibility_flags = ["nodejs_compat"]
|
|
7
|
+
workers_dev = true
|
|
7
8
|
|
|
8
9
|
# ── Worker Routes — same-domain tracking (imune a bloqueios) ─────────────────
|
|
9
10
|
# Substituir SEU_DOMINIO pelo domínio do cliente antes do deploy
|
|
@@ -16,19 +17,19 @@ compatibility_flags = ["nodejs_compat"]
|
|
|
16
17
|
# zone_name = "SEU_DOMINIO"
|
|
17
18
|
|
|
18
19
|
[[routes]]
|
|
19
|
-
pattern = "
|
|
20
|
-
zone_name = "
|
|
20
|
+
pattern = "SEU_DOMINIO/track*"
|
|
21
|
+
zone_name = "SEU_DOMINIO"
|
|
21
22
|
|
|
22
23
|
[[routes]]
|
|
23
|
-
pattern = "*.
|
|
24
|
-
zone_name = "
|
|
24
|
+
pattern = "*.SEU_DOMINIO/track*"
|
|
25
|
+
zone_name = "SEU_DOMINIO"
|
|
25
26
|
|
|
26
27
|
# ── Variáveis públicas (não são segredos) ─────────────────────────────────────
|
|
27
28
|
[vars]
|
|
28
|
-
META_PIXEL_ID = "
|
|
29
|
-
GA4_MEASUREMENT_ID = "
|
|
30
|
-
TIKTOK_PIXEL_ID = "
|
|
31
|
-
SITE_DOMAIN = "
|
|
29
|
+
META_PIXEL_ID = ""
|
|
30
|
+
GA4_MEASUREMENT_ID = ""
|
|
31
|
+
TIKTOK_PIXEL_ID = ""
|
|
32
|
+
SITE_DOMAIN = "SEU_DOMINIO"
|
|
32
33
|
|
|
33
34
|
# ── Banco D1 ──────────────────────────────────────────────────────────────────
|
|
34
35
|
# Após criar o banco com "wrangler d1 create cdp-edge-db",
|
|
@@ -36,7 +37,7 @@ SITE_DOMAIN = "lancamentosabc.com.br"
|
|
|
36
37
|
[[d1_databases]]
|
|
37
38
|
binding = "DB"
|
|
38
39
|
database_name = "cdp-edge-db"
|
|
39
|
-
database_id = "
|
|
40
|
+
database_id = "SEU_DATABASE_ID"
|
|
40
41
|
|
|
41
42
|
# ── Queues — Retry + Dead Letter Queue ───────────────────────────────────────
|
|
42
43
|
# Produtor: worker envia eventos com falha para cdp-edge-retry
|