@metodokorexmk/tracking 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -61
- package/dist/index.cjs +83 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +227 -199
- package/dist/index.d.ts +227 -199
- package/dist/index.js +79 -37
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +27 -27
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +54 -54
- package/dist/react/index.d.ts +54 -54
- package/dist/react/index.js +27 -27
- package/dist/react/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -11,6 +11,8 @@ Sistema de tracking reutilizable para landing pages con **Google Analytics 4**,
|
|
|
11
11
|
- 🖱️ **Click heatmap**: Captura coordenadas de clicks por sección.
|
|
12
12
|
- 📝 **Form auto-tracking**: Detecta automáticamente inicio, campos y envío de formularios.
|
|
13
13
|
- ⏱️ **Dwell time por sección**: Mide tiempo de permanencia con IntersectionObserver.
|
|
14
|
+
- 🎯 **Funnel tracking**: Quiz, Thank You Page y WhatsApp click (Regla 1).
|
|
15
|
+
- 🔗 **Attribution completa**: `campaign_id`, `adset_id`, `ad_id`, UTMs (Regla 3).
|
|
14
16
|
- ⚛️ **Hooks React opcionales**: Import separado que no afecta a proyectos sin React.
|
|
15
17
|
- 🔧 **Framework-agnostic**: Las capas core funcionan en cualquier entorno con DOM.
|
|
16
18
|
|
|
@@ -29,69 +31,70 @@ yarn add @metodokorexmk/tracking react-ga4
|
|
|
29
31
|
### Vanilla JavaScript / TypeScript
|
|
30
32
|
|
|
31
33
|
```ts
|
|
32
|
-
import { initGA, trackPageView, trackEvent, createLandingTracker } from '@metodokorexmk/tracking'
|
|
34
|
+
import { initGA, trackPageView, trackEvent, createLandingTracker } from '@metodokorexmk/tracking';
|
|
33
35
|
|
|
34
36
|
// 1. Inicializar GA4
|
|
35
|
-
initGA({ trackingId: 'G-XXXXXXX' })
|
|
37
|
+
initGA({ trackingId: 'G-XXXXXXX' });
|
|
36
38
|
|
|
37
39
|
// 2. Trackear pageview
|
|
38
|
-
trackPageView('/mi-landing')
|
|
40
|
+
trackPageView('/mi-landing');
|
|
39
41
|
|
|
40
42
|
// 3. Crear tracker completo para la landing
|
|
41
43
|
const tracker = createLandingTracker({
|
|
42
44
|
pagePath: '/mi-landing',
|
|
43
45
|
pageName: 'Mi Landing Page',
|
|
44
46
|
gtmId: 'GTM-XXXXXXX', // Opcional
|
|
45
|
-
})
|
|
47
|
+
});
|
|
46
48
|
|
|
47
49
|
// 4. Trackear eventos manuales
|
|
48
|
-
trackEvent('CTA', 'click', 'Botón Principal')
|
|
50
|
+
trackEvent('CTA', 'click', 'Botón Principal');
|
|
49
51
|
|
|
50
52
|
// 5. Al desmontar:
|
|
51
|
-
tracker.destroy()
|
|
53
|
+
tracker.destroy();
|
|
52
54
|
```
|
|
53
55
|
|
|
54
56
|
### React / Next.js
|
|
55
57
|
|
|
56
58
|
```tsx
|
|
57
|
-
import { initGA } from '@metodokorexmk/tracking'
|
|
58
|
-
import { useLandingPageTracking, useVideoTracking } from '@metodokorexmk/tracking/react'
|
|
59
|
+
import { initGA } from '@metodokorexmk/tracking';
|
|
60
|
+
import { useLandingPageTracking, useVideoTracking } from '@metodokorexmk/tracking/react';
|
|
59
61
|
|
|
60
62
|
// Inicializar una vez en la app
|
|
61
|
-
initGA({ trackingId: 'G-XXXXXXX' })
|
|
63
|
+
initGA({ trackingId: 'G-XXXXXXX' });
|
|
62
64
|
|
|
63
65
|
function MiLanding() {
|
|
64
66
|
// Tracking automático de la landing
|
|
65
67
|
const tracker = useLandingPageTracking({
|
|
66
68
|
pagePath: '/mi-landing',
|
|
67
69
|
pageName: 'Mi Landing Page',
|
|
68
|
-
})
|
|
70
|
+
});
|
|
69
71
|
|
|
70
72
|
// Tracking de video HTML5
|
|
71
|
-
const videoRef = useRef<HTMLVideoElement>(null)
|
|
73
|
+
const videoRef = useRef<HTMLVideoElement>(null);
|
|
72
74
|
const { progress, isPlaying } = useVideoTracking({
|
|
73
75
|
videoId: 'hero-video',
|
|
74
76
|
videoElement: videoRef.current,
|
|
75
77
|
onComplete: () => console.log('Video completado'),
|
|
76
|
-
})
|
|
78
|
+
});
|
|
77
79
|
|
|
78
80
|
return (
|
|
79
81
|
<>
|
|
80
82
|
<video ref={videoRef} src="/video.mp4" />
|
|
81
|
-
<button onClick={() => tracker?.trackCTAClick('Unirse', 'hero')}>
|
|
82
|
-
Unirse
|
|
83
|
-
</button>
|
|
83
|
+
<button onClick={() => tracker?.trackCTAClick('Unirse', 'hero')}>Unirse</button>
|
|
84
84
|
</>
|
|
85
|
-
)
|
|
85
|
+
);
|
|
86
86
|
}
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
## Documentación
|
|
90
90
|
|
|
91
|
-
| Doc
|
|
92
|
-
|
|
93
|
-
| [
|
|
94
|
-
| [
|
|
91
|
+
| Doc | Descripción |
|
|
92
|
+
| ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
|
|
93
|
+
| [GUIA-COMPLETA.md](./docs/GUIA-COMPLETA.md) | Guía paso a paso completa: despliegue, integración y ejemplos |
|
|
94
|
+
| [ARCHITECTURE.md](./docs/ARCHITECTURE.md) | Arquitectura de 4 capas, patrones de diseño, reglas de implementación y convenciones de código |
|
|
95
|
+
| [INTEGRATION-GUIDE.md](./docs/INTEGRATION-GUIDE.md) | Guía paso a paso de integración + tabla de migración desde KOREX-WEB-PROD |
|
|
96
|
+
| [backend_rules_tracking.md](./docs/backend_rules_tracking.md) | Requerimientos de backend derivados de `rules_context.md` |
|
|
97
|
+
| [rules_context.md](./docs/rules_context.md) | Reglas de negocio del sistema de métricas de ads |
|
|
95
98
|
|
|
96
99
|
## Arquitectura
|
|
97
100
|
|
|
@@ -111,25 +114,25 @@ Core ← analytics (GA4), gtm, types
|
|
|
111
114
|
|
|
112
115
|
### Patrones de diseño aplicados
|
|
113
116
|
|
|
114
|
-
| Patrón
|
|
115
|
-
|
|
116
|
-
| **Singleton** | Una instancia global de VideoTracker
|
|
117
|
-
| **Factory**
|
|
118
|
-
| **Observer**
|
|
119
|
-
| **Strategy**
|
|
120
|
-
| **Dual Send** | Cada evento se envía por `gtag` + `ReactGA` simultáneamente | `analytics.ts`
|
|
117
|
+
| Patrón | Uso | Archivo |
|
|
118
|
+
| ------------- | ----------------------------------------------------------- | ---------------------------------------- |
|
|
119
|
+
| **Singleton** | Una instancia global de VideoTracker | `video-tracker.ts` |
|
|
120
|
+
| **Factory** | `createLandingTracker(config)` crea instancias | `landing-tracker.ts` |
|
|
121
|
+
| **Observer** | Callbacks `onUpdate()` en adaptadores de video | `wistia-adapter.ts`, `voomly-adapter.ts` |
|
|
122
|
+
| **Strategy** | `resolveTrackingId` inyecta lógica de resolución de GA ID | `analytics.ts` |
|
|
123
|
+
| **Dual Send** | Cada evento se envía por `gtag` + `ReactGA` simultáneamente | `analytics.ts` |
|
|
121
124
|
|
|
122
125
|
Ver [ARCHITECTURE.md](./docs/ARCHITECTURE.md) para detalles completos.
|
|
123
126
|
|
|
124
127
|
## Convenciones de nombrado de archivos
|
|
125
128
|
|
|
126
|
-
| Tipo
|
|
127
|
-
|
|
128
|
-
| Módulo core
|
|
129
|
-
| Adaptador video | `{plataforma}-adapter.ts` | `wistia-adapter.ts`
|
|
130
|
-
| Clase tracker
|
|
131
|
-
| Hook React
|
|
132
|
-
| Test unitario
|
|
129
|
+
| Tipo | Patrón | Ejemplo |
|
|
130
|
+
| --------------- | ------------------------- | ------------------------- |
|
|
131
|
+
| Módulo core | `{nombre}.ts` | `analytics.ts`, `gtm.ts` |
|
|
132
|
+
| Adaptador video | `{plataforma}-adapter.ts` | `wistia-adapter.ts` |
|
|
133
|
+
| Clase tracker | `{nombre}-tracker.ts` | `video-tracker.ts` |
|
|
134
|
+
| Hook React | `use-{nombre}.ts` | `use-landing-tracking.ts` |
|
|
135
|
+
| Test unitario | `{módulo}.test.ts` | `analytics.test.ts` |
|
|
133
136
|
|
|
134
137
|
> Todos los archivos usan **kebab-case**. Exports usan `camelCase` (funciones) y `PascalCase` (clases/tipos).
|
|
135
138
|
|
|
@@ -137,30 +140,36 @@ Ver [ARCHITECTURE.md](./docs/ARCHITECTURE.md) para detalles completos.
|
|
|
137
140
|
|
|
138
141
|
### Core (`@metodokorexmk/tracking`)
|
|
139
142
|
|
|
140
|
-
| Export
|
|
141
|
-
|
|
142
|
-
| `initGA(config)`
|
|
143
|
-
| `trackEvent(cat, action, label?, value?, data?)` | Envía evento a GA4
|
|
144
|
-
| `trackPageView(path)`
|
|
145
|
-
| `captureUTMParams()`
|
|
146
|
-
| `captureUserIdFromURL()`
|
|
147
|
-
| `createLandingTracker(config)`
|
|
148
|
-
| `trackWistiaByMediaId(id)`
|
|
149
|
-
| `trackVoomlyByEmbedId(id)`
|
|
150
|
-
| `trackHTML5Video(id, element)`
|
|
151
|
-
| `trackCTAClick(btn, section)`
|
|
152
|
-
| `trackFormSubmit(name, success)`
|
|
153
|
-
| `trackConversion(type, value?)`
|
|
154
|
-
| `
|
|
155
|
-
| `
|
|
143
|
+
| Export | Descripción |
|
|
144
|
+
| ------------------------------------------------ | ------------------------------------------------- |
|
|
145
|
+
| `initGA(config)` | Inicializa Google Analytics 4 |
|
|
146
|
+
| `trackEvent(cat, action, label?, value?, data?)` | Envía evento a GA4 |
|
|
147
|
+
| `trackPageView(path)` | Envía pageview |
|
|
148
|
+
| `captureUTMParams()` | Extrae UTM params de la URL |
|
|
149
|
+
| `captureUserIdFromURL()` | Lee `?user_id=` de la URL |
|
|
150
|
+
| `createLandingTracker(config)` | Crea orquestador de sesión completa |
|
|
151
|
+
| `trackWistiaByMediaId(id)` | Tracking de video Wistia |
|
|
152
|
+
| `trackVoomlyByEmbedId(id)` | Tracking de video Voomly |
|
|
153
|
+
| `trackHTML5Video(id, element)` | Tracking de `<video>` nativo |
|
|
154
|
+
| `trackCTAClick(btn, section)` | Evento CTA click |
|
|
155
|
+
| `trackFormSubmit(name, success)` | Evento formulario enviado |
|
|
156
|
+
| `trackConversion(type, value?)` | Evento de conversión |
|
|
157
|
+
| `trackQuizStart(quizName)` | Evento inicio de quiz |
|
|
158
|
+
| `trackQuizAnswer(quizName, index, answer)` | Evento respuesta a pregunta del quiz |
|
|
159
|
+
| `trackQuizComplete(quizName, total?, score?)` | Evento quiz completado |
|
|
160
|
+
| `trackThankYouPageVisit(source?)` | Evento visita a Thank You Page |
|
|
161
|
+
| `trackWhatsAppClick(phone?, section?)` | Evento clic en enlace WhatsApp |
|
|
162
|
+
| `extractUrlParams(url?)` | Extrae params de tracking incl. `adsetId`, `adId` |
|
|
163
|
+
| `pushToDataLayer(event, data)` | Push directo al GTM dataLayer |
|
|
164
|
+
| `injectGTMScript(gtmId)` | Inyecta script de GTM |
|
|
156
165
|
|
|
157
166
|
### React Hooks (`@metodokorexmk/tracking/react`)
|
|
158
167
|
|
|
159
|
-
| Export
|
|
160
|
-
|
|
161
|
-
| `useLandingPageTracking(config)`
|
|
162
|
-
| `useVideoTracking(options)`
|
|
163
|
-
| `useWistiaVideoTracking(mediaId)` | Hook para Wistia video
|
|
168
|
+
| Export | Descripción |
|
|
169
|
+
| --------------------------------- | --------------------------- |
|
|
170
|
+
| `useLandingPageTracking(config)` | Hook orquestador de landing |
|
|
171
|
+
| `useVideoTracking(options)` | Hook para HTML5 video |
|
|
172
|
+
| `useWistiaVideoTracking(mediaId)` | Hook para Wistia video |
|
|
164
173
|
|
|
165
174
|
## Calidad de código
|
|
166
175
|
|
|
@@ -175,11 +184,11 @@ npm run format:check # Verificar formato sin modificar
|
|
|
175
184
|
|
|
176
185
|
### Config
|
|
177
186
|
|
|
178
|
-
| Herramienta
|
|
179
|
-
|
|
180
|
-
| **ESLint**
|
|
181
|
-
| **Prettier**
|
|
182
|
-
| **TypeScript** | `tsconfig.json`
|
|
187
|
+
| Herramienta | Config | Estilo |
|
|
188
|
+
| -------------- | ---------------- | ------------------------------------------------------- |
|
|
189
|
+
| **ESLint** | `.eslintrc.json` | Airbnb base + TypeScript + Prettier |
|
|
190
|
+
| **Prettier** | `.prettierrc` | `singleQuote`, `semi`, `printWidth: 140`, `tabWidth: 2` |
|
|
191
|
+
| **TypeScript** | `tsconfig.json` | `strict: true`, ES2020, bundler module resolution |
|
|
183
192
|
|
|
184
193
|
## Scripts
|
|
185
194
|
|
|
@@ -197,4 +206,3 @@ npm run format:check # Verificar formato
|
|
|
197
206
|
## Licencia
|
|
198
207
|
|
|
199
208
|
MIT
|
|
200
|
-
|
package/dist/index.cjs
CHANGED
|
@@ -259,7 +259,7 @@ var VideoTracker = class {
|
|
|
259
259
|
this.watchTimeIntervals = /* @__PURE__ */ new Map();
|
|
260
260
|
}
|
|
261
261
|
/**
|
|
262
|
-
*
|
|
262
|
+
* Initializes tracking for a video.
|
|
263
263
|
*/
|
|
264
264
|
initVideo(videoId) {
|
|
265
265
|
if (this.videos.has(videoId)) return;
|
|
@@ -287,7 +287,7 @@ var VideoTracker = class {
|
|
|
287
287
|
});
|
|
288
288
|
}
|
|
289
289
|
/**
|
|
290
|
-
*
|
|
290
|
+
* Tracks a play event.
|
|
291
291
|
*/
|
|
292
292
|
trackPlay(videoId, currentTime = 0) {
|
|
293
293
|
const state = this.getOrCreateState(videoId);
|
|
@@ -303,7 +303,7 @@ var VideoTracker = class {
|
|
|
303
303
|
});
|
|
304
304
|
}
|
|
305
305
|
/**
|
|
306
|
-
*
|
|
306
|
+
* Tracks a pause event.
|
|
307
307
|
*/
|
|
308
308
|
trackPause(videoId, currentTime, duration) {
|
|
309
309
|
const state = this.getOrCreateState(videoId);
|
|
@@ -325,7 +325,7 @@ var VideoTracker = class {
|
|
|
325
325
|
});
|
|
326
326
|
}
|
|
327
327
|
/**
|
|
328
|
-
*
|
|
328
|
+
* Tracks a seek event (timeline jump).
|
|
329
329
|
*/
|
|
330
330
|
trackSeek(videoId, fromTime, toTime) {
|
|
331
331
|
const state = this.getOrCreateState(videoId);
|
|
@@ -340,7 +340,7 @@ var VideoTracker = class {
|
|
|
340
340
|
});
|
|
341
341
|
}
|
|
342
342
|
/**
|
|
343
|
-
*
|
|
343
|
+
* Tracks progress milestones (25%, 50%, 75%).
|
|
344
344
|
*/
|
|
345
345
|
trackProgress(videoId, percentage, currentTime) {
|
|
346
346
|
const state = this.getOrCreateState(videoId);
|
|
@@ -356,7 +356,7 @@ var VideoTracker = class {
|
|
|
356
356
|
}
|
|
357
357
|
}
|
|
358
358
|
/**
|
|
359
|
-
*
|
|
359
|
+
* Tracks video completion (>=95%).
|
|
360
360
|
*/
|
|
361
361
|
trackComplete(videoId, totalDuration) {
|
|
362
362
|
const state = this.getOrCreateState(videoId);
|
|
@@ -373,7 +373,7 @@ var VideoTracker = class {
|
|
|
373
373
|
});
|
|
374
374
|
}
|
|
375
375
|
/**
|
|
376
|
-
*
|
|
376
|
+
* Tracks video end (native ended event).
|
|
377
377
|
*/
|
|
378
378
|
trackEnd(videoId) {
|
|
379
379
|
const state = this.getOrCreateState(videoId);
|
|
@@ -386,7 +386,7 @@ var VideoTracker = class {
|
|
|
386
386
|
});
|
|
387
387
|
}
|
|
388
388
|
/**
|
|
389
|
-
*
|
|
389
|
+
* Tracks playback speed change.
|
|
390
390
|
*/
|
|
391
391
|
trackSpeedChange(videoId, speed) {
|
|
392
392
|
const state = this.getOrCreateState(videoId);
|
|
@@ -397,7 +397,7 @@ var VideoTracker = class {
|
|
|
397
397
|
});
|
|
398
398
|
}
|
|
399
399
|
/**
|
|
400
|
-
*
|
|
400
|
+
* Tracks fullscreen toggle.
|
|
401
401
|
*/
|
|
402
402
|
trackFullscreen(videoId, isFullscreen) {
|
|
403
403
|
trackEvent("Video", isFullscreen ? "fullscreen_enter" : "fullscreen_exit", videoId, void 0, {
|
|
@@ -406,7 +406,7 @@ var VideoTracker = class {
|
|
|
406
406
|
});
|
|
407
407
|
}
|
|
408
408
|
/**
|
|
409
|
-
*
|
|
409
|
+
* Tracks no interaction (user is on the page but not interacting with the video).
|
|
410
410
|
*/
|
|
411
411
|
trackNoInteraction(videoId, timeOnPage) {
|
|
412
412
|
trackEvent("Video", "no_interaction", videoId, void 0, {
|
|
@@ -415,20 +415,20 @@ var VideoTracker = class {
|
|
|
415
415
|
});
|
|
416
416
|
}
|
|
417
417
|
/**
|
|
418
|
-
*
|
|
418
|
+
* Returns the current state of a video.
|
|
419
419
|
*/
|
|
420
420
|
getState(videoId) {
|
|
421
421
|
return this.videos.get(videoId);
|
|
422
422
|
}
|
|
423
423
|
/**
|
|
424
|
-
*
|
|
424
|
+
* Cleans up tracking for a specific video.
|
|
425
425
|
*/
|
|
426
426
|
cleanup(videoId) {
|
|
427
427
|
this.stopWatchTimeTracking(videoId);
|
|
428
428
|
this.videos.delete(videoId);
|
|
429
429
|
}
|
|
430
430
|
/**
|
|
431
|
-
*
|
|
431
|
+
* Cleans up all video tracking.
|
|
432
432
|
*/
|
|
433
433
|
cleanupAll() {
|
|
434
434
|
for (const videoId of this.videos.keys()) {
|
|
@@ -436,7 +436,7 @@ var VideoTracker = class {
|
|
|
436
436
|
}
|
|
437
437
|
this.videos.clear();
|
|
438
438
|
}
|
|
439
|
-
// ---
|
|
439
|
+
// --- Private methods ---
|
|
440
440
|
getOrCreateState(videoId) {
|
|
441
441
|
if (!this.videos.has(videoId)) {
|
|
442
442
|
this.initVideo(videoId);
|
|
@@ -559,6 +559,34 @@ var trackDownload = (fileName, fileType) => {
|
|
|
559
559
|
file_type: fileType
|
|
560
560
|
});
|
|
561
561
|
};
|
|
562
|
+
var trackQuizStart = (quizName) => {
|
|
563
|
+
trackEvent("Quiz", "started", quizName, void 0, {
|
|
564
|
+
quiz_name: quizName
|
|
565
|
+
});
|
|
566
|
+
};
|
|
567
|
+
var trackQuizAnswer = (quizName, questionIndex, answer) => {
|
|
568
|
+
trackEvent("Quiz", "answer", quizName, questionIndex, {
|
|
569
|
+
quiz_name: quizName,
|
|
570
|
+
question_index: questionIndex,
|
|
571
|
+
answer
|
|
572
|
+
});
|
|
573
|
+
};
|
|
574
|
+
var trackQuizComplete = (quizName, totalQuestions, score) => {
|
|
575
|
+
trackEvent("Quiz", "completed", quizName, totalQuestions, {
|
|
576
|
+
quiz_name: quizName,
|
|
577
|
+
...totalQuestions !== void 0 && { total_questions: totalQuestions },
|
|
578
|
+
...score !== void 0 && { score }
|
|
579
|
+
});
|
|
580
|
+
};
|
|
581
|
+
var trackThankYouPageVisit = (source) => {
|
|
582
|
+
trackEvent("Funnel", "thank_you_page_visit", source);
|
|
583
|
+
};
|
|
584
|
+
var trackWhatsAppClick = (phoneNumber, section) => {
|
|
585
|
+
trackEvent("WhatsApp", "click", section, void 0, {
|
|
586
|
+
...phoneNumber && { phone_number: phoneNumber },
|
|
587
|
+
...section && { section }
|
|
588
|
+
});
|
|
589
|
+
};
|
|
562
590
|
|
|
563
591
|
// src/trackers/wistia-adapter.ts
|
|
564
592
|
var createStats = (timeWatched, completed) => ({
|
|
@@ -856,7 +884,7 @@ var LandingTracker = class {
|
|
|
856
884
|
this.listeners = [];
|
|
857
885
|
}
|
|
858
886
|
/**
|
|
859
|
-
*
|
|
887
|
+
* Initializes landing page tracking with the given configuration.
|
|
860
888
|
*/
|
|
861
889
|
init(config) {
|
|
862
890
|
if (typeof window === "undefined") return;
|
|
@@ -892,7 +920,7 @@ var LandingTracker = class {
|
|
|
892
920
|
this.trackSessionStart();
|
|
893
921
|
}
|
|
894
922
|
/**
|
|
895
|
-
*
|
|
923
|
+
* Destroys the tracker and cleans up all observers and listeners.
|
|
896
924
|
*/
|
|
897
925
|
destroy() {
|
|
898
926
|
this.observers.forEach((obs) => obs.disconnect());
|
|
@@ -908,43 +936,43 @@ var LandingTracker = class {
|
|
|
908
936
|
this.sectionTimers.clear();
|
|
909
937
|
}
|
|
910
938
|
// ====================================
|
|
911
|
-
//
|
|
939
|
+
// PUBLIC TRACKING METHODS
|
|
912
940
|
// ====================================
|
|
913
|
-
/**
|
|
941
|
+
/** Track a CTA click */
|
|
914
942
|
trackCTAClick(buttonName, section, additionalData) {
|
|
915
943
|
trackCTAClick(buttonName, section, additionalData);
|
|
916
944
|
this.pushGTMEvent("cta_click", { button_text: buttonName, section });
|
|
917
945
|
}
|
|
918
|
-
/**
|
|
946
|
+
/** Track a conversion */
|
|
919
947
|
trackConversion(type, value, additionalData) {
|
|
920
948
|
trackEvent("Conversion", type, void 0, value, additionalData);
|
|
921
949
|
this.pushGTMEvent("conversion", { conversion_type: type, value });
|
|
922
950
|
}
|
|
923
|
-
/**
|
|
951
|
+
/** Track FAQ expansion */
|
|
924
952
|
trackFAQExpand(question, index) {
|
|
925
953
|
trackEvent("FAQ", "expand", question, index);
|
|
926
954
|
}
|
|
927
|
-
/**
|
|
955
|
+
/** Track social link click */
|
|
928
956
|
trackSocialClick(platform, action) {
|
|
929
957
|
trackEvent("Social", "click", platform, void 0, { social_action: action });
|
|
930
958
|
}
|
|
931
|
-
/**
|
|
959
|
+
/** Track image click */
|
|
932
960
|
trackImageClick(imageName, section) {
|
|
933
961
|
trackEvent("Engagement", "image_click", imageName, void 0, { section });
|
|
934
962
|
}
|
|
935
|
-
/**
|
|
963
|
+
/** Track scroll to a section */
|
|
936
964
|
trackScrollTo(section) {
|
|
937
965
|
trackEvent("Navigation", "scroll_to", section);
|
|
938
966
|
}
|
|
939
|
-
/**
|
|
967
|
+
/** Track content share */
|
|
940
968
|
trackShare(platform, content) {
|
|
941
969
|
trackEvent("Share", "click", platform, void 0, { share_content: content });
|
|
942
970
|
}
|
|
943
|
-
/**
|
|
971
|
+
/** Track file download */
|
|
944
972
|
trackDownload(fileName, fileType) {
|
|
945
973
|
trackEvent("Download", "click", fileName, void 0, { file_type: fileType });
|
|
946
974
|
}
|
|
947
|
-
/**
|
|
975
|
+
/** Get current session data */
|
|
948
976
|
getSessionData() {
|
|
949
977
|
return {
|
|
950
978
|
duration: Math.round((Date.now() - this.sessionStartTime) / 1e3),
|
|
@@ -953,7 +981,7 @@ var LandingTracker = class {
|
|
|
953
981
|
};
|
|
954
982
|
}
|
|
955
983
|
// ====================================
|
|
956
|
-
//
|
|
984
|
+
// PRIVATE METHODS
|
|
957
985
|
// ====================================
|
|
958
986
|
captureInitialData() {
|
|
959
987
|
const utmParams = captureUTMParams();
|
|
@@ -1141,7 +1169,7 @@ var initTrackingAPI = (config) => {
|
|
|
1141
1169
|
};
|
|
1142
1170
|
var getAPIConfig = () => {
|
|
1143
1171
|
if (!apiConfig) {
|
|
1144
|
-
throw new Error("[@metodokorexmk/tracking] initTrackingAPI()
|
|
1172
|
+
throw new Error("[@metodokorexmk/tracking] initTrackingAPI() must be called before using persistence functions.");
|
|
1145
1173
|
}
|
|
1146
1174
|
return apiConfig;
|
|
1147
1175
|
};
|
|
@@ -1197,11 +1225,14 @@ var extractUrlParams = (url) => {
|
|
|
1197
1225
|
return {
|
|
1198
1226
|
userId: "",
|
|
1199
1227
|
idCampana: "",
|
|
1228
|
+
adsetId: "",
|
|
1229
|
+
adId: "",
|
|
1200
1230
|
utmContent: "",
|
|
1201
1231
|
fbclid: "",
|
|
1202
1232
|
nombreNetworker: "",
|
|
1203
1233
|
whatsapp: "",
|
|
1204
1234
|
pipelineId: "",
|
|
1235
|
+
leadCampaign: "Funnel Organico",
|
|
1205
1236
|
leadCampaing: "Funnel Organico",
|
|
1206
1237
|
isOrganico: true
|
|
1207
1238
|
};
|
|
@@ -1219,6 +1250,8 @@ var extractUrlParams = (url) => {
|
|
|
1219
1250
|
}
|
|
1220
1251
|
const userId = searchParams.get("user_id") || "";
|
|
1221
1252
|
const idCampana = searchParams.get("campaign_id") || searchParams.get("utm_id") || "";
|
|
1253
|
+
const adsetId = searchParams.get("adset_id") || "";
|
|
1254
|
+
const adId = searchParams.get("ad_id") || "";
|
|
1222
1255
|
const utmContent = searchParams.get("utm_content") || "";
|
|
1223
1256
|
const fbclid = searchParams.get("fbclid") || "";
|
|
1224
1257
|
const whatsapp = searchParams.get("whatsapp") || "";
|
|
@@ -1234,6 +1267,8 @@ var extractUrlParams = (url) => {
|
|
|
1234
1267
|
return {
|
|
1235
1268
|
userId,
|
|
1236
1269
|
idCampana,
|
|
1270
|
+
adsetId,
|
|
1271
|
+
adId,
|
|
1237
1272
|
utmContent,
|
|
1238
1273
|
fbclid,
|
|
1239
1274
|
nombreNetworker,
|
|
@@ -1244,6 +1279,7 @@ var extractUrlParams = (url) => {
|
|
|
1244
1279
|
utmSource,
|
|
1245
1280
|
utmMedium,
|
|
1246
1281
|
utmCampaign,
|
|
1282
|
+
leadCampaign: leadCampaing,
|
|
1247
1283
|
leadCampaing,
|
|
1248
1284
|
isOrganico
|
|
1249
1285
|
};
|
|
@@ -1286,6 +1322,12 @@ var buildTrackingRequestBody = (params, formData, origin, options) => {
|
|
|
1286
1322
|
body.referringUserId = collaboratorId;
|
|
1287
1323
|
body.referring_user_id = collaboratorId;
|
|
1288
1324
|
}
|
|
1325
|
+
if (params.adsetId) body.adsetId = params.adsetId;
|
|
1326
|
+
if (params.adId) body.adId = params.adId;
|
|
1327
|
+
if (params.utmSource) body.utmSource = params.utmSource;
|
|
1328
|
+
if (params.utmMedium) body.utmMedium = params.utmMedium;
|
|
1329
|
+
if (params.utmCampaign) body.utmCampaign = params.utmCampaign;
|
|
1330
|
+
if (params.leadCampaign) body.leadCampaign = params.leadCampaign;
|
|
1289
1331
|
if (params.pipelineId) {
|
|
1290
1332
|
const parsed = parseInt(params.pipelineId, 10);
|
|
1291
1333
|
if (!isNaN(parsed)) body.pipeline_id = parsed;
|
|
@@ -1384,7 +1426,7 @@ var DwellTimeTracker = class {
|
|
|
1384
1426
|
this.boundVisibilityChange = this.handleVisibilityChange.bind(this);
|
|
1385
1427
|
}
|
|
1386
1428
|
/**
|
|
1387
|
-
*
|
|
1429
|
+
* Starts dwell time tracking.
|
|
1388
1430
|
*/
|
|
1389
1431
|
start(config) {
|
|
1390
1432
|
if (typeof window === "undefined") return;
|
|
@@ -1421,7 +1463,7 @@ var DwellTimeTracker = class {
|
|
|
1421
1463
|
this.retryPendingUpdates();
|
|
1422
1464
|
}
|
|
1423
1465
|
/**
|
|
1424
|
-
*
|
|
1466
|
+
* Stops tracking and sends accumulated time.
|
|
1425
1467
|
*/
|
|
1426
1468
|
stop() {
|
|
1427
1469
|
if (this.startTime) {
|
|
@@ -1436,7 +1478,7 @@ var DwellTimeTracker = class {
|
|
|
1436
1478
|
this.cleanup();
|
|
1437
1479
|
}
|
|
1438
1480
|
/**
|
|
1439
|
-
*
|
|
1481
|
+
* Returns elapsed time in seconds (excluding paused time).
|
|
1440
1482
|
*/
|
|
1441
1483
|
getElapsedTime() {
|
|
1442
1484
|
if (!this.startTime) return 0;
|
|
@@ -1448,8 +1490,8 @@ var DwellTimeTracker = class {
|
|
|
1448
1490
|
return Math.max(0, totalTime - currentPauseTime);
|
|
1449
1491
|
}
|
|
1450
1492
|
/**
|
|
1451
|
-
*
|
|
1452
|
-
*
|
|
1493
|
+
* Manually updates video time.
|
|
1494
|
+
* Called from VideoTracker or other adapters.
|
|
1453
1495
|
*/
|
|
1454
1496
|
updateVideoTime(videoTimeWatched, videoCompleted = false) {
|
|
1455
1497
|
const hasNewTime = videoTimeWatched > this.videoTimeWatched;
|
|
@@ -1463,7 +1505,7 @@ var DwellTimeTracker = class {
|
|
|
1463
1505
|
}
|
|
1464
1506
|
}
|
|
1465
1507
|
/**
|
|
1466
|
-
*
|
|
1508
|
+
* Updates the trackingDataId (useful when obtained after registration).
|
|
1467
1509
|
*/
|
|
1468
1510
|
updateTrackingId(trackingDataId) {
|
|
1469
1511
|
if (!trackingDataId || typeof trackingDataId === "string" && trackingDataId.trim() === "") return;
|
|
@@ -1486,7 +1528,7 @@ var DwellTimeTracker = class {
|
|
|
1486
1528
|
}
|
|
1487
1529
|
}
|
|
1488
1530
|
/**
|
|
1489
|
-
*
|
|
1531
|
+
* Cleans up all listeners and timers.
|
|
1490
1532
|
*/
|
|
1491
1533
|
destroy() {
|
|
1492
1534
|
this.stop();
|
|
@@ -1546,7 +1588,7 @@ var DwellTimeTracker = class {
|
|
|
1546
1588
|
const isNetworkError = err.name === "AbortError" || err.name === "TimeoutError" || err.name === "TypeError" && err.message?.includes("Failed to fetch");
|
|
1547
1589
|
if (token) this.savePendingUpdate(elapsedTime);
|
|
1548
1590
|
if (this.onError && !isNetworkError) {
|
|
1549
|
-
this.onError(error instanceof Error ? error : new Error("
|
|
1591
|
+
this.onError(error instanceof Error ? error : new Error("Unknown error"));
|
|
1550
1592
|
}
|
|
1551
1593
|
} finally {
|
|
1552
1594
|
this.isSending = false;
|
|
@@ -1766,12 +1808,17 @@ exports.trackHTML5Video = trackHTML5Video;
|
|
|
1766
1808
|
exports.trackImageClick = trackImageClick;
|
|
1767
1809
|
exports.trackPageView = trackPageView;
|
|
1768
1810
|
exports.trackPricingCardClick = trackPricingCardClick;
|
|
1811
|
+
exports.trackQuizAnswer = trackQuizAnswer;
|
|
1812
|
+
exports.trackQuizComplete = trackQuizComplete;
|
|
1813
|
+
exports.trackQuizStart = trackQuizStart;
|
|
1769
1814
|
exports.trackScrollTo = trackScrollTo;
|
|
1770
1815
|
exports.trackSectionClick = trackSectionClick;
|
|
1771
1816
|
exports.trackShare = trackShare;
|
|
1772
1817
|
exports.trackSocialClick = trackSocialClick;
|
|
1818
|
+
exports.trackThankYouPageVisit = trackThankYouPageVisit;
|
|
1773
1819
|
exports.trackTimeInSection = trackTimeInSection;
|
|
1774
1820
|
exports.trackVoomlyByEmbedId = trackVoomlyByEmbedId;
|
|
1821
|
+
exports.trackWhatsAppClick = trackWhatsAppClick;
|
|
1775
1822
|
exports.trackWistiaByMediaId = trackWistiaByMediaId;
|
|
1776
1823
|
exports.updateTrackingLead = updateTrackingLead;
|
|
1777
1824
|
exports.videoTracker = videoTracker;
|