Guía de migración · Versión 04.26
Configuración multiidioma para Klaviyo
Esta guía te muestra cómo usar la función de traducción de Klaviyo para asegurarte de que tus usuarios reciben emails en el idioma correcto. Para que sea más fácil de seguir, esta guía asume que el alemán es el idioma principal de la tienda y que el inglés se añade como segundo idioma.
1. Contexto
En julio de 2025, Klaviyo lanzó una función de traducción que permite traducir emails directamente dentro de Klaviyo. Igual que con las traducciones en Shopify, primero creas tu email en un idioma y después lo traduces.
Cuando se envía el email, Klaviyo determina qué versión de idioma debe mostrarse según el idioma seleccionado en el perfil.
Core benefits
- Hay traducciones con IA disponibles.
- Pasas menos tiempo creando emails duplicados.
- Reduces el riesgo de enviar emails en el idioma equivocado.
2. Configuración de la función de traducción
2.1 Configuración básica
Para utilizar la función de traducción, ve a Configuración → Traducción en Klaviyo y actívala.
A continuación, elige qué propiedad debe utilizar Klaviyo para determinar el idioma. Utiliza la locale proporcionada por Shopify.
La locale de Shopify se divide automáticamente en idioma y país dentro de Klaviyo, lo que facilita la segmentación y la gestión de flujos y campañas.
- Locale
- Locale: País
- Locale: Idioma
Después de seleccionar la locale, define los idiomas que quieres soportar y establece un idioma predeterminado. Si la mayoría de tus usuarios habla alemán, puedes usar alemán como idioma por defecto. Si tu audiencia es más internacional, el inglés suele ser la mejor opción.
2.2 Migrar perfiles existentes
Si ya llevas tiempo usando Klaviyo, el siguiente paso es asegurarte de que todos tus perfiles activos existentes tengan un locale definido.
Primero, crea un segmento con:
- Propiedades de una persona → Locale = Not Set
- Y: La persona puede recibir email marketing
Después, reduce a 0 el número de perfiles sin locale siguiendo los pasos de abajo.
01 Resincronizar Shopify
Ve a la integración de Shopify en Klaviyo y vuelve a importar tus contactos. Esto permitirá enriquecer perfiles antiguos donde el locale no se había enviado anteriormente.
02 Usar propiedades de idioma antiguas
Si anteriormente guardabas el idioma de tus clientes en otra propiedad personalizada, utiliza tu segmento “Locale = Not Set” como trigger de un flujo.
- Añade un split condicional basado en tu propiedad de idioma antigua.
- Dirige a los usuarios según su idioma (DE, EN, ES, FR, etc.) a diferentes ramas.
- Utiliza una acción de “Update Profile Property” y asigna correctamente el valor de $locale (de, en, es, fr, etc.).
- Pon el flujo en Live y usa “Add past profiles” en el trigger para que también entren los perfiles existentes.
03 Usar asignaciones de listas
Si todavía quedan usuarios en el segmento “Locale = Not Set”, utiliza sus pertenencias a listas para categorizarlos, por ejemplo si antes separabas usuarios por idioma en diferentes listas.
Aplica la misma lógica de flujo: usa el segmento como trigger, haz un split por lista y luego actualiza el locale.
04 Asignar un valor por defecto
Si ya has agotado todas las opciones y aún quedan perfiles sin locale, asigna un valor por defecto (por ejemplo, inglés).
Objetivo
Objetivo: tu segmento “Locale = Not Set” debería estar en 0.
2.3 Etiquetar nuevos perfiles
Una vez migrados los datos históricos, asegúrate de que los nuevos perfiles reciban automáticamente una locale.
Los nuevos perfiles normalmente se crean a través de:
- Formularios de Klaviyo o scripts onsite
- Registros de Back in Stock
- Checkout de Shopify
- Formularios de newsletter de Shopify
- Herramientas externas como Typeform, apps de quiz o herramientas de consulta
2.3.1 Script onsite de Klaviyo
Si un visitante navega por tu tienda pero no inicia el checkout, Klaviyo puede no saber qué idioma o país ha utilizado. Añade este snippet en tu theme.liquid antes de la etiqueta de cierre </body>:
<!-- Start Klaviyo MultiLanguage -->
<script>
klaviyo.identify({
{% if customer.email %}
'$email': '{{ customer.email }}',
{% endif %}
'$locale': '{{ request.locale.iso_code }}-{{ localization.country.iso_code }}'
});
</script>
<!-- End Klaviyo MultiLanguage -->
Esto garantiza que tanto el idioma como el país se sincronicen automáticamente con Klaviyo en todo momento. Cada vez que se crea un nuevo perfil —ya sea a través de un formulario de Klaviyo o un registro de Back in Stock— la locale correcta se envía al instante.
Al mismo tiempo, cualquier cambio que se realice más adelante en tu tienda (por ejemplo, si un cliente cambia el idioma o estaba mal asignado) se refleja automáticamente en Klaviyo, manteniendo todos los perfiles actualizados y correctos.
2.3.2 Herramientas externas / apps
Las herramientas externas son un poco más complejas, pero normalmente ya requieren un sistema claro para mapear los distintos idiomas. Una vez definido este sistema, puedes utilizarlo para asignar la locale correcta en Klaviyo de forma consistente, ya sea directamente mediante un paso de “Update Profile Property” o de forma indirecta a través de Shopify Flow, incluso de manera retroactiva para perfiles existentes.
3. Configuración de formularios de suscripción
Para garantizar una experiencia de idioma coherente en tus formularios (registro y Back in Stock) y en los correos de doble opt-in —lo que impacta directamente en la tasa de confirmación— necesitas una pequeña pero importante configuración.
Empieza creando una lista separada para cada idioma. Por ejemplo:
- Newsletter DE
- Newsletter EN
- Newsletter ES
Para cada lista, adapta el correo de doble opt-in al idioma correspondiente. Si el correo de confirmación se envía en el idioma incorrecto, puede reducir significativamente tu tasa de suscripción.
Puedes ignorar otras páginas relacionadas con listas, como las páginas de preferencias o de baja, ya que Klaviyo generalmente utiliza tus configuraciones predeterminadas al enviar campañas o flujos.
3.1 Configuración de formularios de Klaviyo
Al utilizar formularios de Klaviyo, debes asegurarte de que los visitantes siempre vean el formulario de registro en el idioma correcto, para evitar que, por ejemplo, un formulario en alemán aparezca en la versión en inglés de tu tienda.
Si utilizas Shopify Markets, Shopify estructura automáticamente tus URLs por locale (por ejemplo, /en_DE o /fr_FR). Estos patrones de URL pueden utilizarse para controlar qué formulario se muestra a cada usuario.
Esto te permite mostrar el formulario correcto según el idioma (y, si aplica, el país).
Ejemplo
Para la versión en inglés de tu tienda, las URLs pueden contener /en (por ejemplo, tudomain.com/en_DE). Aquí, 'en' representa el idioma y 'DE' el país. Utiliza esta información para crear tu formulario de registro:
01 1. Crear tu formulario
Crea tu formulario de registro en el idioma deseado (por ejemplo, empieza con la versión en inglés).
02 2. Configurar el targeting
En el editor de formularios, ve a Targeting → Targeting y configura el formulario para que solo se muestre en páginas que contengan tudomain.com/en.
03 3. Configurar el comportamiento de envío
Configura lo siguiente para el botón de envío en el idioma inglés:
- Añade los suscriptores a tu lista de newsletter en inglés (para el email de doble opt-in).
- Añade un campo personalizado oculto con Locale = en
04 4. Duplicar para otros idiomas
Una vez que tu formulario en inglés esté configurado, duplícalo y adáptalo para otros idiomas.
- Actualiza todos los textos al idioma correspondiente.
- Asegúrate de mostrarlo solo en páginas con el identificador de idioma adecuado.
- Conecta el formulario con la lista de newsletter correspondiente.
- Actualiza el campo oculto de locale (por ejemplo, 'fr').
- Repite esto para todos los idiomas
Importante: Tu idioma por defecto
Para tu idioma por defecto no tendrás un identificador en la URL. En este caso, procede de la siguiente manera:
- Actualiza todos los textos al idioma por defecto.
- Ve a Targeting → Targeting y selecciona 'Don't show on' en URLs que contengan tus otros idiomas (por ejemplo, tudomain.com/en, tudomain.com/fr, etc.).
- Conecta el formulario con la lista de newsletter del idioma por defecto.
- Actualiza el campo oculto de locale al idioma por defecto (por ejemplo, 'es').
3.2 Configuración de Back in Stock
Si utilizas el snippet estándar de Back in Stock de Klaviyo para añadir una función de notificación en productos agotados, te enfrentarás a tres desafíos al configurar un sistema multilingüe:
- ¿Cómo aseguras que el formulario de Back in Stock se muestre en el idioma correcto?
- ¿Cómo se transfiere el locale del usuario a su perfil en Klaviyo?
- ¿Y cómo envías el email de doble opt-in en el idioma correcto si los usuarios también quieren suscribirse a la newsletter?
El locale se establece automáticamente cuando se crea un perfil mediante el script de la sección 2.3.1 (si está correctamente implementado).
Esto significa que solo necesitas centrarte en dos aspectos: las traducciones y la asignación a la lista correcta.
Sigue estos pasos para configurarlo:
01 1. Añadir el snippet de Back in Stock
Inserta el snippet de Back in Stock en tu archivo theme.liquid antes de la etiqueta de cierre </body> y define placeholders para todos los elementos que quieras traducir.
<script src="https://a.klaviyo.com/media/js/onsite/onsite.js"></script>
<script>
var klaviyo = klaviyo || [];
klaviyo.init({
account: "XXXXX",
list: "{{ 'general.back_in_stock.list' | t }}",
platform: "shopify"
});
klaviyo.enable("backinstock", {
trigger: {
product_page_text: "{{ 'general.back_in_stock.product_page_text' | t }}",
product_page_class: "button w-full",
product_page_text_align: "center",
product_page_margin: "10px 0px 0px 0px",
product_page_width: "100%",
replace_anchor: false
},
modal: {
headline: "{product_name}",
body_content: "{{ 'general.back_in_stock.body_content' | t }}",
email_field_label: "{{ 'general.back_in_stock.body_email_field_label' | t }}",
button_label: "{{ 'general.back_in_stock.button_label' | t }}",
subscription_success_label: "{{ 'general.back_in_stock.subscription_success_label' | t }}",
footer_content: "",
additional_styles: "@import url('https://fonts.googleapis.com/css?family=Inter+Neue');",
drop_background_color: "#000",
background_color: "#fff",
text_color: "#000",
button_text_color: "#fff",
button_background_color: "#000",
close_button_color: "#ccc",
error_background_color: "#fcd6d7",
error_text_color: "#C72E2F",
success_background_color: "#d3efcd",
success_text_color: "#1B9500",
newsletter_subscribe_label: "{{ 'general.back_in_stock.newsletter_subscribe_label' | t }}"
}
});
</script>
02 2. Sustituir tu ID de cuenta de Klaviyo
Sustituye 'XXXXX' por tu clave pública de API de Klaviyo. Puedes encontrarla en Settings → API Keys → Public API Key.
03 3. Añadir traducciones para el idioma por defecto
Ve a tu archivo de locale (por ejemplo, en.default.json) y añade el siguiente bloque de traducción dentro de la sección 'general':
"back_in_stock": {
"body_content": "Register to receive a notification when this item comes back in stock.",
"email_field_label": "Email",
"button_label": "Notify me when available",
"subscription_success_label": "You're in! We'll let you know when it's back.",
"product_page_text": "Notify Me When Available!",
"newsletter_subscribe_label": "Save 10% when signing up for our newsletter.",
"list": "ID of your English list"
},
Personaliza el ID de la lista y las traducciones según tus necesidades.
Debería verse similar a esto:
04 4. Añadir traducciones para otros idiomas
Repite este proceso para cada idioma y adapta tanto los textos como el ID de la lista. Por ejemplo, en tu archivo de.json:
"back_in_stock": {
"body_content": "Erhalte eine Benachrichtigung, sobald dieser Artikel wieder verfügbar ist",
"email_field_label": "E-Mail-Adresse",
"button_label": "Sag mir Bescheid, wenn der Artikel wieder da ist!",
"subscription_success_label": "Geschafft! Wir informieren dich, sobald der Artikel zurück ist.",
"product_page_text": "Sag mir Bescheid, wenn der Artikel wieder da ist!",
"newsletter_subscribe_label": "Werde Teil der Community und spare zusätzlich 10% auf deinen Erstkauf.",
"list": "ID deiner deutschen Liste"
},
05 5. Repetir para todos los idiomas
Asegúrate de que cada idioma tenga su propio conjunto de traducciones y esté conectado a la lista correcta.
3.3 Integración de Shopify y listas basadas en idioma
La buena noticia: Los nuevos perfiles desde Shopify (por ejemplo, a través del checkout o formularios del tema) envían automáticamente el idioma del cliente a Klaviyo.
El problema: Por defecto, Klaviyo solo puede añadir estos usuarios a una única lista — independientemente de su idioma.
Dado que el correo de doble opt-in está vinculado a esa lista, a menudo se envía en el idioma incorrecto.
La solución: Debes evitar la asignación automática de listas y definir tú mismo a qué lista se añade cada usuario según su idioma.
Sigue estos pasos para configurarlo:
01 1. Desactivar la asignación por defecto
Ve a la integración de Shopify en Klaviyo y desactiva la opción que añade automáticamente los perfiles a una lista.
02 2. Crear un Shopify Flow
En Shopify, crea un Shopify Flow que dirija a los nuevos suscriptores de email a diferentes listas según el idioma seleccionado en tu tienda.
03 3. Asignar perfiles según el idioma
Configura el flow para que los clientes que se suscriban al email marketing se añadan a la lista correcta de Klaviyo en función de su locale.
4. Páginas de baja y preferencias
Esto nos lleva a la pregunta de cómo ofrecer páginas de baja y preferencias en varios idiomas.
En Klaviyo, estas páginas se gestionan en dos lugares: en Settings → Other → Consent Pages y directamente en cada lista.
Las páginas específicas de listas solo funcionan si envías campañas a esas listas. Sin embargo, cuando envías a segmentos —que suele ser el enfoque recomendado— Klaviyo utiliza las páginas de consentimiento predeterminadas.
Sigue estos pasos para configurarlo:
01 1. Activar Hosted Pages
Ve a Settings → Other → Consent Pages y activa Hosted Pages en tu cuenta. Si tu cuenta es nueva, puede que primero tengas que esperar a que Klaviyo la verifique.
02 2. Abrir la pestaña “Hosted Pages”
Una vez activado, aparecerá una nueva pestaña llamada “Hosted Pages” en la navegación lateral.
03 3. Crear la página de baja
Crea una nueva página usando unsubscribe_page.tmpl y añade el HTML de tu página de baja.
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8" />
<title>Unsubscribe</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<style>
:root{
--page-bg:#f3f3f3; /* CHANGE ME */
--card-bg:#ffffff; /* CHANGE ME */
--text:#050505; /* CHANGE ME */
--soft:#f4f4f4; /* CHANGE ME */
--accent:#429991; /* CHANGE ME */
--accent-hover:#357f79; /* CHANGE ME */
}
*{box-sizing:border-box;}
body{
background:var(--page-bg);
color:var(--text);
font-family:'Assistant', Arial, Helvetica, sans-serif;
font-size:14px;
line-height:1.45;
}
.container{max-width:100%;}
.col-12.col-md-6.offset-md-3{
max-width:600px;
margin:32px auto !important;
background:var(--card-bg);
padding:54px 42px 44px;
}
.lang-row{
display:flex;
justify-content:center;
margin-bottom:22px;
}
.lang-bar{
display:inline-flex;
gap:6px;
background:#f4f4f4;
padding:5px;
border-radius:999px;
}
.lang-bar .btn{
border:0;
border-radius:999px;
background:transparent;
color:#555;
font-size:11px;
font-weight:800;
letter-spacing:.04em;
padding:6px 10px;
line-height:1;
}
.lang-bar .btn:hover,
.lang-bar .btn:focus,
.lang-bar .btn.is-active{
background:#111;
color:#fff;
}
.logo-wrap{
padding:0 0 18px;
text-align:center;
}
.logo-wrap img{
max-height:66px;
display:inline-block;
}
.heading{
text-align:center;
font-size:28px;
line-height:1.05;
font-family:'Playfair Display', serif;
font-weight:900;
letter-spacing:-.03em;
text-transform:none;
margin:8px 0 12px;
}
.subcopy{
color:#222;
text-align:center;
max-width:390px;
margin:0 auto 28px;
font-size:13px;
line-height:1.5;
}
.panel-card,
.success-card,
.card-like{
border:0;
border-radius:0;
padding:0;
}
.form-label,
h6{
font-size:13px;
font-weight:800;
color:#050505;
margin-bottom:7px;
}
.mb-3{
margin-bottom:22px !important;
}
.form-control{
border:1px solid #d8d8d8;
border-radius:0;
height:42px;
font-size:13px;
padding:9px 12px;
color:#111;
background-color:#fff;
}
.form-control:focus{
border-color:#111;
box-shadow:none;
}
.help-text{
background:var(--soft);
border-left:3px solid #111;
padding:12px 14px;
color:#333;
font-size:12px;
line-height:1.45;
margin:10px 0 14px;
}
#freqSection .form-check{
display:flex;
align-items:center;
gap:10px;
margin:0 0 4px;
padding-left:28px;
}
.form-check-input{
position:static;
margin:0;
width:15px;
height:15px;
border-radius:0;
border:1px solid #999;
flex-shrink:0;
}
.form-check-input:checked{
background-color:#111;
border-color:#111;
}
.form-check-label{
font-size:14px;
color:#111;
line-height:1.3;
}
.btn-pill{
border-radius:0;
}
.btn-cta{
width:100%;
padding:15px 20px;
font-size:13px;
font-weight:900;
text-transform:uppercase;
letter-spacing:.02em;
background:var(--accent);
color:#fff;
border:1px solid var(--accent);
}
.btn-cta:hover,
.btn-cta:focus{
background:var(--accent-hover);
border-color:var(--accent-hover);
color:#fff;
}
#unsubscribeLink{
color:var(--accent);
text-decoration:none;
font-size:12px;
font-weight:600;
}
#unsubscribeLink:hover{
text-decoration:underline;
color:var(--accent-hover);
}
#orText{display:none;}
.text-center.mt-4{
margin-top:22px !important;
font-size:12px;
}
.divider{
height:36px;
border-bottom:1px solid #eee;
}
.success-icon{
width:54px;
height:54px;
border-radius:999px;
margin:0 auto 18px;
background:#f4f4f4;
color:#111;
display:flex;
align-items:center;
justify-content:center;
font-size:26px;
font-weight:900;
}
@media(max-width:576px){
body{background:#fff;}
.col-12.col-md-6.offset-md-3{
max-width:100%;
margin:0 auto !important;
padding:42px 24px 36px;
}
.heading{font-size:25px;}
#freqSection .form-check{
padding-left:12px;
}
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-12 col-md-6 offset-md-3 mt-4">
<div class="lang-row">
<div class="lang-bar">
<button type="button" class="btn btn-sm" data-lang-btn="de">DE</button>
<button type="button" class="btn btn-sm" data-lang-btn="en">EN</button>
<button type="button" class="btn btn-sm" data-lang-btn="es">ES</button>
<button type="button" class="btn btn-sm" data-lang-btn="fr">FR</button>
</div>
</div>
<div class="logo-wrap mb-2">
<a href="https://domain.de">
<img src="https://domain.de/Logo.png" alt="Logo">
</a>
</div>
<div class="card-like mt-3">
{% if request.GET|lookup:'success' == '1' or request.method == "POST" %}
<div class="success-card">
<div class="success-icon">✓</div>
<h5 id="successHeadline" class="heading">Geschafft!</h5>
<p id="successText" class="subcopy">
Deine Einstellungen wurden gespeichert. Danke, dass du dir kurz Zeit genommen hast.
</p>
<div class="d-grid gap-2 mt-4">
<a href="#" id="backLink" class="btn btn-pill btn-cta">Zurück</a>
</div>
</div>
{% else %}
<div class="panel-card">
<h5 id="headline" class="heading">Schade, dass du uns verlassen möchtest</h5>
<p id="intro" class="subcopy">
Bestätige hier deine Abmeldung oder entscheide, wie häufig du von uns E-Mails erhalten möchtest.
</p>
<form id="prefsForm" action="" method="POST" class="mt-3">
<input type="hidden" name="$fields" value="$email,EmailFrequency,$list:[LIST_ID_1],$list:[LIST_ID_2]" />
<input type="hidden" id="updatedUrl" name="$updated_profile_url" value="" />
<input type="hidden" id="unsubUrl" name="$unsubscribed_url" value="" />
<div class="mb-3">
<label for="email" class="form-label" id="emailLabel">E-Mail-Adresse</label>
<input type="email" class="form-control" id="email" name="$email" value="{{ person.email|default:'' }}">
</div>
<div class="mb-3 d-none" id="listSubscriptions" aria-hidden="true">
<h6 id="listsHeadline" class="mb-tight">Wähle, welche Listen du abonnieren möchtest</h6>
<div class="form-check">
<input type="checkbox" class="form-check-input" name="$list:[LIST_ID_1]" id="breakingNewsList" value="true"
{% if '[LIST_ID_1]' in person|lookup:'$lists' or request.POST|lookup:'$list:[LIST_ID_1]' %}checked{% endif %}>
<label class="form-check-label" for="breakingNewsList" id="list1Label">Breaking News</label>
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" name="$list:[LIST_ID_2]" id="opinionPiecesList" value="true"
{% if '[LIST_ID_2]' in person|lookup:'$lists' or request.POST|lookup:'$list:[LIST_ID_2]' %}checked{% endif %}>
<label class="form-check-label" for="opinionPiecesList" id="list2Label">Opinion Pieces</label>
</div>
<div class="help-text" id="listsHelp">Du kannst eine oder mehrere Listen auswählen.</div>
</div>
<div class="mb-3" id="freqSection">
<h6 id="freqHeadline" class="mb-tight">Wie häufig möchtest du unseren Newsletter erhalten?</h6>
<div class="help-text" id="freqHelp">
Du kannst statt einer vollständigen Abmeldung auch einfach deine E-Mail-Frequenz reduzieren.
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" name="EmailFrequency" value="always" id="newsletterFrequencyAlways"
{% if person|lookup:'EmailFrequency' == "always" %}checked{% endif %}>
<label class="form-check-label" for="newsletterFrequencyAlways" id="freqAlways">Gerne alle News</label>
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" name="EmailFrequency" value="monthly" id="newsletterFrequencyMonthly"
{% if person|lookup:'EmailFrequency' == "monthly" %}checked{% endif %}>
<label class="form-check-label" for="newsletterFrequencyMonthly" id="freqMonthly">Einmal im Monat</label>
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" name="EmailFrequency" value="sales" id="newsletterFrequencySale"
{% if person|lookup:'EmailFrequency' == "sales" %}checked{% endif %}>
<label class="form-check-label" for="newsletterFrequencySale" id="freqSale">Nur bei Sales & Produktlaunches</label>
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" name="EmailFrequency" value="transactional" id="newsletterFrequencyTransactional"
{% if person|lookup:'EmailFrequency' == "transactional" %}checked{% endif %}>
<label class="form-check-label" for="newsletterFrequencyTransactional" id="freqTransactional">Nur transaktionale E-Mails</label>
</div>
</div>
<div class="d-grid gap-2 my-3">
<button type="submit" class="btn btn-pill btn-cta" id="saveBtn">
Präferenzen speichern
</button>
</div>
<input id="unsubscribeFromList" type="hidden" name="$unsubscribe" value="" />
<div class="text-center mt-4">
<span id="orText">oder</span>
<a href="#" id="unsubscribeLink">Von allen E-Mails abmelden</a>
</div>
</form>
</div>
{% endif %}
</div>
<div class="divider"></div>
</div>
</div>
</div>
<script>
const t = {
de: {
headline: "Schade, dass du uns verlassen möchtest",
intro: "Bestätige hier deine Abmeldung oder entscheide, wie häufig du von uns E-Mails erhalten möchtest.",
email: "E-Mail-Adresse",
freqH: "Wie häufig möchtest du unseren Newsletter erhalten?",
freqHelp: "Du kannst statt einer vollständigen Abmeldung auch einfach deine E-Mail-Frequenz reduzieren.",
a: "Gerne alle News",
m: "Einmal im Monat",
s: "Nur bei Sales & Produktlaunches",
transactional: "Nur transaktionale E-Mails",
save: "Präferenzen speichern",
or: "oder",
unsubAll: "Von allen E-Mails abmelden",
listsH: "Wähle, welche Listen du abonnieren möchtest",
list1: "Breaking News",
list2: "Opinion Pieces",
listsHelp: "Du kannst eine oder mehrere Listen auswählen.",
sHeadline: "Geschafft!",
sText: "Deine Einstellungen wurden gespeichert. Danke, dass du dir kurz Zeit genommen hast.",
uHeadline: "Abgemeldet",
uText: "Du wurdest erfolgreich von allen E-Mails abgemeldet.",
back: "Zurück"
},
en: {
headline: "Sorry to see you go.",
intro: "Confirm your unsubscription or choose how often you’d like to receive emails from us.",
email: "Your email address",
freqH: "How often would you like to receive our newsletter?",
freqHelp: "Instead of unsubscribing completely, you can simply reduce your email frequency.",
a: "All updates",
m: "Once a month",
s: "Only sales & product launches",
transactional: "Transactional emails only",
save: "Save preferences",
or: "or",
unsubAll: "Unsubscribe from all emails",
listsH: "Choose which lists you want to subscribe to",
list1: "Breaking News",
list2: "Opinion Pieces",
listsHelp: "You can select one or multiple lists.",
sHeadline: "All set!",
sText: "Your preferences have been saved. Thanks for taking a moment.",
uHeadline: "Unsubscribed",
uText: "You have been successfully unsubscribed from all emails.",
back: "Back"
},
es: {
headline: "Lamentamos que te vayas.",
intro: "Confirma tu baja o elige con qué frecuencia quieres recibir nuestros correos.",
email: "Tu correo electrónico",
freqH: "¿Con qué frecuencia quieres recibir nuestro boletín?",
freqHelp: "En lugar de darte de baja por completo, puedes simplemente reducir la frecuencia de tus emails.",
a: "Todas las novedades",
m: "Una vez al mes",
s: "Solo ofertas y lanzamientos",
transactional: "Solo correos transaccionales",
save: "Guardar preferencias",
or: "o",
unsubAll: "Darse de baja de todos los correos",
listsH: "Elige a qué listas quieres suscribirte",
list1: "Breaking News",
list2: "Opinion Pieces",
listsHelp: "Puedes seleccionar una o varias listas.",
sHeadline: "¡Listo!",
sText: "Tus preferencias se han guardado. Gracias por tomarte un momento.",
uHeadline: "Dado de baja",
uText: "Te has dado de baja correctamente de todos los correos.",
back: "Volver"
},
fr: {
headline: "Désolé de te voir partir.",
intro: "Confirme ton désabonnement ou choisis la fréquence à laquelle tu souhaites recevoir nos e-mails.",
email: "Ton adresse e-mail",
freqH: "À quelle fréquence souhaites-tu recevoir notre newsletter ?",
freqHelp: "Au lieu de te désabonner complètement, tu peux simplement réduire la fréquence de tes e-mails.",
a: "Toutes les nouveautés",
m: "Une fois par mois",
s: "Uniquement promos et lancements",
transactional: "Uniquement les e-mails transactionnels",
save: "Enregistrer les préférences",
or: "ou",
unsubAll: "Se désabonner de tous les e-mails",
listsH: "Choisis les listes auxquelles tu veux t’abonner",
list1: "Breaking News",
list2: "Opinion Pieces",
listsHelp: "Tu peux sélectionner une ou plusieurs listes.",
sHeadline: "C’est fait !",
sText: "Tes préférences ont été enregistrées. Merci d’avoir pris un moment.",
uHeadline: "Désabonné",
uText: "Tu as été désabonné(e) de tous les e-mails avec succès.",
back: "Retour"
}
};
const SUPPORTED = ["de","en","es","fr"];
function getLangFromUrl(){
const p = new URLSearchParams(window.location.search);
const lang = (p.get("lang") || "").toLowerCase();
return SUPPORTED.includes(lang) ? lang : null;
}
function detectBrowserLang(){
const raw = (navigator.language || navigator.userLanguage || "de").toLowerCase();
const primary = raw.split("-")[0];
return SUPPORTED.includes(primary) ? primary : "de";
}
function ensureLangInUrl(lang){
const url = new URL(window.location.href);
url.searchParams.set("lang", lang);
window.history.replaceState({}, "", url.toString());
}
function buildSuccessUrl(lang, action){
const url = new URL(window.location.href);
url.searchParams.set("success", "1");
url.searchParams.set("lang", lang);
if (action) url.searchParams.set("action", action);
return url.toString();
}
function getSuccessAction(){
const p = new URLSearchParams(window.location.search);
return (p.get("action") || "").toLowerCase();
}
function applyLanguage(lang){
const L = t[lang] || t.de;
document.documentElement.lang = lang;
document.querySelectorAll("[data-lang-btn]").forEach(btn => {
btn.classList.toggle("is-active", btn.getAttribute("data-lang-btn") === lang);
});
const byId = (id) => document.getElementById(id);
if (byId("headline")) byId("headline").innerText = L.headline;
if (byId("intro")) byId("intro").innerText = L.intro;
if (byId("emailLabel")) byId("emailLabel").innerText = L.email;
if (byId("listsHeadline")) byId("listsHeadline").innerText = L.listsH;
if (byId("list1Label")) byId("list1Label").innerText = L.list1;
if (byId("list2Label")) byId("list2Label").innerText = L.list2;
if (byId("listsHelp")) byId("listsHelp").innerText = L.listsHelp;
if (byId("freqHeadline")) byId("freqHeadline").innerText = L.freqH;
if (byId("freqHelp")) byId("freqHelp").innerText = L.freqHelp;
if (byId("freqAlways")) byId("freqAlways").innerText = L.a;
if (byId("freqMonthly")) byId("freqMonthly").innerText = L.m;
if (byId("freqSale")) byId("freqSale").innerText = L.s;
if (byId("freqTransactional")) byId("freqTransactional").innerText = L.transactional;
if (byId("saveBtn")) byId("saveBtn").innerText = L.save;
if (byId("orText")) byId("orText").innerText = L.or;
if (byId("unsubscribeLink")) byId("unsubscribeLink").innerText = L.unsubAll;
const action = getSuccessAction();
if (byId("successHeadline") && byId("successText")){
if (action === "unsub"){
byId("successHeadline").innerText = L.uHeadline || L.sHeadline;
byId("successText").innerText = L.uText || L.sText;
} else {
byId("successHeadline").innerText = L.sHeadline;
byId("successText").innerText = L.sText;
}
}
if (byId("backLink")) byId("backLink").innerText = L.back;
}
function setRedirectInputs(lang){
const updated = document.getElementById("updatedUrl");
const unsub = document.getElementById("unsubUrl");
if (updated) updated.value = buildSuccessUrl(lang, "updated");
if (unsub) unsub.value = buildSuccessUrl(lang, "unsub");
}
(function(){
let lang = getLangFromUrl();
if (!lang) lang = detectBrowserLang();
ensureLangInUrl(lang);
applyLanguage(lang);
setRedirectInputs(lang);
document.querySelectorAll("[data-lang-btn]").forEach(btn => {
btn.addEventListener("click", () => {
const l = btn.getAttribute("data-lang-btn");
ensureLangInUrl(l);
applyLanguage(l);
setRedirectInputs(l);
});
});
const form = document.getElementById("prefsForm");
if (form){
form.addEventListener("submit", () => {
const currentLang = getLangFromUrl() || lang || "de";
setRedirectInputs(currentLang);
});
}
const unsubLink = document.getElementById("unsubscribeLink");
if (unsubLink){
unsubLink.addEventListener("click", function(e){
e.preventDefault();
const currentLang = getLangFromUrl() || lang || "de";
setRedirectInputs(currentLang);
document.getElementById("unsubscribeFromList").value = "true";
const l1 = document.getElementById("breakingNewsList");
const l2 = document.getElementById("opinionPiecesList");
if (l1) l1.checked = false;
if (l2) l2.checked = false;
this.closest("form").submit();
});
}
const freqBoxes = Array.from(document.querySelectorAll("input[type='checkbox'][name='EmailFrequency']"));
if (freqBoxes.length){
freqBoxes.forEach(box => {
box.addEventListener("click", function(){
if (this.checked){
freqBoxes.forEach(other => {
if (other !== box) other.checked = false;
});
}
});
});
}
const back = document.getElementById("backLink");
if (back){
back.addEventListener("click", (e) => {
e.preventDefault();
const url = new URL(window.location.href);
url.searchParams.delete("success");
url.searchParams.delete("action");
window.location.href = url.toString();
});
}
})();
</script>
</body>
<!-- © GrowWithFlows. All rights reserved. -->
</html>
04 4. Personalizar la página de baja
Ajusta el HTML a tus colores y branding, sustituye la URL del logo, actualiza los IDs de listas y elimina los idiomas que no ofreces.
05 5. Crear la página de preferencias
Crea otra página para las preferencias y añade el HTML correspondiente.
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8" />
<title>Preference page</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<style>
:root{
--page-bg:#f3f3f3; /* CHANGE ME */
--card-bg:#ffffff; /* CHANGE ME */
--text:#050505; /* CHANGE ME */
--soft:#f4f4f4; /* CHANGE ME */
--accent:#429991; /* CHANGE ME */
--accent-hover:#357f79; /* CHANGE ME */
}
*{box-sizing:border-box;}
body{
background:var(--page-bg);
color:var(--text);
font-family:'Assistant', Arial, Helvetica, sans-serif;
font-size:14px;
line-height:1.45;
}
.container{max-width:100%;}
.col-12.col-md-6.offset-md-3{
max-width:600px;
margin:32px auto !important;
background:var(--card-bg);
padding:54px 42px 44px;
}
.lang-row{
display:flex;
justify-content:center;
margin-bottom:22px;
}
.lang-bar{
display:inline-flex;
gap:6px;
background:#f4f4f4;
padding:5px;
border-radius:999px;
}
.lang-bar .btn{
border:0;
border-radius:999px;
background:transparent;
color:#555;
font-size:11px;
font-weight:800;
letter-spacing:.04em;
padding:6px 10px;
line-height:1;
}
.lang-bar .btn:hover,
.lang-bar .btn:focus,
.lang-bar .btn.is-active{
background:#111;
color:#fff;
}
.logo-wrap{
padding:0 0 18px;
text-align:center;
}
.logo-wrap img{
max-height:66px;
}
.heading{
text-align:center;
font-size:28px;
line-height:1.05;
font-family:'Playfair Display', serif;
font-weight:900;
letter-spacing:-.03em;
margin:8px 0 12px;
}
.subcopy{
color:#222;
text-align:center;
max-width:330px;
margin:0 auto 28px;
font-size:13px;
line-height:1.45;
}
.panel-card,
.success-card,
.card-like{
border:0;
border-radius:0;
padding:0;
}
.form-label,
h6{
font-size:13px;
font-weight:800;
color:#050505;
margin-bottom:7px;
}
.mb-3{
margin-bottom:22px !important;
}
.row.mb-3{
display:block;
}
.row.mb-3 .col{
width:100%;
max-width:100%;
margin-bottom:18px;
}
.form-control,
.form-select{
border:1px solid #d8d8d8;
border-radius:0;
height:42px;
font-size:13px;
padding:9px 12px;
color:#111;
background-color:#fff;
}
.form-control:focus,
.form-select:focus{
border-color:#111;
box-shadow:none;
}
.help-text{
background:var(--soft);
border-left:3px solid #111;
padding:12px 14px;
color:#333;
font-size:12px;
line-height:1.45;
margin:10px 0 14px;
}
#freqSection{
padding-left:0;
margin-top:6px;
}
#freqSection .form-check{
display:flex;
align-items:center;
gap:10px;
margin:0 0 4px;
padding-left:28px;
}
.form-check-input{
position:static;
margin:0;
width:15px;
height:15px;
border-radius:0;
border:1px solid #999;
flex-shrink:0;
}
.form-check-input:checked{
background-color:#111;
border-color:#111;
}
.form-check-label{
font-size:14px;
color:#111;
line-height:1.3;
}
.btn-pill{
border-radius:0;
}
.btn-cta{
width:100%;
padding:15px 20px;
font-size:13px;
font-weight:900;
text-transform:uppercase;
letter-spacing:.02em;
background:var(--accent);
color:#fff;
border:1px solid var(--accent);
}
.btn-cta:hover,
.btn-cta:focus{
background:var(--accent-hover);
border-color:var(--accent-hover);
color:#fff;
}
#unsubscribeLink{
color:var(--accent);
text-decoration:none;
font-size:12px;
font-weight:500;
}
#unsubscribeLink:hover{
text-decoration:underline;
color:var(--accent-hover);
}
#orText{
display:none;
}
.text-center.mt-4{
margin-top:22px !important;
font-size:12px;
}
.divider{
height:36px;
border-bottom:1px solid #eee;
}
.success-icon{
width:54px;
height:54px;
border-radius:999px;
margin:0 auto 18px;
background:#f4f4f4;
color:#111;
display:flex;
align-items:center;
justify-content:center;
font-size:26px;
font-weight:900;
}
@media(max-width:576px){
body{
background:#fff;
}
.col-12.col-md-6.offset-md-3{
max-width:100%;
margin:0 auto !important;
padding:42px 24px 36px;
}
.heading{
font-size:25px;
}
#freqSection .form-check{
padding-left:12px;
}
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-12 col-md-6 offset-md-3 mt-4">
<div class="lang-row">
<div class="lang-bar">
<button type="button" class="btn btn-sm" data-lang-btn="en">EN</button>
<button type="button" class="btn btn-sm" data-lang-btn="de">DE</button>
<button type="button" class="btn btn-sm" data-lang-btn="es">ES</button>
<button type="button" class="btn btn-sm" data-lang-btn="fr">FR</button>
</div>
</div>
<div class="logo-wrap mb-2">
<img src="YOUR_LOGO_URL" alt="Logo" />
</div>
<div class="card-like mt-3">
{% if request.GET|lookup:'success' == '1' or request.method == "POST" %}
<div class="success-card">
<div class="success-icon">✓</div>
<h5 id="successHeadline" class="heading">
Geschafft!
</h5>
<p id="successText" class="subcopy">
</p>
<div class="d-grid gap-2 mt-4">
<a href="#" id="backLink" class="btn btn-pill btn-cta">
</a>
</div>
</div>
{% else %}
<div class="panel-card">
<h5 id="headline" class="heading">
</h5>
<p id="intro" class="subcopy">
</p>
<form id="prefsForm" action="" method="POST" class="mt-3">
<input
type="hidden"
name="$fields"
value="$first_name,$last_name,$email,Favourite Dog,EmailFrequency,Birthday"
/>
<input type="hidden" id="updatedUrl" name="$updated_profile_url" value="" />
<input type="hidden" id="unsubUrl" name="$unsubscribed_url" value="" />
<div class="row mb-3">
<div class="col">
<label for="firstName" class="form-label" id="firstNameLabel">
</label>
<input
type="text"
id="firstName"
class="form-control"
name="$first_name"
value="{{ person.first_name|default:'' }}"
/>
</div>
<div class="col">
<label for="lastName" class="form-label" id="lastNameLabel">
</label>
<input
type="text"
id="lastName"
class="form-control"
name="$last_name"
value="{{ person.last_name|default:'' }}"
/>
</div>
</div>
<div class="mb-3">
<label for="email" class="form-label" id="emailLabel">
</label>
<input
type="email"
class="form-control"
id="email"
name="$email"
value="{{ person.email|default:'' }}"
/>
</div>
<div class="mb-3">
<label for="Birthday" class="form-label" id="birthdayLabel">
</label>
<div id="birthdayTitle" class="help-text">
</div>
<input
type="date"
id="Birthday"
class="form-control"
name="Birthday"
value="{{ person|lookup:'Birthday'|default:'' }}"
/>
</div>
<div class="mb-3">
<label for="favouriteDog" id="favDogLabel" class="form-label">
</label>
<select class="form-select" id="favouriteDog" name="Favourite Dog">
<option value="">
Love them all!
</option>
<option value="Springer Spaniel"
{% if person|lookup:'Favourite Dog' == "Springer Spaniel" %}selected{% endif %}>
Springer Spaniel
</option>
<option value="Poodle"
{% if person|lookup:'Favourite Dog' == "Poodle" %}selected{% endif %}>
Poodle
</option>
<option value="Pug"
{% if person|lookup:'Favourite Dog' == "Pug" %}selected{% endif %}>
Pug
</option>
<option value="Golden Retriever"
{% if person|lookup:'Favourite Dog' == "Golden Retriever" %}selected{% endif %}>
Golden Retriever
</option>
</select>
</div>
<div class="mb-3" id="freqSection">
<h6 id="freqHeadline">
</h6>
<div class="help-text" id="freqHelp">
</div>
<div class="form-check">
<input
type="checkbox"
class="form-check-input"
name="EmailFrequency"
value="always"
id="newsletterFrequencyAlways"
{% if person|lookup:'EmailFrequency' == "always" %}checked{% endif %}
/>
<label class="form-check-label" for="newsletterFrequencyAlways" id="freqAlways">
</label>
</div>
<div class="form-check">
<input
type="checkbox"
class="form-check-input"
name="EmailFrequency"
value="monthly"
id="newsletterFrequencyMonthly"
{% if person|lookup:'EmailFrequency' == "monthly" %}checked{% endif %}
/>
<label class="form-check-label" for="newsletterFrequencyMonthly" id="freqMonthly">
</label>
</div>
<div class="form-check">
<input
type="checkbox"
class="form-check-input"
name="EmailFrequency"
value="sales"
id="newsletterFrequencySales"
{% if person|lookup:'EmailFrequency' == "sales" %}checked{% endif %}
/>
<label class="form-check-label" for="newsletterFrequencySales" id="freqSales">
</label>
</div>
</div>
<div class="d-grid gap-2 my-3">
<button type="submit" class="btn btn-pill btn-cta" id="saveBtn">
</button>
</div>
<input id="unsubscribeFromList" type="hidden" name="$unsubscribe" value="" />
<div class="text-center mt-4">
<a href="#" id="unsubscribeLink">
</a>
</div>
</form>
</div>
{% endif %}
</div>
<div class="divider"></div>
</div>
</div>
</div>
<script>
const t = {
de: {
headline: "Aktualisiere deine Präferenzen",
intro: "Wähle aus, welche Inhalte du erhältst und wie häufig wir dir schreiben.",
first: "Vorname",
last: "Nachname",
email: "E-Mail-Adresse",
fav: "Lieblings-Hunderasse",
birthdayTitle: "Nenne uns dein Geburtstagsdatum, um an deinem besonderen Tag ein Geschenk zu erhalten.",
birthdayLabel: "Geburtstag",
freqH: "Wie häufig möchtest du unseren Newsletter erhalten?",
a: "Gerne alle News",
m: "Einmal im Monat",
s: "Nur bei Sales & Produktlaunches",
freqHelp: "Bitte wähle eine Option (Einfachauswahl).",
save: "Präferenzen speichern",
unsubAll: "Von allen E-Mails abmelden",
sHeadline: "Geschafft!",
sText: "Deine Einstellungen wurden gespeichert.",
uHeadline: "Abgemeldet",
uText: "Du wurdest erfolgreich von allen E-Mails abgemeldet.",
back: "Zurück"
},
en: {
headline: "Update your preferences",
intro: "Choose what you receive and how often we email you.",
first: "First name",
last: "Last name",
email: "Your email address",
fav: "Favourite dog breed",
birthdayTitle: "Tell us your birthday to receive a gift on your special day.",
birthdayLabel: "Birthday",
freqH: "How often would you like to receive our newsletter?",
a: "All updates",
m: "Once a month",
s: "Only sales & product launches",
freqHelp: "Please choose one option.",
save: "Save preferences",
unsubAll: "Unsubscribe from all emails",
sHeadline: "All set!",
sText: "Your preferences have been saved.",
uHeadline: "Unsubscribed",
uText: "You have been successfully unsubscribed.",
back: "Back"
},
es: {
headline: "Actualiza tus preferencias",
intro: "Elige qué recibir y con qué frecuencia te escribimos.",
first: "Nombre",
last: "Apellido",
email: "Tu correo electrónico",
fav: "Raza de perro favorita",
birthdayTitle: "Cuéntanos tu fecha de cumpleaños para recibir un regalo en tu día especial.",
birthdayLabel: "Cumpleaños",
freqH: "¿Con qué frecuencia quieres recibir nuestro boletín?",
a: "Todas las novedades",
m: "Una vez al mes",
s: "Solo ofertas y lanzamientos",
freqHelp: "Elige una opción.",
save: "Guardar preferencias",
unsubAll: "Darse de baja de todos los correos",
sHeadline: "¡Listo!",
sText: "Tus preferencias se han guardado.",
uHeadline: "Dado de baja",
uText: "Te has dado de baja correctamente.",
back: "Volver"
},
fr: {
headline: "Mets à jour tes préférences",
intro: "Choisis ce que tu reçois et la fréquence de nos e-mails.",
first: "Prénom",
last: "Nom",
email: "Ton adresse e-mail",
fav: "Race de chien préférée",
birthdayTitle: "Indique ta date d’anniversaire pour recevoir un cadeau le jour J.",
birthdayLabel: "Anniversaire",
freqH: "À quelle fréquence souhaites-tu recevoir notre newsletter ?",
a: "Toutes les nouveautés",
m: "Une fois par mois",
s: "Uniquement promos et lancements",
freqHelp: "Choisis une option.",
save: "Enregistrer les préférences",
unsubAll: "Se désabonner de tous les e-mails",
sHeadline: "C’est fait !",
sText: "Tes préférences ont été enregistrées.",
uHeadline: "Désabonné",
uText: "Tu as été désabonné(e) avec succès.",
back: "Retour"
}
};
const SUPPORTED = ["de","en","es","fr"];
function getLangFromUrl(){
const p = new URLSearchParams(window.location.search);
const lang = (p.get("lang") || "").toLowerCase();
return SUPPORTED.includes(lang) ? lang : null;
}
function detectBrowserLang(){
const raw = (navigator.language || navigator.userLanguage || "de").toLowerCase();
const primary = raw.split("-")[0];
return SUPPORTED.includes(primary) ? primary : "de";
}
function ensureLangInUrl(lang){
const url = new URL(window.location.href);
url.searchParams.set("lang", lang);
window.history.replaceState({}, "", url.toString());
}
function buildSuccessUrl(lang, action){
const url = new URL(window.location.href);
url.searchParams.set("success", "1");
url.searchParams.set("lang", lang);
if (action){
url.searchParams.set("action", action);
}
return url.toString();
}
function setRedirectInputs(lang){
const updated = document.getElementById("updatedUrl");
const unsub = document.getElementById("unsubUrl");
if (updated){
updated.value = buildSuccessUrl(lang, "updated");
}
if (unsub){
unsub.value = buildSuccessUrl(lang, "unsub");
}
}
function getSuccessAction(){
const p = new URLSearchParams(window.location.search);
return (p.get("action") || "").toLowerCase();
}
function applyLanguage(lang){
const L = t[lang] || t.de;
document.documentElement.lang = lang;
document.querySelectorAll("[data-lang-btn]").forEach(btn => {
btn.classList.toggle(
"is-active",
btn.getAttribute("data-lang-btn") === lang
);
});
const byId = (id) => document.getElementById(id);
if (byId("headline")) byId("headline").innerText = L.headline;
if (byId("intro")) byId("intro").innerText = L.intro;
if (byId("firstNameLabel")) byId("firstNameLabel").innerText = L.first;
if (byId("lastNameLabel")) byId("lastNameLabel").innerText = L.last;
if (byId("emailLabel")) byId("emailLabel").innerText = L.email;
if (byId("favDogLabel")) byId("favDogLabel").innerText = L.fav;
if (byId("birthdayTitle")) byId("birthdayTitle").innerText = L.birthdayTitle;
if (byId("birthdayLabel")) byId("birthdayLabel").innerText = L.birthdayLabel;
if (byId("freqHeadline")) byId("freqHeadline").innerText = L.freqH;
if (byId("freqAlways")) byId("freqAlways").innerText = L.a;
if (byId("freqMonthly")) byId("freqMonthly").innerText = L.m;
if (byId("freqSales")) byId("freqSales").innerText = L.s;
if (byId("freqHelp")) byId("freqHelp").innerText = L.freqHelp;
if (byId("saveBtn")) byId("saveBtn").innerText = L.save;
if (byId("unsubscribeLink")) byId("unsubscribeLink").innerText = L.unsubAll;
const action = getSuccessAction();
if (byId("successHeadline") && byId("successText")){
if (action === "unsub"){
byId("successHeadline").innerText = L.uHeadline;
byId("successText").innerText = L.uText;
} else {
byId("successHeadline").innerText = L.sHeadline;
byId("successText").innerText = L.sText;
}
}
if (byId("backLink")){
byId("backLink").innerText = L.back;
}
}
(function(){
let lang = getLangFromUrl();
if (!lang){
lang = detectBrowserLang();
}
ensureLangInUrl(lang);
applyLanguage(lang);
setRedirectInputs(lang);
document.querySelectorAll("[data-lang-btn]").forEach(btn => {
btn.addEventListener("click", () => {
const l = btn.getAttribute("data-lang-btn");
ensureLangInUrl(l);
applyLanguage(l);
setRedirectInputs(l);
});
});
const form = document.getElementById("prefsForm");
if (form){
form.addEventListener("submit", () => {
const currentLang = getLangFromUrl() || lang || "de";
setRedirectInputs(currentLang);
});
}
const unsubLink = document.getElementById("unsubscribeLink");
if (unsubLink){
unsubLink.addEventListener("click", function(e){
e.preventDefault();
const currentLang = getLangFromUrl() || lang || "de";
setRedirectInputs(currentLang);
document.getElementById("unsubscribeFromList").value = "true";
this.closest("form").submit();
});
}
const freqBoxes = Array.from(
document.querySelectorAll("input[type='checkbox'][name='EmailFrequency']")
);
freqBoxes.forEach(box => {
box.addEventListener("click", function(){
if (this.checked){
freqBoxes.forEach(other => {
if (other !== box){
other.checked = false;
}
});
}
});
});
const back = document.getElementById("backLink");
if (back){
back.addEventListener("click", (e) => {
e.preventDefault();
const url = new URL(window.location.href);
url.searchParams.delete("success");
url.searchParams.delete("action");
window.location.href = url.toString();
});
}
})();
</script>
</body>
<!-- © GrowWithFlows. All rights reserved. -->
</html>
06 6. Adaptar las propiedades personalizadas
Asegúrate de que las propiedades personalizadas, los IDs de listas y los campos estén correctamente configurados — de lo contrario, no funcionará correctamente. Si es necesario, pide ayuda a un desarrollador o contacta con nosotros.
07 7. Asignar las páginas
Vuelve a la vista general y asigna tus páginas a las correspondientes páginas de baja y preferencias.
08 8. Probar todo
Envíate un email real usando un perfil de prueba — no solo una vista previa. Ve al perfil, abre “View Messages”, haz clic en “Send Mail” y comprueba que tanto la baja como las preferencias funcionan correctamente.
5. Configuración de flows
Dentro de tus flows también puedes aprovechar los datos de locale que provienen de Shopify.
Existen dos enfoques principales:
5.1 Flows separados o conditional splits
Esto es similar a la configuración clásica: puedes filtrar flows completos por idioma o utilizar conditional splits dentro de un mismo flow.
Ventajas
- Fácil diferenciación por idioma o país.
- Permite emails completamente diferentes por mercado.
- Visibilidad del rendimiento por idioma o país.
Desventajas
- Más flows o ramas que gestionar.
- Más trabajo manual.
- Los destinatarios pueden quedar “bloqueados” en el flujo inicial según el idioma.
Elige este enfoque si quieres tener visibilidad completa de cómo funcionan tus flows en diferentes idiomas o mercados.
5.2 Uso de la función de traducción
Si principalmente quieres comunicarte en el idioma correcto y no necesitas reporting por idioma, puedes utilizar la función de traducción de Klaviyo dentro de un único flow central.
Ventajas
- Solo necesitas mantener un único email.
- Las traducciones con IA están disponibles — solo necesitas revisarlas.
- Estructura de flows más limpia y fácil de gestionar.
Desventajas
- Sin diferenciación integrada entre mercados.
- Sin reporting por idioma o país.
Elige este enfoque si buscas una configuración más sencilla y solo necesitas comunicar en el idioma correcto sin analizar el rendimiento por mercado.
6. Configuración de campañas
Con la nueva función de traducción, en teoría ya no necesitas campañas separadas por idioma. En su lugar, puedes enviar una única campaña a todos y controlar el idioma mediante la función de traducción.
Sin embargo, para análisis y datos a nivel de mercado, puede seguir teniendo sentido dividir las campañas por idioma o país. Esto es especialmente útil si quieres entender cómo funciona una campaña en mercados y/o idiomas específicos.
Por lo tanto, debes decidir qué configuración se adapta mejor a tu caso:
6.1 Una campaña usando la función de traducción
Si tu objetivo principal es enviar emails en el idioma correcto —y no necesitas análisis detallados por idioma— sigue estos pasos:
- Crea los segmentos que quieres targetear sin especificar un idioma.
- Diseña y escribe tu email de campaña primero en un idioma.
- Una vez finalizado el email, utiliza la función de traducción de Klaviyo para añadir las demás versiones.
Ventajas
- Gestionas los segmentos en función del comportamiento, no del idioma.
- Envías una única campaña a una audiencia más grande, lo que puede ser útil para A/B testing.
- La IA de Klaviyo puede traducir la mayor parte del email por ti, solo necesitas revisarlo y ajustarlo.
Desventajas
- El reporting se muestra como un resultado global, no desglosado por idioma o país.
- Tienes menos visibilidad sobre qué versión de idioma funciona mejor.
Elige este enfoque si principalmente quieres enviar el idioma correcto y buscas la configuración más simple posible.
6.2 Campañas separadas usando exclusiones por idioma o país
Utiliza este enfoque si es importante para ti entender cómo funcionan los distintos idiomas o países.
- Crea tus segmentos principales sin condiciones de idioma o país.
- Crea segmentos adicionales por idioma, por ejemplo:
- Perfiles en alemán (Locale: Language = de) y en inglés (Locale: Language = en).
- Segmentos por país como perfiles en Alemania (Locale: Country = DE), Austria (Locale: Country = AT) u otros mercados relevantes.
- Para un análisis más profundo, crea combinaciones de idioma-país como perfiles en alemán en Alemania (Locale = de_DE) o en inglés en Alemania (Locale = en_DE).
- Al enviar campañas, utiliza tu segmento principal como 'Send to' y excluye los idiomas o países que no quieres targetear.
Envío por idioma
Utiliza un segmento principal y controla cada versión de la campaña mediante exclusiones.
Ventajas
- Puedes analizar el rendimiento de cada campaña por idioma o país.
- Al usar segmentos de idioma o país como exclusiones, puedes reutilizarlos en múltiples campañas sin necesidad de crear nuevos segmentos cada vez.
- Obtienes mayor control sobre la comunicación y el análisis por mercado.
Desventajas
- Es ligeramente más complejo de gestionar (comparado con la opción 1), ya que siempre debes trabajar con exclusiones (por ejemplo, para emails en alemán excluir perfiles en inglés — y viceversa).
- Requiere crear manualmente un email separado para cada idioma.
- La configuración de campañas lleva más tiempo que con una única campaña traducida.
Elige este enfoque si quieres mejor reporting y mayor control por idioma, país o mercado.
Conclusión
Con la nueva función de traducción, gestionar el multi-idioma en Klaviyo se ha vuelto mucho más sencillo. Si sigues los pasos de esta guía, deberías terminar con una configuración limpia en la que el locale se sincroniza correctamente desde Shopify.
Esta guía se centra únicamente en la configuración multilingüe dentro de Klaviyo.
Desde 2026, Klaviyo también es compatible con Shopify Markets a través de los llamados Locale Aware Catalogs. Esto te permite sincronizar datos de producto específicos por mercado desde Shopify a Klaviyo, incluyendo idioma, moneda, precios y URLs de producto localizadas — para que tus emails siempre muestren la información correcta para cada mercado.
Todo ha funcionado — tu guía está en camino.
Revisa tu bandeja de entrada. Si no aparece, comprueba también spam o promociones.
¿Aún pensando en tu setup multilingüe?
Deja que implementemos tu setup multilingüe por ti
Configuramos tu sistema multilingüe por completo — limpio, estructurado y listo para usar en Shopify y Klaviyo.
- Migración de tu setup de idiomas existente
- Limpieza de propiedades de idioma en Klaviyo
- Integración limpia con Shopify localization
- Estructura de flows y segmentos
- Sistema escalable para varios mercados