Skip to main content

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 GTMDescripció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:

ClaseCuándo se aplicaEfecto visual
(ninguna)Inicial (recién creado)Oculto, fuera de pantalla (translateY(calc(100% + 16px))).
is-visible100ms tras la creaciónSlide-up: transform: translateY(0).
is-loadingAl enviar el formularioMuestra spinner SVG, oculta texto del botón.
has-errorSi la API devuelve success: falseMuestra el mensaje de error (fondo rojo #f22248).
has-successSi la API devuelve success: trueFondo 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"
}
CampoTipoDescripción
successbooleantrue → estado de éxito. false → estado de error.
messagestringTexto que se muestra al usuario en éxito o error.
hashedEmailstringEmail 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-*):

ClaseElementoDescripción
gtm-html-popupdiv raízContenedor del popup. Posición fixed, fondo rgba(0,0,0,0.85), 415px escritorio / 90% móvil.
gtm-html-popup__titlepTexto superior "JOIN OUR". 16px, amarillo #c7ff06.
gtm-html-popup__secondary-titlepTítulo principal. 36px/24px móvil, amarillo #c7ff06.
gtm-html-popup-descriptionpDescripción. 1rem, blanco.
gtm-html-popup__button-closedivBotón ×. Posición absoluta top-right.
gtm-html-popup__formformFormulario de suscripción.
gtm-html-popup__input-emailinputCampo email. Fondo gris #e7e7e7.
gtm-html-popup__legal-wrapperdivFila checkbox + texto legal.
gtm-html-popup__button-submitbuttonBotón enviar. Fondo amarillo #c7ff06, negro, 18px/16px móvil.
gtm-html-popup__button-loadersvgSpinner. Visible solo con is-loading. Animación spin.
gtm-html-popup__errorpError genérico. Visible solo con has-error. Fondo rojo #f22248.
gtm-html-popup__successdivMensaje de éxito + icono check. Visible solo con has-success.

Campos del formulario

Atributo nameTipoDescripción
emailPopupFastSignUpemailEmail del usuario. Enviado en el body del POST como email=....
legalPopupFastSignUpcheckboxAceptació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

PropiedadEscritorioMóvil (≤768px)
Ancho415px90% (centrado, left: 5%, right: 5%)
Título secundario36px24px
Título principal16px14px
Botón submit18px, padding: 16px16px, padding: 12px