@metodokorexmk/tracking 1.0.0 → 1.1.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 +43 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -1
- package/dist/index.d.ts +31 -1
- package/dist/index.js +39 -1
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs.map +1 -1
- 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
|
@@ -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) => ({
|
|
@@ -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
|
};
|
|
@@ -1280,6 +1316,8 @@ var buildTrackingRequestBody = (params, formData, origin, options) => {
|
|
|
1280
1316
|
if (origin.hasCampaign) {
|
|
1281
1317
|
if (collaboratorId) body.userId = collaboratorId;
|
|
1282
1318
|
if (params.idCampana) body.idCampana = params.idCampana;
|
|
1319
|
+
if (params.adsetId) body.adsetId = params.adsetId;
|
|
1320
|
+
if (params.adId) body.adId = params.adId;
|
|
1283
1321
|
if (params.utmContent) body.utmContent = params.utmContent;
|
|
1284
1322
|
if (params.fbclid) body.fbclid = params.fbclid;
|
|
1285
1323
|
} else if (collaboratorId) {
|
|
@@ -1766,12 +1804,17 @@ exports.trackHTML5Video = trackHTML5Video;
|
|
|
1766
1804
|
exports.trackImageClick = trackImageClick;
|
|
1767
1805
|
exports.trackPageView = trackPageView;
|
|
1768
1806
|
exports.trackPricingCardClick = trackPricingCardClick;
|
|
1807
|
+
exports.trackQuizAnswer = trackQuizAnswer;
|
|
1808
|
+
exports.trackQuizComplete = trackQuizComplete;
|
|
1809
|
+
exports.trackQuizStart = trackQuizStart;
|
|
1769
1810
|
exports.trackScrollTo = trackScrollTo;
|
|
1770
1811
|
exports.trackSectionClick = trackSectionClick;
|
|
1771
1812
|
exports.trackShare = trackShare;
|
|
1772
1813
|
exports.trackSocialClick = trackSocialClick;
|
|
1814
|
+
exports.trackThankYouPageVisit = trackThankYouPageVisit;
|
|
1773
1815
|
exports.trackTimeInSection = trackTimeInSection;
|
|
1774
1816
|
exports.trackVoomlyByEmbedId = trackVoomlyByEmbedId;
|
|
1817
|
+
exports.trackWhatsAppClick = trackWhatsAppClick;
|
|
1775
1818
|
exports.trackWistiaByMediaId = trackWistiaByMediaId;
|
|
1776
1819
|
exports.updateTrackingLead = updateTrackingLead;
|
|
1777
1820
|
exports.videoTracker = videoTracker;
|