@bacano/sdk 1.1.20 → 1.2.2

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
@@ -945,6 +945,10 @@ contains only browser-safe media metadata and a public Storage URL.
945
945
 
946
946
  GA4, Meta, and Microsoft Clarity are configured per website in Bacano and are
947
947
  disabled by default.
948
+ An optional Google Tag Manager web container is also supported via
949
+ `marketing.destinations.gtm.containerId`. It adds `bacano_*` browser events to
950
+ the data layer without replacing native destinations or server conversions.
951
+ See [GTM setup, limitations and duplication safeguards](./STOREFRONT_MARKETING.md#google-tag-manager-contenedor-web-opcional).
948
952
  The existing public-config request returns only active public destination IDs;
949
953
  provider secrets never reach the SDK. The runtime remains a no-op outside the
950
954
  website's canonical production domain.
@@ -1,5 +1,12 @@
1
1
  # Formularios de websites
2
2
 
3
+ Desde SDK 1.2.0, `BacanoForm` instrumenta interacciones mediante el provider
4
+ global de marketing. Para modales montados ocultos, pasar `visible={open}`.
5
+ Renderers personalizados usan `useBacanoFormTracking`. Leer la sección de
6
+ interacciones en [STOREFRONT_MARKETING.md](./STOREFRONT_MARKETING.md) y los
7
+ [ejemplos de migración](./skills/bacano-web/references/interactions.md).
8
+ No añadir un segundo listener ni convertir aperturas en leads.
9
+
3
10
  Los formularios públicos de Bacano son definiciones tipadas y versionadas. El
4
11
  storefront decide dónde se muestran y cómo lucen; Bacano controla su estructura,
5
12
  estado y validaciones. La definición nunca contiene HTML ni JavaScript arbitrario.
@@ -6,9 +6,65 @@ identificadores, adaptadores ni llamadas directas a proveedores.
6
6
 
7
7
  ## Regla principal
8
8
 
9
+ ### Google Tag Manager (contenedor web opcional)
10
+
11
+ En Bacano, la tarjeta Google Tag Manager permite guardar un ID `GTM-…`, validar
12
+ que el script publicado sea accesible y activar o pausar la integración por sitio.
13
+ Validar no comprueba propiedad del contenedor, etiquetas, consentimiento ni
14
+ recepción de eventos: comprobar esto en Tag Assistant con el administrador del
15
+ contenedor. No se solicitan secretos, HTML ni URLs de scripts personalizados.
16
+
17
+ Requiere desplegar API/migración y actualizar `@bacano/sdk` en el storefront.
18
+ El contrato público añade `marketing.destinations.gtm.containerId`; SDKs anteriores
19
+ lo ignoran. Un sitio con configuración estática debe reconstruirse para incorporar
20
+ cambios. No se modifica ni se publica automáticamente ningún contenedor de Google.
21
+
22
+ El mismo `BacanoMarketingProvider` carga `gtm.js` una sola vez, conserva la cola
23
+ `window.dataLayer` existente y respeta las barreras de dominio, preview y
24
+ `measurementAllowed`, además de la carga diferida. No instalar otro snippet.
25
+ Esta versión requiere JavaScript; no incorpora un iframe `noscript` ni GTM server-side.
26
+ Pausar evita nuevas cargas con la configuración actualizada; no puede deshacer
27
+ etiquetas de terceros ya ejecutadas en pestañas abiertas. Recargar para comprobar.
28
+
29
+ Los eventos oficiales de navegador se publican con prefijo `bacano_`:
30
+
31
+ ```js
32
+ { event: "bacano_add_to_cart", bacano: {
33
+ schema_version: 1, event_name: "add_to_cart", event_id: "…",
34
+ currency: "COP", value: 50000,
35
+ items: [{ item_id: "product-variant-id", item_name: "Producto", quantity: 1 }]
36
+ } }
37
+ ```
38
+
39
+ Configurar activadores de evento personalizado `bacano_*` y variables de capa de
40
+ datos como `bacano.event_name`, `bacano.value` y `bacano.items`. El objeto `bacano`
41
+ se limpia antes de cada evento para no arrastrar artículos ni parámetros anteriores.
42
+ Incluye URL saneada, parámetros de comercio e identificadores técnicos de
43
+ interacciones; no copia datos de clientes, valores de formularios, atribución,
44
+ títulos de página ni texto libre de búsqueda. Los eventos `search` no llevan el término.
45
+ No emitir desde GTM `purchase`, `refund` u `order_placed` basándose en la página de
46
+ gracias: siguen siendo autoritativos del servidor y no se publican en este puente.
47
+
48
+ GA4, Meta y Clarity nativos permanecen sin cambios. **No repetir esos destinos o
49
+ conversiones dentro del contenedor**. Esta fase no es un modo alternativo completo
50
+ de medición ni realiza deduplicación entre proveedores y etiquetas configuradas
51
+ externamente. El administrador de GTM puede ejecutar scripts con acceso a la página:
52
+ otorgar acceso solo a personas de confianza y revisar cada publicación.
53
+ El aviso de cookies informativo de Bacano no es un CMP y no autoriza las etiquetas;
54
+ el responsable del contenedor debe configurar el consentimiento aplicable.
55
+
56
+ CSP: permitir `https://www.googletagmanager.com` en `script-src`. Los destinos
57
+ adicionales y Tag Assistant requieren revisar sus propios permisos de CSP; no
58
+ habilitar comodines ni `unsafe-eval` globalmente para acomodar un contenedor.
59
+
60
+ Referencias: [configuración de GTM](https://support.google.com/tagmanager/answer/14842164)
61
+ y [contrato dataLayer](https://developers.google.com/tag-platform/tag-manager/datalayer).
62
+
63
+ ### Eventos comunes
64
+
9
65
  El storefront expresa hechos mediante `useMarketing().track()`. El SDK decide
10
- si la medición está activa, sanea la URL y adapta el evento a GA4, Meta y
11
- Microsoft Clarity. Nunca
66
+ si la medición está activa, sanea la URL y adapta el evento a GA4, Meta,
67
+ Microsoft Clarity y, si se configuró, GTM. Nunca
12
68
  se debe llamar directamente a `gtag`, `dataLayer`, `fbq`, Measurement Protocol
13
69
  o Conversions API.
14
70
  Clarity también se carga desde este runtime; no se instala su snippet de forma
@@ -120,8 +176,6 @@ Valores de `contactPlacement`:
120
176
  - `header`
121
177
  - `footer`
122
178
  - `contact_page`
123
- - `checkout`
124
- - `other` únicamente cuando ninguna ubicación canónica describe el contacto
125
179
 
126
180
  El campo es opcional, no acepta textos visibles ni valores libres y el runtime
127
181
  lo ignora cuando el evento no es `contact`. Una ubicación nueva debe añadirse
@@ -276,9 +330,9 @@ Antes de declarar un storefront listo:
276
330
  ## Checklist corto para agentes
277
331
 
278
332
  - [ ] Leí este contrato antes de instrumentar.
279
- - [ ] Uso únicamente `useMarketing().track()`.
333
+ - [ ] Uso el runtime oficial mediante `track`, `useBacanoCta` y los formularios oficiales.
280
334
  - [ ] Uso `product_variant_id` como `itemId`.
281
- - [ ] Emito eventos después del éxito, no antes.
335
+ - [ ] Cada evento representa su hecho: un intento no se presenta como éxito.
282
336
  - [ ] Instrumenté todos los contactos con método y ubicación.
283
337
  - [ ] Los contactos de producto incluyen item, cantidad y valor.
284
338
  - [ ] No emito conversiones autoritativas desde el navegador.
@@ -289,3 +343,104 @@ Antes de declarar un storefront listo:
289
343
  La guía de gobierno, persistencia y eventos autoritativos vive en
290
344
  `docs/websites/MARKETING_MEASUREMENT_STOREFRONTS_CHECKLIST.md` dentro del
291
345
  repositorio Bacano. Este archivo es el contrato distribuible para storefronts.
346
+
347
+ ## Interacciones y formularios — SDK 1.2.0
348
+
349
+ Aplicable también a webs informativas y de servicios. No exige checkout ni
350
+ configurar un proveedor ausente. Esta versión agrega instrumentación; no crea
351
+ un dashboard de embudos dentro de Bacano ni publica configuraciones remotas.
352
+
353
+ | Evento Bacano | GA4 | Meta | Clarity | Propietario y condición |
354
+ | --- | --- | --- | --- | --- |
355
+ | `cta_click` | `cta_click` | personalizado `cta_click` | `cta_click` | CTA pulsado, no hover |
356
+ | `form_open` | `form_open` | personalizado `form_open` | `form_open` | Formulario pasa a estar presentado; no implica inicio |
357
+ | `form_start` | `form_start` | personalizado `form_start` | `form_start` | Primera respuesta introducida/seleccionada por la persona |
358
+ | `form_step_complete` | `form_step_complete` | personalizado `form_step_complete` | `form_step_complete` | Paso validado y avance, una vez por paso/diligenciamiento |
359
+ | `form_submit_attempt` | `form_submit_attempt` | personalizado `form_submit_attempt` | `form_submit_attempt` | Intento de envío final, incluso si la validación lo rechaza |
360
+ | `form_submit_error` | `form_submit_error` | personalizado `form_submit_error` | `form_submit_error` | Fallo de ese intento; categoría segura |
361
+ | `form_submit_success` | `form_submit_success` | personalizado `form_submit_success` | `form_submit_success` | Resultado oficial `accepted: true` y UUID de respuesta |
362
+
363
+ GA4 y Meta reciben solamente `form_key`, `cta_id`, `placement`, `step_key`
364
+ cuando corresponden y `error_category` para errores. Los identificadores son
365
+ técnicos, estables, 1–64 caracteres, patrón `[a-z][a-z0-9_-]*`; no labels,
366
+ respuestas, emails ni teléfonos. `cta_click` exige `ctaId`; los eventos de
367
+ formulario exigen `formKey`; completar un paso exige `stepKey`. Categorías:
368
+ `validation`, `network`, `rejected`, `unavailable`. Parámetros inválidos
369
+ rechazan el evento completo. Clarity recibe solo el nombre, no esos parámetros.
370
+ GA4 recibe además URL saneada, `event_id`, destino explícito y debug según
371
+ configuración. Meta recibe la misma identidad mediante `eventID`, dirigida
372
+ solo al píxel configurado, no a todos los píxeles de la página.
373
+
374
+ `BacanoForm` instrumenta apertura, primera edición, pasos, intento y resultado.
375
+ Un formulario montado dentro de un contenedor oculto necesita `visible={open}`;
376
+ no se intenta adivinar CSS o extraer textos del DOM. Siempre visible significa
377
+ presentado en la página, no una impresión garantizada dentro del viewport.
378
+ Los cambios programáticos de `values` no cuentan como primera edición.
379
+ Un renderer personalizado usa `useBacanoFormTracking` y conserva su propia UI.
380
+ Los CTA usan `useBacanoCta`; no instrumentar el mismo clic también con `track`.
381
+ Ver [ejemplos y migración](./skills/bacano-web/references/interactions.md).
382
+
383
+ ### Persistencia, antispam y conversiones
384
+
385
+ `accepted: true, responseId: null` conserva el mensaje genérico de aceptación,
386
+ pero **no** emite éxito. No revelar el motivo al visitante. Un `onSubmit`
387
+ personalizado que devuelve `void` conserva su comportamiento visual, pero no
388
+ demuestra persistencia para medición; devolver el resultado de
389
+ `client.forms.submitResponse()` cuando se usa ese flujo.
390
+
391
+ Una respuesta guardada no prueba que se haya creado un lead nuevo. Esta
392
+ integración **no emite `generate_lead` ni `Lead`**, tampoco para `CAPTURE_LEAD`:
393
+ la resolución de identidad pertenece al backend y su resultado no forma parte
394
+ del contrato público. Una futura conversión autoritativa debe definirse ahí,
395
+ con identidad compartida si se envía también por navegador; no inferirla de
396
+ este evento de interacción. No duplicar la captura del lead por campaña.
397
+
398
+ ### Deduplicación y atribución
399
+
400
+ - El runtime descarta repeticiones de `(eventName, eventId)` entre sus últimas
401
+ 1.000 identidades. No es una garantía entre recargas ni un acuse del proveedor.
402
+ - CTA: el helper agrupa doble clic del mismo botón dentro de 400 ms, sin
403
+ impedir su acción. Un clic posterior es legítimo y recibe otra identidad.
404
+ - Cerrar/reabrir genera otra apertura; no otro inicio mientras el formulario
405
+ permanezca montado. Desmontar/montar inicia otro diligenciamiento. Un render
406
+ o la repetición de efectos de Strict Mode no equivalen a reabrir.
407
+ - Un envío pendiente no acepta otro simultáneo. Un reintento tras error genera
408
+ otro intento analítico, pero conserva la `idempotencyKey` de persistencia.
409
+ Éxito usa el UUID de respuesta para no duplicarlo dentro del runtime.
410
+ - Se reutiliza la atribución existente: `utm_content` se conserva como
411
+ `content`, junto a las demás UTM. Cada interacción recaptura la ubicación
412
+ usando ese mismo almacenamiento; navegación sin UTM no borra el origen.
413
+ No se copian click IDs de un proveedor a parámetros personalizados de otro.
414
+ - Las respuestas conservan atribución en Bacano; CTA/aperturas se envían a los
415
+ proveedores, no se guardan como una secuencia propia en Bacano. No prometer
416
+ seguimiento completo entre dispositivos, navegadores o bloqueadores.
417
+
418
+ GA4 puede medir formularios automáticamente. Al adoptar este contrato, revisar
419
+ y desactivar **Form interactions** de Enhanced Measurement para que `form_start`
420
+ no tenga dos propietarios. El SDK no cambia esa configuración de la cuenta.
421
+ No tratar el `form_submit` automático como evidencia de guardado.
422
+ [Referencia oficial de GA4](https://support.google.com/analytics/answer/9216061?hl=en).
423
+
424
+ ### Privacidad y diagnóstico
425
+
426
+ El único `BacanoMarketingProvider` acepta `measurementAllowed={false}` cuando
427
+ el gestor de consentimiento del sitio todavía no permite medir. No carga
428
+ scripts, no captura atribución nueva ni emite eventos en ese estado. Este
429
+ interruptor no sustituye el gestor de consentimiento, no borra almacenamiento
430
+ previo ni descarga scripts de terceros que ya estaban cargados. Tampoco
431
+ autoriza publicidad por el hecho de aceptar términos de compra.
432
+
433
+ Config desactivada, dominio distinto, preview o proveedores ausentes son no-op.
434
+ Diagnósticos: `MARKETING_DISABLED`, `MEASUREMENT_NOT_ALLOWED`,
435
+ `DOMAIN_NOT_ALLOWED`, `PROVIDER_NOT_CONFIGURED`, `PREVIEW_DISABLED`,
436
+ `PUBLIC_CONFIG_UNAVAILABLE`, `INVALID_INTERACTION`, `INVALID_EVENT`,
437
+ `SCRIPT_LOAD_FAILED`, `EVENT_DISPATCH_FAILED`, `EVENT_DISPATCHED`.
438
+ Un fallo de descarga no permite distinguir por sí solo bloqueador, CSP o red.
439
+ `EVENT_DISPATCHED` significa únicamente pasado al adaptador; no recepción
440
+ externa. Ni un callback de diagnóstico que falle puede bloquear el formulario.
441
+
442
+ No incluir PII en rutas ni en valores UTM: sanear una URL no identifica toda la
443
+ información personal que el sitio pudiera introducir en su ruta. No evadir
444
+ Core Setup/Protected Data Mode o consentimiento mediante campos alternativos.
445
+ La coherencia entre píxel y CAPI se revisa del lado Bacano; no exponer tokens
446
+ ni inventar un segundo destino público para intentar corregirla en el sitio.