@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 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 | Descripción |
92
- |---|---|
93
- | [ARCHITECTURE.md](./docs/ARCHITECTURE.md) | Arquitectura de 4 capas, patrones de diseño, reglas de implementación y convenciones de código |
94
- | [INTEGRATION-GUIDE.md](./docs/INTEGRATION-GUIDE.md) | Guía paso a paso de integración + tabla de migración desde KOREX-WEB-PROD |
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 | Uso | Archivo |
115
- |---|---|---|
116
- | **Singleton** | Una instancia global de VideoTracker | `video-tracker.ts` |
117
- | **Factory** | `createLandingTracker(config)` crea instancias | `landing-tracker.ts` |
118
- | **Observer** | Callbacks `onUpdate()` en adaptadores de video | `wistia-adapter.ts`, `voomly-adapter.ts` |
119
- | **Strategy** | `resolveTrackingId` inyecta lógica de resolución de GA ID | `analytics.ts` |
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 | Patrón | Ejemplo |
127
- |---|---|---|
128
- | Módulo core | `{nombre}.ts` | `analytics.ts`, `gtm.ts` |
129
- | Adaptador video | `{plataforma}-adapter.ts` | `wistia-adapter.ts` |
130
- | Clase tracker | `{nombre}-tracker.ts` | `video-tracker.ts` |
131
- | Hook React | `use-{nombre}.ts` | `use-landing-tracking.ts` |
132
- | Test unitario | `{módulo}.test.ts` | `analytics.test.ts` |
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 | Descripción |
141
- |---|---|
142
- | `initGA(config)` | Inicializa Google Analytics 4 |
143
- | `trackEvent(cat, action, label?, value?, data?)` | Envía evento a GA4 |
144
- | `trackPageView(path)` | Envía pageview |
145
- | `captureUTMParams()` | Extrae UTM params de la URL |
146
- | `captureUserIdFromURL()` | Lee `?user_id=` de la URL |
147
- | `createLandingTracker(config)` | Crea orquestador de sesión completa |
148
- | `trackWistiaByMediaId(id)` | Tracking de video Wistia |
149
- | `trackVoomlyByEmbedId(id)` | Tracking de video Voomly |
150
- | `trackHTML5Video(id, element)` | Tracking de `<video>` nativo |
151
- | `trackCTAClick(btn, section)` | Evento CTA click |
152
- | `trackFormSubmit(name, success)` | Evento formulario enviado |
153
- | `trackConversion(type, value?)` | Evento de conversión |
154
- | `pushToDataLayer(event, data)` | Push directo al GTM dataLayer |
155
- | `injectGTMScript(gtmId)` | Inyecta script de GTM |
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 | Descripción |
160
- |---|---|
161
- | `useLandingPageTracking(config)` | Hook orquestador de landing |
162
- | `useVideoTracking(options)` | Hook para HTML5 video |
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 | Config | Estilo |
179
- |---|---|---|
180
- | **ESLint** | `.eslintrc.json` | Airbnb base + TypeScript + Prettier |
181
- | **Prettier** | `.prettierrc` | `singleQuote`, `semi`, `printWidth: 140`, `tabWidth: 2` |
182
- | **TypeScript** | `tsconfig.json` | `strict: true`, ES2020, bundler module resolution |
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;