GTM — Popup Fast Sign Up
Script que añade dinámicamente un popup de suscripción por email en la esquina inferior derecha de la página. Incluye formulario con email + checkbox legal, validación, envío vía XHR, y gestión visual de los estados de carga, error y éxito. Al registrarse correctamente envía un evento sign_up al dataLayer de GTM.
Variables GTM
| Variable GTM | Descripción |
|---|---|
{{popup-title}} | Título secundario grande (amarillo, uppercase). Se muestra bajo el texto fijo "JOIN OUR". |
{{popup-text-content}} | Descripción del popup. |
{{popup-url}} | URL del endpoint al que se envía el formulario (atributo action). |
{{popup-introduce-email}} | Placeholder del campo email. |
{{popup-accept-legal}} | Texto de la cláusula legal (prefijo del enlace a política de privacidad). |
{{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. |
Texto fijo
El texto "JOIN OUR" es estático en el código — no proviene de ninguna variable GTM.
Estados del popup
El popup usa clases CSS en .gtm-html-popup para gestionar todos los estados visuales:
| Clase | Cuándo se aplica | Efecto visual |
|---|---|---|
| (ninguna) | Inicial (recién creado) | Oculto, fuera de pantalla (translateY(calc(100% + 16px))). |
is-visible | 100ms tras la creación | Slide-up: transform: translateY(0). |
is-loading | Al enviar el formulario | Muestra spinner SVG, oculta texto del botón. |
has-error | Si la API devuelve success: false | Muestra el mensaje de error (fondo rojo #f22248). |
has-success | Si la API devuelve success: true | Fondo verde (#18b284), oculta form y títulos, muestra mensaje de éxito + icono check. Cierra automáticamente a los 3s. |
Respuesta de la API
El XHR espera un JSON con esta estructura:
{
"success": true,
"message": "¡Gracias por suscribirte!",
"hashedEmail": "5f4dcc3b5aa765d61d8327deb882cf99"
}
| Campo | Tipo | Descripción |
|---|---|---|
success | boolean | true → estado de éxito. false → estado de error. |
message | string | Texto que se muestra al usuario en éxito o error. |
hashedEmail | string | Email hasheado que se empuja al dataLayer (nunca el email en claro). |
Evento GTM
Al registrarse correctamente se hace un push al dataLayer:
{
event: "sign_up",
method: "web",
place: "popup",
email: hashedEmail // email hasheado, no en claro
}
Clases CSS
El script separa clases visuales (gtm-html-*) de selectores JS (gtm-js-*):
- Visuales (gtm-html-*)
- Selectores JS (gtm-js-*)
| Clase | Elemento | Descripción |
|---|---|---|
gtm-html-popup | div raíz | Contenedor del popup. Posición fixed, fondo rgba(0,0,0,0.85), 415px escritorio / 90% móvil. |
gtm-html-popup__title | p | Texto superior "JOIN OUR". 16px, amarillo #c7ff06. |
gtm-html-popup__secondary-title | p | Título principal. 36px/24px móvil, amarillo #c7ff06. |
gtm-html-popup-description | p | Descripción. 1rem, blanco. |
gtm-html-popup__button-close | div | Botón ×. Posición absoluta top-right. |
gtm-html-popup__form | form | Formulario de suscripción. |
gtm-html-popup__input-email | input | Campo email. Fondo gris #e7e7e7. |
gtm-html-popup__legal-wrapper | div | Fila checkbox + texto legal. |
gtm-html-popup__button-submit | button | Botón enviar. Fondo amarillo #c7ff06, negro, 18px/16px móvil. |
gtm-html-popup__button-loader | svg | Spinner. Visible solo con is-loading. Animación spin. |
gtm-html-popup__error | p | Error genérico. Visible solo con has-error. Fondo rojo #f22248. |
gtm-html-popup__success | div | Mensaje de éxito + icono check. Visible solo con has-success. |
| Clase | Elemento | Descripción |
|---|---|---|
gtm-js-popup__input-email | input | Campo email — referenciado en validación y envío. |
gtm-js-popup__input-legal | input[checkbox] | Checkbox legal — su .checked se valida antes del envío. |
gtm-js-popup__error-generic | p | Contenedor del mensaje de error. |
gtm-js-popup__success-text | p | Contenedor del mensaje de éxito. |
gtm-js-popup__form | form | Formulario — al que se añade el listener submit. |
Campos del formulario
Atributo name | Tipo | Descripción |
|---|---|---|
emailPopupFastSignUp | email | Email del usuario. Enviado en el body del POST como email=.... |
legalPopupFastSignUp | checkbox | Aceptación de la política de privacidad. Solo se valida localmente (no se envía al servidor). |
Flujo de ejecución
initPopup()
│
├─ injectCode()
│ ├─ Crea div.gtm-html-popup con htmlCodePopup() como innerHTML
│ ├─ Lo añade a document.body
│ └─ setTimeout(100ms) → añade is-visible → slide-up
│
├─ initElements()
│ └─ Referencia todos los elementos del popup vía gtm-js-* selectors
│
└─ listenEvents()
├─ Botón × → click → closePopup()
│ ├─ Quita is-visible (slide-down)
│ └─ setTimeout(600ms) → remove() del DOM
│
└─ Form → submit → handleSubmitForm(event)
├─ event.preventDefault()
├─ validateForm() → {url, email, isValid}
│ ├─ URL vacía → error
│ ├─ Email vacío → error
│ └─ Legal no marcado → error
├─ startLoading() → añade is-loading, quita has-error
├─ Si isValid: XHR POST a url con email=...
│ └─ readyState 4 + status 200:
│ ├─ success: true → setSuccess(message, hashedEmail)
│ │ ├─ Escribe message en gtm-js-popup__success-text
│ │ ├─ Añade has-success al wrapper
│ │ ├─ launchGtmEvent(hashedEmail) → dataLayer.push(sign_up)
│ │ └─ setTimeout(3000ms) → closePopup()
│ └─ success: false → setError(element, message)
│ ├─ Escribe message en gtm-js-popup__error-generic
│ └─ Añade has-error al wrapper
└─ stopLoading() → quita is-loading
Responsive
| Propiedad | Escritorio | Móvil (≤768px) |
|---|---|---|
| Ancho | 415px | 90% (centrado, left: 5%, right: 5%) |
| Título secundario | 36px | 24px |
| Título principal | 16px | 14px |
| Botón submit | 18px, padding: 16px | 16px, padding: 12px |