GTM — Sign Up Fake Product PDP (Customer Guest)
Script que transforma la PDP de un producto no disponible para su compra en un punto de captación de leads. Elimina el botón original "Add to Cart" y el mensaje de fecha de llegada, y los sustituye por un botón que despliega un formulario de suscripción inline. Al registrarse correctamente, envía un evento sign_up al dataLayer de GTM.
Variables GTM
| Variable GTM | Descripción |
|---|---|
{{fake-product-button-let-me-know}} | Texto del botón que reemplaza al "Add to Cart". |
{{fake-product-form-intro-guest}} | Texto introductorio que aparece dentro del panel del formulario. |
{{fake-product-message-success-guest}} | Mensaje de éxito que se muestra tras el registro correcto. |
{{popup-url}} | URL del endpoint al que se envía el formulario. |
{{popup-introduce-email}} | Placeholder del campo email. |
{{popup-accept-legal}} | Texto de la cláusula legal (prefijo del enlace). |
{{privacy-policyURL}} | URL de la política de privacidad. |
{{popup-privacy-policy}} | Texto del enlace a la política de privacidad. |
{{popup-button-submit}} | Texto del botón de envío del formulario. |
{{popup-url}}, {{popup-introduce-email}}, {{popup-accept-legal}}, {{privacy-policyURL}}, {{popup-privacy-policy}} y {{popup-button-submit}} son las mismas variables que usa el script Popup Fast Sign Up. Se pueden reutilizar si los valores coinciden.
Elementos que se eliminan del DOM
Antes de inyectar el contenido propio, el script elimina dos elementos del DOM original:
| Selector | Qué es | Por qué se elimina |
|---|---|---|
.js-button-add-to-cart | Botón original de añadir al carrito | Se reemplaza por el botón fake |
.js-arrival-date-message | Mensaje de fecha estimada de llegada | No es relevante para un producto fake |
El padre del botón original recibe la clase gtm-html-fake-button-parent (flex-wrap: wrap) para que el botón fake y el panel del formulario se apilen correctamente.
Flujo de interacción
La experiencia tiene dos pasos:
- Botón fake visible — reemplaza visualmente al "Add to Cart" (fondo gris
#969696). Al hacer clic, muestra un estado de carga durante 500ms. - Panel del formulario — se abre tras esos 500ms. Contiene email + checkbox legal + botón de envío.
[Botón fake] → click → is-loading (500ms) → panel abre (is-opened)
[Panel] → submit → XHR POST → éxito / error
Estados del componente
- Botón fake
- Panel formulario
| Clase | Cuándo se aplica | Efecto visual |
|---|---|---|
| (ninguna) | Estado inicial | Botón gris #969696 activo. |
is-loading | Al hacer click (durante 500ms) | cursor: not-allowed, oculta el texto, muestra spinner SVG. |
| Clase | Elemento | Cuándo se aplica | Efecto |
|---|---|---|---|
is-opened | .gtm-html-fake-button-content | Tras los 500ms del botón | display: block — panel visible. |
is-loading | form | Al enviar el formulario | Oculta texto del botón de envío, muestra spinner. |
has-error | form | Si la API devuelve success: false | Muestra mensaje de error (fondo rojo #f22248). |
has-success | .gtm-html-fake-product__success | Si la API devuelve success: true | Muestra mensaje de éxito. El <form> se elimina del DOM. |
Clases CSS
- Visuales (gtm-html-*)
- Selectores JS (gtm-js-*)
| Clase | Elemento | Descripción |
|---|---|---|
gtm-html-fake-button-parent | Padre del botón original | flex-wrap: wrap — permite apilar botón fake + panel. |
gtm-html-fake-button-add-to-cart | button fake | Botón gris #969696, ancho 100%, negro al hover. |
gtm-html-fake-button-add-to-cart__text | span dentro del botón | Texto visible del botón; se oculta con is-loading. |
gtm-html-fake-button-content | div panel | Oculto por defecto (display: none); visible con is-opened. border: 1px solid #969696. |
gtm-html-fake-product-form__input | input[email] | Ancho 100%, fondo #f9f9f9, font-size: 14px. |
gtm-html-fake-product-form__button | button[submit] | Fondo negro, texto blanco, ancho 100%. |
gtm-html-fake-product-form__button-text | span del botón | Texto del envío; se oculta con is-loading en el form. |
gtm-html-fake-product-form__legal-wrapper | div | Fila checkbox + texto. align-items: baseline. |
gtm-html-fake-product-form__legal-text | label | Texto legal con enlace subrayado. font-size: 14px. |
gtm-html-button-loader | svg spinner | Compartido por botón fake y botón de envío. Animación gtm-spin. |
gtm-html-fake-product__error | p | Oculto por defecto; visible con has-error en el form. Fondo rojo #f22248. |
gtm-html-fake-product__success | p | Oculto por defecto; visible con has-success. |
| Clase | Elemento | Descripción |
|---|---|---|
gtm-js-fake-button-add-to-cart | button fake | Referenciado para añadir el listener de click. |
gtm-js-fake-product-form | form | Referenciado para el listener de submit y gestión de estados. |
Campos del formulario
Atributo name | Tipo | Descripción |
|---|---|---|
emailPopupFastSignUp | email | Email del usuario. Enviado en el body del POST como email=.... |
fakeProductSignUpLegal | checkbox | Aceptación de la política de privacidad. Solo se valida localmente. |
El campo email usa el mismo name (emailPopupFastSignUp) que el script Popup Fast Sign Up. El checkbox usa un name propio (fakeProductSignUpLegal).
Respuesta de la API
El XHR espera la misma estructura JSON que el Popup Fast Sign Up:
{
"success": true,
"message": "¡Gracias por suscribirte!",
"hashedEmail": "5f4dcc3b5aa765d61d8327deb882cf99"
}
Evento GTM
Al registrarse correctamente se hace un push al dataLayer:
{
event: "sign_up",
method: "web",
place: "fake_product", // diferente de "popup"
email: hashedEmail // email hasheado, nunca en claro
}
Diferencias respecto a Popup Fast Sign Up
| Aspecto | Popup Fast Sign Up | Sign Up Fake Product |
|---|---|---|
| Posición en pantalla | fixed, esquina inferior derecha | Inline en la PDP, parte del flujo de página |
| Disparador | Se abre automáticamente al cargar | Clic del usuario en el botón fake |
| Animación de apertura | Slide-up con translateY | Panel con display: none → block tras 500ms |
| Elementos eliminados | Ninguno | .js-button-add-to-cart + .js-arrival-date-message |
| Cierre automático | Sí, 3000ms tras el éxito | No — el formulario se elimina y queda el mensaje |
place en evento GTM | "popup" | "fake_product" |
| Nombre del checkbox | legalPopupFastSignUp | fakeProductSignUpLegal |
Flujo de ejecución
fnGtmSignUpFakeProductInit() ← llamada directa al cargar el tag
│
├─ fnGtmSignUpFakeProductToPreInitElements()
│ ├─ Busca .js-button-add-to-cart → lo elimina del DOM
│ ├─ Guarda su parentElement como addToCartButtonParent
│ ├─ Añade gtm-html-fake-button-parent al parentElement
│ └─ Busca .js-arrival-date-message → lo elimina del DOM
│
├─ fnGtmSignUpFakeProductToInjectCode()
│ ├─ Crea button.gtm-html-fake-button-add-to-cart con texto + spinner
│ ├─ Crea div.gtm-html-fake-button-content con form + success
│ └─ Appenda ambos al addToCartButtonParent
│
├─ fnGtmSignUpFakeProductToInitElements()
│ └─ Recupera todos los nodos via selectores gtm-js-* y gtm-html-*
│
└─ fnGtmSignUpFakeProductToListenEvents()
│
├─ Botón fake → click → fnGtmSignUpFakeProductToShowForm()
│ ├─ Añade is-loading al botón fake
│ └─ setTimeout(500ms):
│ ├─ Añade is-opened al panel (form visible)
│ └─ Quita is-loading del botón fake
│
└─ Form → submit → fnGtmSignUpFakeProductToHandleSubmitForm(event)
├─ event.preventDefault()
├─ fnGtmSignUpFakeProductToValidateForm() → {url, email, isValid}
│ ├─ URL vacía → error (console)
│ ├─ Email vacío → error (console)
│ └─ Legal no marcado → error (console)
├─ fnGtmSignUpFakeProductToStartLoadingForm()
│ └─ Añade is-loading al form, quita has-error
├─ Si isValid: XHR POST a url con email=...
│ └─ readyState 4 + status 200:
│ ├─ success: true → fnGtmSignUpFakeProductToSetSuccess(hashedEmail)
│ │ ├─ Elimina el <form> del DOM
│ │ ├─ Añade has-success a .gtm-html-fake-product__success
│ │ └─ fnGtmSignUpFakeProductToLaunchGtmEvent(hashedEmail)
│ │ └─ dataLayer.push({ event: "sign_up", place: "fake_product", ... })
│ └─ success: false → fnGtmSignUpFakeProductToSetError(message)
│ ├─ Escribe message en .gtm-html-fake-product__error
│ └─ Añade has-error al form
└─ fnGtmSignUpFakeProductToStopLoadingForm()
└─ Quita is-loading del form