cdp-edge 1.5.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.
@@ -0,0 +1,55 @@
1
+ # Modelo: Página de Obrigado (Cloudflare Native)
2
+
3
+ Este modelo é destinado à página final do funil de vendas. O foco principal é a **deduplicação inteligente** e a garantia de que o evento de conversão foi registrado corretamente no banco de dados e nas APIs.
4
+
5
+ ---
6
+
7
+ ## 🏗️ ARQUITETURA TÉCNICA (Quantum Tier)
8
+
9
+ O rastreamento na página de obrigado segue dois caminhos:
10
+ 1. **Obrigado de Lead**: Disparo direto via `cdpTrack.track()` se o lead ainda não foi marcado no servidor.
11
+ 2. **Obrigado de Venda**: O evento de compra (`Purchase`) deve ser evitado se houver integração via Webhook, disparando apenas um `ViewContent` para análise de navegação.
12
+
13
+ ---
14
+
15
+ ## 🛠️ PASSO 1: CONFIGURAÇÃO DO SITE
16
+
17
+ ### 1.1 Obrigado de Lead (Formulário)
18
+ ```javascript
19
+ <script>
20
+ // Dispara apenas se o lead ainda não foi marcado no Worker
21
+ cdpTrack.track('Lead_Success', {
22
+ source: 'thank_you_page'
23
+ });
24
+ </script>
25
+ ```
26
+
27
+ ### 1.2 Obrigado de Venda (Purchase)
28
+ > [!IMPORTANT]
29
+ > Caso utilize **Webhooks (Ticto/Hotmart/Kiwify)**, a página de obrigado **NÃO** deve disparar o evento `Purchase`. O Worker fará o envio via servidor para evitar duplicidade e garantir 100% de atribuição.
30
+
31
+ ```javascript
32
+ <script>
33
+ // Dispara evento de visualização para análise de funil
34
+ cdpTrack.track('ViewContent', {
35
+ content_name: 'Success_Page',
36
+ content_category: 'Sales'
37
+ });
38
+ </script>
39
+ ```
40
+
41
+ ---
42
+
43
+ ## 🖥️ PASSO 2: SERVIDOR (CLOUDFLARE WORKER)
44
+
45
+ O Worker realiza a verificação de duplicidade:
46
+ - **D1 Cross-Check**: Verifica se o `transaction_id` já existe no banco antes de enviar para Meta CAPI (v22.0) e TikTok (v1.3).
47
+ - **Match Quality**: Recupera os identificadores originais do banco de dados para enriquecer o evento.
48
+
49
+ ---
50
+
51
+ ## ✅ VALIDAÇÃO TÉCNICA
52
+
53
+ - **Deduplicação**: Verifique se não há disparos duplos de `Purchase` (um pelo site e outro pelo webhook).
54
+ - **Persistência**: O evento de sucesso deve estar registrado no log de eventos do D1.
55
+ - **Match Quality**: Conferir se os dados de atribuição (`fbp`, `fbc`) estão sendo enviados corretamente nas chamadas de servidor.
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Pinterest Conversions API Server Template — CDP Edge Quantum Tier
3
+ *
4
+ * Este template contém a função de envio para a Conversions API do Pinterest
5
+ * Uso: Incluir no worker.js gerado pelo Server Tracking Agent
6
+ */
7
+
8
+ /**
9
+ * Função principal de envio para Pinterest Conversions API
10
+ * @param {Object} env - Variáveis de ambiente do Cloudflare Worker
11
+ * @param {Object} eventData - Dados do evento a ser enviado
12
+ * @returns {Promise<Object>} - Resposta da API
13
+ */
14
+ export async function sendPinterestApi(env, eventData) {
15
+ const {
16
+ email, phone, userId, clientIp, userAgent, pageUrl,
17
+ eventId, value, currency, orderId, productName, productId
18
+ } = eventData;
19
+
20
+ // Verificar se as credenciais estão configuradas
21
+ if (!env.PINTEREST_ACCESS_TOKEN || !env.PINTEREST_AD_ACCOUNT_ID) {
22
+ console.warn('Pinterest Conversions API: Credenciais não configuradas');
23
+ return { success: false, error: 'MISSING_CREDENTIALS' };
24
+ }
25
+
26
+ // Função de hash SHA-256
27
+ async function sha256(str) {
28
+ if (!str) return undefined;
29
+ const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(str.toLowerCase().trim()));
30
+ return Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2, '0')).join('');
31
+ }
32
+
33
+ // Normalizar evento — Pinterest usa nomes específicos
34
+ const pinterestEventMap = {
35
+ 'PageView': 'pagevisit',
36
+ 'Lead': 'lead',
37
+ 'Purchase': 'checkout',
38
+ 'AddToCart': 'addtocart',
39
+ 'InitiateCheckout': 'checkout',
40
+ 'ViewContent': 'pagevisit',
41
+ 'CompleteRegistration': 'signup',
42
+ 'Search': 'search',
43
+ };
44
+ const pinterestEvent = pinterestEventMap[eventName] || 'custom';
45
+
46
+ // User data com hashing
47
+ const userData = {};
48
+ if (email) userData.em = [await sha256(email)];
49
+ if (phone) userData.ph = [await sha256(phone.replace(/\D/g, ''))];
50
+ if (userId) userData.external_id = [await sha256(userId)];
51
+ if (clientIp) userData.client_ip_address = clientIp; // sem hash
52
+ if (userAgent) userData.client_user_agent = userAgent; // sem hash
53
+
54
+ // Payload da Conversions API
55
+ const payload = {
56
+ data: [{
57
+ event_name: pinterestEvent,
58
+ action_source: 'web',
59
+ event_time: Math.floor(Date.now() / 1000),
60
+ event_id: eventId, // deduplicação com browser tag
61
+ event_source_url: pageUrl || '',
62
+ user_data: userData,
63
+ custom_data: {
64
+ currency: currency || 'BRL',
65
+ value: value ? String(value) : '0',
66
+ order_id: orderId || undefined,
67
+ content_ids: productId ? [productId] : undefined,
68
+ content_name: productName || undefined,
69
+ content_type: 'product',
70
+ },
71
+ // Para lead: adicionar lead_type
72
+ ...(eventName === 'Lead' ? { custom_data: { ...{}, lead_type: 'Newsletter' } } : {}),
73
+ }],
74
+ };
75
+
76
+ try {
77
+ const resp = await fetch(
78
+ `https://api.pinterest.com/v5/ad_accounts/${env.PINTEREST_AD_ACCOUNT_ID}/events`,
79
+ {
80
+ method: 'POST',
81
+ headers: {
82
+ 'Content-Type': 'application/json',
83
+ 'Authorization': `Bearer ${env.PINTEREST_ACCESS_TOKEN}`,
84
+ },
85
+ body: JSON.stringify(payload),
86
+ }
87
+ );
88
+
89
+ const result = await resp.json();
90
+
91
+ // Resposta de sucesso: { num_events_received: 1, num_events_processed: 1 }
92
+ if (result.num_events_received === 1 && result.num_events_processed === 1) {
93
+ return { success: true, result };
94
+ } else {
95
+ return { success: false, error: 'API_ERROR', result };
96
+ }
97
+
98
+ } catch (error) {
99
+ console.error('Pinterest Conversions API Error:', error);
100
+ return { success: false, error: error.message };
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Função de Enhanced Match — re-inicializa o pixel com dados hasheados
106
+ * @param {string} email - Email do usuário (opcional)
107
+ * @param {string} phone - Telefone do usuário (opcional)
108
+ */
109
+ export async function reinitPinterestWithEnhancedMatch(email, phone) {
110
+ if (!email && !phone) return;
111
+
112
+ const hashedEmail = email ? await sha256Email(email) : '';
113
+ const hashedPhone = phone ? await sha256Phone(phone.replace(/\D/g, '')) : '';
114
+
115
+ // Re-load com dados hasheados para Enhanced Match
116
+ if (typeof pintrk !== 'undefined') {
117
+ pintrk('load', '{PINTEREST_TAG_ID}', {
118
+ em: hashedEmail,
119
+ ph: hashedPhone
120
+ });
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Funções de hash para Enhanced Match no browser
126
+ */
127
+ export async function sha256Email(str) {
128
+ if (!str) return '';
129
+ const normalized = str.toLowerCase().trim();
130
+ const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(normalized));
131
+ return Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2, '0')).join('');
132
+ }
133
+
134
+ export async function sha256Phone(str) {
135
+ if (!str) return '';
136
+ const normalized = str.replace(/\D/g, '').toLowerCase().trim();
137
+ const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(normalized));
138
+ return Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2, '0')).join('');
139
+ }
140
+
141
+ export default {
142
+ sendPinterestApi,
143
+ reinitPinterestWithEnhancedMatch
144
+ };
@@ -0,0 +1,48 @@
1
+ {
2
+ "platform": "pinterest",
3
+ "version": "v5",
4
+ "event_mappings": {
5
+ "pixel_to_native": {
6
+ "PageView": "pagevisit",
7
+ "Lead": "lead",
8
+ "Purchase": "checkout",
9
+ "AddToCart": "addtocart",
10
+ "InitiateCheckout": "checkout",
11
+ "ViewContent": "pagevisit",
12
+ "CompleteRegistration": "signup",
13
+ "Search": "search"
14
+ },
15
+ "native_names": {
16
+ "pagevisit": "Visualização de página",
17
+ "lead": "Formulário de lead",
18
+ "checkout": "Compra confirmada",
19
+ "addtocart": "Adicionar ao carrinho",
20
+ "signup": "Cadastro",
21
+ "search": "Busca"
22
+ }
23
+ },
24
+ "required_parameters": {
25
+ "pagevisit": ["line_items"],
26
+ "lead": ["lead_type"],
27
+ "addtocart": ["value", "currency", "line_items"],
28
+ "checkout": ["value", "currency", "order_id", "line_items"],
29
+ "signup": ["lead_type"],
30
+ "search": ["search_query"],
31
+ "watchvideo": []
32
+ },
33
+ "optional_parameters": {
34
+ "pagevisit": ["custom_data"],
35
+ "lead": ["custom_data"],
36
+ "addtocart": ["custom_data"],
37
+ "checkout": ["custom_data"],
38
+ "signup": ["custom_data"],
39
+ "search": ["custom_data"]
40
+ },
41
+ "enhanced_match_fields": {
42
+ "email": "em",
43
+ "phone": "ph",
44
+ "external_id": "external_id",
45
+ "client_ip_address": "client_ip_address",
46
+ "client_user_agent": "client_user_agent"
47
+ }
48
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Pinterest Pixel Browser Template — CDP Edge Quantum Tier
3
+ *
4
+ * Este template contém o código de inicialização do Pinterest Pixel
5
+ * Uso: Incluir no tracking.js gerado pelo Browser Tracking Agent
6
+ */
7
+
8
+ export const PINTEREST_TAG_TEMPLATE = `
9
+ <!-- Pinterest Pixel Base Code -->
10
+ <script>
11
+ !function(e){if(!window.pintrk){window.pintrk=function(){
12
+ window.pintrk.queue.push(Array.prototype.slice.call(arguments))};
13
+ var n=window.pintrk;n.queue=[],n.version="3.0";
14
+ var t=document.createElement("script");
15
+ t.async=!0,t.src=e;
16
+ var r=document.getElementsByTagName("script")[0];
17
+ r.parentNode.insertBefore(t,r)}}("https://s.pinimg.com/ct/core.js");
18
+
19
+ pintrk('load', '{PINTEREST_TAG_ID}', {
20
+ em: '<user_email_if_known>' // Enhanced Match — enviar email quando disponível
21
+ });
22
+ pintrk('page');
23
+ </script>
24
+ <noscript>
25
+ <img height="1" width="1" style="display:none;"
26
+ src="https://ct.pinterest.com/v3/?event=init&tid={PINTEREST_TAG_ID}&pd[em]=<hashed_email>&noscript=1" />
27
+ </noscript>
28
+ `;
@@ -0,0 +1,68 @@
1
+ # Modelo: Quiz Funnel (Cloudflare Native)
2
+
3
+ Este modelo é destinado a funis de quiz, onde o usuário responde a uma série de perguntas antes de ser redirecionado para a oferta final. O rastreamento foca na progressão do usuário e na captura de dados intermediários.
4
+
5
+ ---
6
+
7
+ ## 🏗️ ARQUITETURA TÉCNICA (Quantum Tier)
8
+
9
+ O rastreamento segue a lógica de micro-eventos:
10
+ 1. **Página**: Dispara um evento a cada resposta dada no quiz via `cdpTrack.track()`.
11
+ 2. **Servidor (Worker)**: Recebe e armazena o progresso no banco D1.
12
+ 3. **Database (D1)**: Mantém o histórico de respostas vinculado ao `track_user_id`.
13
+
14
+ ---
15
+
16
+ ## 📘 EVENTOS PRINCIPAIS
17
+
18
+ | Evento | Gatilho | Dados Enviados |
19
+ |---|---|---|
20
+ | **QuizStart** | Início do quiz | `quiz_name`, `source` |
21
+ | **QuizAnswer** | Resposta a uma pergunta | `question`, `answer`, `step` |
22
+ | **QuizComplete** | Finalização do quiz | `result`, `completion_time` |
23
+
24
+ ---
25
+
26
+ ## 🛠️ PASSO 1: CONFIGURAÇÃO DO SITE
27
+
28
+ ### 1.1 Rastreamento de Respostas
29
+ Integre este código na lógica de clique do seu quiz.
30
+
31
+ ```javascript
32
+ // Exemplo de captura de resposta
33
+ function onResponder(pergunta, resposta, etapa) {
34
+ cdpTrack.track('QuizAnswer', {
35
+ question: pergunta,
36
+ answer: resposta,
37
+ step: etapa,
38
+ event_id: cdpTrack.generateId()
39
+ });
40
+ }
41
+ ```
42
+
43
+ ### 1.2 Finalização do Quiz
44
+ Disparar ao chegar no resultado final ou na página de captura pós-quiz.
45
+
46
+ ```javascript
47
+ cdpTrack.track('QuizComplete', {
48
+ result: 'Perfil_A',
49
+ event_id: cdpTrack.generateId()
50
+ });
51
+ ```
52
+
53
+ ---
54
+
55
+ ## ⚡ PASSO 2: SERVIDOR (CLOUDFLARE WORKER)
56
+
57
+ O Worker realiza:
58
+ - **Agregação**: O `user_id` permite que todas as respostas sejam vinculadas a um único perfil no banco D1.
59
+ - **Enriquecimento**: Se o usuário deixar o e-mail no final, todas as respostas anteriores são associadas ao e-mail para a CAPI.
60
+ - **API Dispatch**: Envio de eventos customizados para Meta e TikTok para otimização de público.
61
+
62
+ ---
63
+
64
+ ## ✅ VALIDAÇÃO TÉCNICA
65
+
66
+ - **Persistência**: Verifique no banco D1 se a jornada do usuário está sendo gravada passo a passo.
67
+ - **Deduplicação**: O `event_id` único por resposta evita contagens duplicadas.
68
+ - **Match Quality**: A vinculação tardia do e-mail com as respostas iniciais aumenta a precisão da atribuição.
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Reddit Conversions API Server Template — CDP Edge Quantum Tier
3
+ *
4
+ * Este template contém a função de envio para a Conversions API do Reddit
5
+ * Uso: Incluir no worker.js gerado pelo Server Tracking Agent
6
+ */
7
+
8
+ /**
9
+ * Função principal de envio para Reddit Conversions API
10
+ * @param {Object} env - Variáveis de ambiente do Cloudflare Worker
11
+ * @param {Object} eventData - Dados do evento a ser enviado
12
+ * @returns {Promise<Object>} - Resposta da API
13
+ */
14
+ export async function sendRedditApi(env, eventData) {
15
+ const { email, phone, userId, clientIp, userAgent, pageUrl,
16
+ eventId, value, currency, itemCount, transactionId } = eventData;
17
+
18
+ // Verificar se as credenciais estão configuradas
19
+ if (!env.REDDIT_ACCESS_TOKEN || !env.REDDIT_AD_ACCOUNT_ID) {
20
+ console.warn('Reddit Conversions API: Credenciais não configuradas');
21
+ return { success: false, error: 'MISSING_CREDENTIALS' };
22
+ }
23
+
24
+ // Função de hash SHA-256
25
+ async function sha256(str) {
26
+ if (!str) return undefined;
27
+ const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(str.toLowerCase().trim()));
28
+ return Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2,'0')).join('');
29
+ }
30
+
31
+ // Mapeamento de eventos CDP Edge → Reddit
32
+ const redditEventMap = {
33
+ 'PageView': 'PageVisit',
34
+ 'ViewContent': 'ViewContent',
35
+ 'Lead': 'Lead',
36
+ 'Purchase': 'Purchase',
37
+ 'AddToCart': 'AddToCart',
38
+ 'CompleteRegistration': 'SignUp',
39
+ 'Search': 'Search',
40
+ 'InitiateCheckout': 'Purchase', // com conversionType BEGIN_CHECKOUT
41
+ };
42
+ const redditEvent = redditEventMap[eventName] || 'Custom';
43
+
44
+ // user object com SHA256
45
+ const user = {};
46
+ if (email) user.email = { value: await sha256(email) };
47
+ if (phone) user.phoneNumber = { value: await sha256(phone.replace(/\D/g,'')) };
48
+ if (userId) user.externalId = { value: await sha256(userId) };
49
+ if (clientIp) user.ipAddress = { value: clientIp }; // sem hash
50
+ if (userAgent) user.userAgent = { value: userAgent }; // sem hash
51
+
52
+ const event = {
53
+ event_at: new Date().toISOString(),
54
+ event_type: { tracking_type: redditEvent },
55
+ click_id: '', // Reddit click ID (rdt_cid) — se disponível da URL
56
+ event_metadata: {
57
+ currency: currency || 'BRL',
58
+ value_decimal: String(value || 0), // string com decimal
59
+ item_count: String(itemCount || 1),
60
+ transaction_id: transactionId || eventId,
61
+ conversion_id: eventId, // deduplicação
62
+ },
63
+ user,
64
+ };
65
+
66
+ // Adicionar conversionType para InitiateCheckout
67
+ if (eventName === 'InitiateCheckout') {
68
+ event.event_type.conversion_type = 'BEGIN_CHECKOUT';
69
+ }
70
+
71
+ const payload = { events: [event] };
72
+
73
+ try {
74
+ const resp = await fetch(
75
+ `https://ads-api.reddit.com/api/v2.0/conversions/events/${env.REDDIT_AD_ACCOUNT_ID}`,
76
+ {
77
+ method: 'POST',
78
+ headers: {
79
+ 'Content-Type': 'application/json',
80
+ 'Authorization': `Bearer ${env.REDDIT_ACCESS_TOKEN}`,
81
+ },
82
+ body: JSON.stringify(payload),
83
+ }
84
+ );
85
+
86
+ // Resposta de sucesso: { status: 200, message: "Success" }
87
+ if (resp.ok) {
88
+ const result = await resp.json();
89
+ return { success: true, result };
90
+ } else {
91
+ return { success: false, error: `HTTP ${resp.status}` };
92
+ }
93
+
94
+ } catch (error) {
95
+ console.error('Reddit Conversions API Error:', error);
96
+ return { success: false, error: error.message };
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Função de Advanced Matching — re-inicializa o pixel com dados hasheados
102
+ * @param {Object} userData - Dados do usuário (email, phone, externalId)
103
+ */
104
+ export function reinitRedditWithUserData(userData) {
105
+ const matchData = {};
106
+ if (userData.email) matchData.email = userData.email; // pixel faz hash
107
+ if (userData.phone) matchData.phoneNumber = userData.phone; // pixel faz hash
108
+ if (userData.externalId) matchData.externalId = userData.externalId;
109
+
110
+ rdt('init', '{REDDIT_PIXEL_ID}', matchData);
111
+ }
112
+
113
+ /**
114
+ * Funções de tracking de eventos (browser + server)
115
+ * Uso: Chamadas do tracking.js para eventos Reddit
116
+ */
117
+
118
+ /**
119
+ * Track de Lead
120
+ * @param {Object} data - Dados do formulário
121
+ */
122
+ export async function trackRedditLead(data = {}) {
123
+ const eventId = generateEventId(); // reutilizar a função do tracking.js
124
+
125
+ // Browser: Reddit Pixel
126
+ if (typeof rdt !== 'undefined') {
127
+ if (data.email || data.phone) reinitRedditWithUserData(data);
128
+ rdt('track', 'Lead', { transactionId: eventId });
129
+ }
130
+
131
+ // Servidor: Conversions API
132
+ await sendToServer('Lead', { ...data, eventId, redditEventId: eventId });
133
+ }
134
+
135
+ /**
136
+ * Track de Purchase
137
+ * @param {Object} data - Dados da compra
138
+ */
139
+ export async function trackRedditPurchase(data = {}) {
140
+ const eventId = generateEventId();
141
+
142
+ if (typeof rdt !== 'undefined')
143
+ rdt('track', 'Purchase', {
144
+ value: data.value || 0,
145
+ currency: data.currency || 'BRL',
146
+ itemCount: data.itemCount ||1,
147
+ transactionId: data.transactionId || eventId,
148
+ });
149
+
150
+ await sendToServer('Purchase', { ...data, eventId, redditEventId: eventId });
151
+ }
152
+
153
+ /**
154
+ * Track de InitiateCheckout
155
+ * @param {Object} data - Dados do checkout iniciado
156
+ */
157
+ export async function trackRedditInitiateCheckout(data = {}) {
158
+ const eventId = generateEventId();
159
+
160
+ if (typeof rdt !== 'undefined')
161
+ rdt('track', 'Purchase', {
162
+ conversionType: 'BEGIN_CHECKOUT',
163
+ value: data.value || 0,
164
+ currency: data.currency || 'BRL',
165
+ transactionId: eventId,
166
+ });
167
+
168
+ await sendToServer('InitiateCheckout', { ...data, eventId });
169
+ }
170
+
171
+ /**
172
+ * Gerador de Event ID único
173
+ * Reutiliza a função do tracking.js ou gera novo
174
+ */
175
+ function generateEventId() {
176
+ return crypto.randomUUID ? crypto.randomUUID() :
177
+ Date.now().toString(36) + Math.random().toString(36).slice(2);
178
+ }
179
+
180
+ /**
181
+ * Enviar dados para servidor via fetch
182
+ * @param {string} eventName - Nome do evento
183
+ * @param {Object} data - Dados completos do evento
184
+ */
185
+ async function sendToServer(eventName, data) {
186
+ const serverUrl = '/api/track'; // ou URL configurada
187
+
188
+ await fetch(serverUrl, {
189
+ method: 'POST',
190
+ headers: { 'Content-Type': 'application/json' },
191
+ body: JSON.stringify({
192
+ event_name: eventName,
193
+ platform: 'reddit',
194
+ ...data
195
+ })
196
+ });
197
+ }
198
+
199
+ export default {
200
+ sendRedditApi,
201
+ reinitRedditWithUserData,
202
+ trackRedditLead,
203
+ trackRedditPurchase,
204
+ trackRedditInitiateCheckout
205
+ };
@@ -0,0 +1,56 @@
1
+ {
2
+ "platform": "reddit",
3
+ "version": "v2.0",
4
+ "event_mappings": {
5
+ "pixel_to_native": {
6
+ "PageView": "PageVisit",
7
+ "ViewContent": "ViewContent",
8
+ "Lead": "Lead",
9
+ "Purchase": "Purchase",
10
+ "AddToCart": "AddToCart",
11
+ "AddToWishlist": "AddToWishlist",
12
+ "InitiateCheckout": "Purchase", // com conversionType: BEGIN_CHECKOUT
13
+ "CompleteRegistration": "SignUp",
14
+ "Search": "Search"
15
+ },
16
+ "native_names": {
17
+ "PageVisit": "Visualização de página",
18
+ "ViewContent": "Visualizar produto/conteúdo",
19
+ "Lead": "Formulário de lead",
20
+ "Purchase": "Compra confirmada",
21
+ "AddToCart": "Adicionar ao carrinho",
22
+ "AddToWishlist": "Adicionar à lista de desejos",
23
+ "SignUp": "Cadastro",
24
+ "Search": "Busca"
25
+ }
26
+ },
27
+ "required_parameters": {
28
+ "PageVisit": [],
29
+ "ViewContent": ["value", "currency", "itemCount"],
30
+ "Lead": [],
31
+ "Purchase": ["value", "currency", "itemCount", "transactionId"],
32
+ "AddToCart": ["value", "currency", "itemCount"],
33
+ "AddToWishlist": ["value", "currency", "itemCount"],
34
+ "InitiateCheckout": ["value", "currency"],
35
+ "SignUp": [],
36
+ "Search": []
37
+ },
38
+ "optional_parameters": {
39
+ "PageVisit": [],
40
+ "ViewContent": ["customData"],
41
+ "Lead": ["customData"],
42
+ "Purchase": ["customData"],
43
+ "AddToCart": ["customData"],
44
+ "AddToWishlist": ["customData"],
45
+ "InitiateCheckout": ["customData"],
46
+ "SignUp": ["customData"],
47
+ "Search": ["customData"]
48
+ },
49
+ "advanced_matching_fields": {
50
+ "email": "email",
51
+ "phoneNumber": "phoneNumber",
52
+ "externalId": "externalId",
53
+ "ipAddress": "ipAddress",
54
+ "userAgent": "userAgent"
55
+ }
56
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Reddit Pixel Browser Template — CDP Edge Quantum Tier
3
+ *
4
+ * Este template contém o código de inicialização do Reddit Pixel
5
+ * Uso: Incluir no tracking.js gerado pelo Browser Tracking Agent
6
+ */
7
+
8
+ export const REDDIT_PIXEL_TEMPLATE = `
9
+ <!-- Reddit Pixel Base Code -->
10
+ <script>
11
+ !function(w,d){if(!w.rdt){var p=w.rdt=function(){p.sendEvent?p.sendEvent.apply(p,arguments):p.callQueue.push(arguments);p.callQueue=[];var t=d.createElement('script');t.src='https://www.redditstatic.com/ads/v2.js',t.async=!0;var s=d.getElementsByTagName('script')[0];s.parentNode.insertBefore(t,s)}}(window,document);
12
+ rdt('init', '{REDDIT_PIXEL_ID}', {
13
+ optOut: false,
14
+ useDecimalCurrencyValues: true,
15
+ email: '', // preencher após captura (hashed automaticamente pelo pixel)
16
+ });
17
+ rdt('track', 'PageVisit');
18
+ </script>
19
+ `;