Migration Guide · Version 04.26
Multi-Language Setup für Klaviyo
Dieser Guide zeigt dir, wie du Klaviyos Übersetzungsfunktion nutzt, damit deine Nutzer E-Mails in der richtigen Sprache erhalten. Zur besseren Orientierung geht dieser Guide davon aus, dass Deutsch die Standardsprache im Shop ist und Englisch als zweite Sprache ergänzt wird.
1. Hintergrund
Im Juli 2025 hat Klaviyo eine Übersetzungsfunktion eingeführt, mit der du E-Mails direkt in Klaviyo übersetzen kannst. Ähnlich wie bei Shopify-Übersetzungen erstellst du deine E-Mail zunächst in einer Sprache und übersetzt sie anschließend.
Beim Versand entscheidet Klaviyo anhand der ausgewählten Sprache des Profils, welche Sprachversion angezeigt wird.
Vorteile:
- KI-Übersetzungen sind verfügbar.
- Du musst weniger doppelte E-Mails erstellen.
- Du reduzierst das Risiko, E-Mails in der falschen Sprache zu senden.
2. Setup der Übersetzungsfunktion
2.1 Basis-Setup
Um die Übersetzungsfunktion zu nutzen, gehe in Klaviyo zu Einstellungen → Übersetzung und aktiviere die Funktion.
Wähle anschließend aus, welche Custom Property Klaviyo für die Sprachzuordnung verwenden soll. Nutze hier die von Shopify übergebene 'Locale'.
Der Vorteil dieser Property: Die Shopify Locale wird in Klaviyo automatisch in Sprache und Land aufgeteilt, was die Segmentierung sowie das Management von Flows und Kampagnen deutlich vereinfacht.
- Locale
- Locale: Land
- Locale: Sprache
Nachdem du die Locale ausgewählt hast, lege deine unterstützten Sprachen fest und definiere eine Standardsprache. Wenn der Großteil deiner Nutzer deutschsprachig ist, kann Deutsch deine Standardsprache sein. Ist deine Zielgruppe international, ist Englisch meist die bessere Wahl.
2.2 Bestehende Profile migrieren
Wenn du Klaviyo bereits länger nutzt, ist der nächste Schritt sicherzustellen, dass alle bestehenden, aktiven Profile eine gesetzte Sprache (Locale) haben.
Erstelle dafür zunächst ein Segment mit:
- Eigenschaften über eine Person → Locale = Not Set
- UND: Person kann E-Mail-Marketing erhalten
Reduziere anschließend die Anzahl der Profile ohne gesetzte Sprache auf 0 mit den folgenden Schritten.
01 Shopify neu synchronisieren
Gehe in Klaviyo zur Shopify-Integration und importiere deine Kontakte erneut. Dadurch können ältere Kundenprofile angereichert werden, bei denen die Sprache zuvor nicht an Klaviyo übergeben wurde.
02 Alte Sprach-Properties nutzen
Wenn du die Sprache deiner Kunden zuvor in einer anderen Custom Property gespeichert hast, nutze dein „Locale = Not Set“-Segment als Trigger für einen Flow.
- Füge einen Conditional Split basierend auf deiner alten Sprach-Property hinzu.
- Leite Nutzer je nach Sprache (DE, EN, ES, FR usw.) in unterschiedliche Pfade.
- Nutze eine „Update Profile Property“-Action und setze $locale entsprechend (z. B. de, en, es, fr).
- Setze den Flow auf Live und nutze „Add past profiles“ am Trigger, damit auch bestehende Profile direkt durch den Flow laufen.
03 Listen-Zuordnungen nutzen
Wenn weiterhin Nutzer im Segment „Locale = Not Set“ sind, nutze vorhandene Listen-Zuordnungen, um sie zu kategorisieren – z. B. wenn du Nutzer früher nach Sprache in verschiedene Listen aufgeteilt hast.
Nutze die gleiche Flow-Logik wie oben: Trigger über das Segment, Split nach Liste und anschließend das Locale-Feld aktualisieren.
04 Fallback festlegen
Wenn du alle Optionen ausgeschöpft hast und noch Profile ohne gesetzte Sprache übrig sind, weise ihnen eine Fallback-Sprache zu (z. B. Englisch).
Ziel
Ziel: Dein Segment „Locale = Not Set“ sollte 0 sein.
2.3 Neue Profile taggen
Sobald deine historischen Daten migriert wurden, solltest du sicherstellen, dass neue Profile automatisch eine Locale erhalten.
Neue Profile entstehen in der Regel über:
- Klaviyo-Formulare oder Onsite-Skripte
- Back-in-Stock-Anmeldungen
- Shopify Checkout
- Shopify Newsletter-Formulare
- Externe Tools wie Typeform, Quiz-Apps oder Beratungs-Tools
2.3.1 Klaviyo Onsite-Skript
Wenn ein User deinen Shop besucht, aber keinen Checkout startet, weiß Klaviyo möglicherweise nicht, welche Sprache oder welches Land verwendet wurde. Füge dieses Snippet in deine theme.liquid vor dem schließenden </body>-Tag ein:
<!-- 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 -->
So wird sichergestellt, dass Sprach- und Länderinformationen jederzeit automatisch mit Klaviyo synchronisiert werden. Sobald ein neues Profil erstellt wird, – egal, ob über ein Klaviyo-Formular oder eine Back-in-Stock-Anfrage – wird die korrekte Locale direkt übergeben.
Gleichzeitig werden spätere Änderungen in deinem Shop (z. B. wenn ein Kunde die Sprache ändert oder zuvor falsch zugeordnet wurde) automatisch in Klaviyo übernommen – sodass alle Profile stets korrekt und aktuell bleiben.
2.3.2 Externe Tools / Apps
Externe Tools sind etwas komplexer – aber in der Regel benötigst du ohnehin ein sauberes System zur Zuordnung der verschiedenen Sprachversionen. Sobald dieses System definiert ist, kannst du dieselben Logiken nutzen, um die korrekte Locale in Klaviyo konsistent zu setzen – entweder direkt über einen „Update Profile Property“-Step oder indirekt über Shopify Flow, auch rückwirkend für bestehende Profile.
3. Aussteuerung von Formularen
Um sicherzustellen, dass deine Shop-Besucher mit den richtigen Sprachversionen bei Formularen (SignUp und BackInstock) angesprochen werden UND gleichzeitig auch die Double OptIn-Mail in der richtigen Sprache erhalten (wichtig für die Bestätigungsrate), gehe wie folgt vor.
Erstelle zunächst für jede Sprache eine eigene Liste. Zum Beispiel:
- DE Newsletter
- EN Newsletter
- ES Newsletter
Passe für jede Liste die Double-Opt-in-E-Mail an die jeweilige Sprache an. Wird die Bestätigungs-E-Mail in der falschen Sprache versendet, kann das deine Opt-in-Rate deutlich senken.
Andere listenbezogene Seiten wie Preference- oder Unsubscribe-Seiten kannst du ignorieren (hierfür bauen wir uns noch was separates).
3.1 Klaviyo Formular-Setup
Bei der Verwendung von Klaviyo-Formularen musst du sicherstellen, dass Besucher das Anmeldeformular immer in der richtigen Sprache sehen – damit z. B. kein deutsches Formular in der englischen Shop-Version angezeigt wird.
Die gute Nachricht: Wenn du Shopify Markets nutzt, strukturiert Shopify deine URLs automatisch nach Locale (z. B. /en_DE oder /fr_FR). Diese URL-Struktur kannst du verwenden, um zu steuern, welches Formular welchem Nutzer angezeigt wird.
So kannst du das passende Formular basierend auf Sprache (und ggf. Land) anzeigen.
Beispiel
Für die englische Version deines Shops können URLs /en enthalten (z. B. deinedomain.com/en_DE). Dabei steht 'en' für die Sprache und 'DE' für das Land. Nutze diese Informationen, um dein Anmeldeformular zu erstellen:
01 1. Formular erstellen
Erstelle dein Anmeldeformular in der gewünschten Sprache (z. B. zunächst auf Englisch).
02 2. Anzeige-Targeting festlegen
Gehe im Formular-Editor zu Targeting → Targeting und stelle ein, dass das Formular nur auf Seiten angezeigt wird, die deinedomain.com/en enthalten.
03 3. Submit-Verhalten konfigurieren
Stelle für den Submit-Button in der englischen Version Folgendes ein:
- Füge Abonnenten zu deiner englischen Newsletter-Liste hinzu (für die Double-Opt-in-Mail).
- Füge ein verstecktes benutzerdefiniertes Feld mit Locale = en hinzu
04 4. Für andere Sprachen duplizieren
Sobald dein englisches Formular eingerichtet ist, dupliziere es und passe es für weitere Sprachen an.
- Passe alle Texte an die Zielsprache an.
- Stelle sicher, dass es nur auf Seiten mit dem entsprechenden Sprach-Identifier angezeigt wird.
- Verbinde das Formular mit der passenden Newsletter-Liste.
- Aktualisiere das versteckte Locale-Feld (z. B. 'fr').
- Wiederhole das für alle Sprachen
Wichtig: Deine Standardsprache
Für deine Standardsprache gibt es keinen URL-Identifier. In diesem Fall gehst du, wie folgt vor:
- Passe alle Texte an die Standardsprache an.
- Gehe zu Targeting → Targeting und füge bei 'Don't show on' alle URLs ein, die deine anderen Sprachen enthalten (z. B. deinedomain.com/en, deinedomain.com/fr usw.).
- Verbinde das Formular mit der Newsletter-Liste der Standardsprache.
- Aktualisiere das versteckte Locale-Feld auf deine Standardsprache (z. B. 'de').
3.2 Back-in-Stock Setup
Wenn du das Standard-Back-in-Stock-Snippet von Klaviyo nutzt, um eine Benachrichtigungsfunktion für ausverkaufte Produkte hinzuzufügen, ergeben sich beim Aufbau eines mehrsprachigen Systems drei Herausforderungen:
- Wie stellst du sicher, dass das Back-in-Stock-Formular in der richtigen Sprache angezeigt wird?
- Wie wird das Locale des Nutzers an sein Klaviyo-Profil übergeben?
- Und wie versendest du die Double-Opt-in-Mail in der richtigen Sprache, wenn sich Nutzer zusätzlich für den Newsletter anmelden möchten?
Die Locale wird über das in 2.3.1 gezeigte Script automatisch bei der Erstellung des Profiles erzeugt (wenn das Script bei dir zuverlässig funktioniert).
Das bedeutet, dass du dich nur noch auf zwei Dinge konzentrieren musst: Übersetzungen und die Zuordnung zur richtigen Liste.
Folge diesen Schritten für das Setup:
01 1. Back-in-Stock-Snippet hinzufügen
Füge das Back-in-Stock-Snippet in deine theme.liquid-Datei vor dem schließenden </body>-Tag ein und definiere Übersetzungs-Strings für alle Elemente, die du lokalisieren möchtest.
<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. Klaviyo Account-ID ersetzen
Ersetze 'XXXXX' durch deinen öffentlichen Klaviyo API-Schlüssel. Diesen findest du unter Settings → API Keys → Public API Key.
03 3. Übersetzungen für die Standardsprache hinzufügen
Gehe in deine Locale-Datei (z. B. en.default.json) und füge folgenden Übersetzungsblock in den 'general'-Bereich ein:
"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"
},
Passe die Listen-ID und die Übersetzungen an deine Anforderungen an.
Das sollte ungefähr so aussehen:
04 4. Übersetzungen für weitere Sprachen hinzufügen
Wiederhole diesen Schritt für jede Sprache und passe sowohl die Texte als auch die Listen-ID entsprechend an. Zum Beispiel in deiner de.json-Datei:
"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. Für alle Sprachen wiederholen
Stelle sicher, dass jede Sprache ihr eigenes Übersetzungsset hat und mit der richtigen Liste verbunden ist.
3.3 Shopify-Integration und sprachbasierte Listen
Die gute Nachricht vorweg: Neue Profile aus Shopify (z. B. über Checkout oder Theme-Formulare) übergeben die Sprache automatisch an Klaviyo.
Das Problem: Klaviyo kann diese Nutzer standardmäßig nur in eine einzige Liste eintragen — unabhängig von ihrer Sprache.
Da die Double-Opt-in-Mail immer an diese Liste gebunden ist, wird sie oft in der falschen Sprache verschickt.
Die Lösung: Du musst die automatische Listen-Zuordnung umgehen und stattdessen selbst festlegen, in welche Liste ein Nutzer je nach Sprache kommt.
Folge diesen Schritten für das Setup:
01 1. Standard-Zuordnung deaktivieren
Gehe zur Shopify-Integration in Klaviyo und deaktiviere die Option, die Profile automatisch zu einer Liste hinzufügt.
02 2. Shopify Flow erstellen
Erstelle in Shopify einen Shopify Flow, der neue Newsletter-Abonnenten basierend auf der im Shop ausgewählten Sprache in unterschiedliche Listen weiterleitet.
03 3. Profile basierend auf Sprache zuweisen
Konfiguriere den Flow so, dass Kunden, die sich für E-Mail-Marketing anmelden, abhängig von ihrem Locale zur richtigen Klaviyo-Liste hinzugefügt werden.
4. Abmelde- und Präferenzseiten
Bleibt noch die Frage, wie wir die Abmelde- und Präferenzseiten in mehreren Sprachen anbieten.
In Klaviyo werden Abmelde- und Präferenzseiten an zwei Stellen verwaltet: unter Settings → Others → Default Consent Pages sowie direkt auf einzelnen Listen.
Listenspezifische Seiten helfen nur, wenn du auch genau an diese Listen sendest. Sobald du jedoch an Segmente sendest – was in der Regel der empfohlene Ansatz ist – verwendet Klaviyo stattdessen die Default-Consent-Seiten.
Folge diesen Schritten, um das Setup umzusetzen:
01 1. Hosted Pages aktivieren
Gehe zu Einstellungen → Sonstiges → Consent Pages und aktiviere Hosted Pages für deinen Account. Falls dein Account noch neu ist, musst du eventuell warten, bis Klaviyo ihn verifiziert hat.
02 2. Tab „Hosted Pages“ öffnen
Sobald aktiviert, erscheint in der linken Navigation ein neuer Tab namens „Hosted Pages“.
03 3. Abmeldeseite erstellen
Erstelle eine neue Hosted Page mit unsubscribe_page.tmpl und füge den HTML-Code für deine Abmeldeseite ein.
<!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. Abmeldeseite anpassen
Passe den HTML-Code an deine Farben und dein Branding an, ersetze die Logo-URL, aktualisiere die Listen-IDs und entferne alle Sprachen, die du nicht anbietest.
05 5. Präferenzseite erstellen
Erstelle eine weitere Hosted Page für deine Präferenzseite und füge den entsprechenden HTML-Code ein.
<!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. Custom Properties anpassen
Stelle sicher, dass deine Custom Properties, Listen-IDs und Felder korrekt gemappt sind – sonst funktioniert das Setup nicht wie erwartet. Falls nötig, lass den Code von einem Entwickler anpassen oder kontaktiere uns für Unterstützung.
07 7. Hosted Pages zuweisen
Gehe zurück zur Übersicht und weise deine Hosted Pages den entsprechenden Abmelde- und Präferenzseiten zu.
08 8. Alles testen
Sende dir selbst eine echte E-Mail über ein Testprofil – nicht nur eine Vorschau - zu (Gehe in das Profil, öffne „View Messages“, klicke auf „Send Mail“ und prüfe, ob Abmeldung und Präferenzen korrekt funktionieren).
5. Flow-Setup
Innerhalb deiner Flows kannst du ebenfalls die Locale-Daten nutzen, die von Shopify übergeben werden.
Grundsätzlich gibt es zwei Ansätze:
5.1 Separate Flows oder Conditional Splits
Das entspricht dem klassischen Setup: Entweder filterst du komplette Flows nach Sprache oder nutzt Conditional Splits innerhalb eines Flows.
Vorteile
- Einfache Differenzierung nach Sprache oder Land.
- Komplett unterschiedliche E-Mails pro Markt möglich.
- Performance pro Sprache oder Land sichtbar.
Nachteile
- Du musst mehr Flows oder Verzweigungen verwalten.
- Mehr manueller Aufwand.
- Empfänger können in der initial festgelegten (bei Trigger oder Conditional-Split) Sprachlogik „feststecken“.
Wähle diesen Ansatz, wenn du volle Transparenz darüber haben möchtest, wie deine Flows in verschiedenen Sprachen oder Märkten performen.
5.2 Nutzung der Übersetzungsfunktion
Wenn du hauptsächlich in der richtigen Sprache kommunizieren möchtest und kein Reporting auf Sprachebene benötigst, kannst du die Übersetzungsfunktion von Klaviyo in einem zentralen Flow nutzen.
Vorteile
- Du musst nur eine E-Mail pflegen.
- KI-Übersetzungen sind verfügbar — du musst sie nur noch überprüfen.
- Sauberere und einfacher zu verwaltende Flow-Struktur.
Nachteile
- Keine integrierte Differenzierung zwischen Märkten.
- Kein Reporting nach Sprache oder Land.
Wähle diesen Ansatz, wenn du sicherstellen willst, dass in der richtigen Sprache kommuniziert wird, ohne aber Performance nach Markt oder Sprache auswerten zu wollen. Perspektivisch ist dieser Ansatz einfacher zu skalieren und zu pflegen, hängt aber natürlich stark an deinen Anforderungen.
6. Kampagnen-Setup
Mit der neuen Übersetzungsfunktion brauchst du (theoretisch) keine separaten Kampagnen mehr pro Sprache. Stattdessen kannst du eine einzige Kampagne an alle senden und die Sprache über die Übersetzungsfunktion steuern.
Für Analysen und Einblicke auf Marktebene kann es jedoch weiterhin sinnvoll sein, Kampagnen nach Sprache oder Land aufzuteilen. Das ist besonders hilfreich, wenn du verstehen möchtest, wie eine Kampagne in bestimmten Märkten und/oder Sprachen performt.
Du musst also entscheiden, welches Setup am besten zu deinem Use Case passt:
6.1 Eine Kampagne mit der Übersetzungsfunktion
Wenn dein Hauptziel darin besteht, E-Mails in der richtigen Sprache zu versenden — und du keine detaillierten Performance-Daten pro Sprache benötigst — folge diesen Schritten:
- Erstelle die Segmente, die du targeten möchtest, ohne eine Sprache festzulegen.
- Erstelle und schreibe deine Kampagnen-E-Mail zunächst in einer Sprache.
- Sobald die E-Mail fertig ist, nutze die Übersetzungsfunktion von Klaviyo, um die weiteren Sprachversionen hinzuzufügen.
Vorteile
- Du segmentierst basierend auf Verhalten, nicht auf Sprache.
- Du versendest nur eine Kampagne an eine größere Zielgruppe, was für A/B-Tests hilfreich sein kann.
- Klaviyo AI kann den Großteil der E-Mail für dich übersetzen — du musst sie nur noch überprüfen und optimieren.
Nachteile
- Das Reporting wird als Gesamtergebnis angezeigt, nicht nach Sprache oder Land aufgeschlüsselt.
- Du hast weniger Einblick, welche Märkte am besten performen.
Ideal, wenn Du NICHT in Märkten denkst, sondern es wirklich nur um die Kommunikation mit deinen Empfängern in der richtigen Sprache geht.
6.2 Separate Kampagnen mit Sprach- oder Länder-Exclusions
Wenn Du zwischen Sprachen und/ oder Märkten unterscheiden möchtest, dann wirst du weiterhin seperate Kampagnen versenden müssen.
- Erstelle deine Segmente, wie gewohnt und OHNE Sprach- oder Länderbedingungen (bspw. Engaged (letzte 90 Tage))
- Erstelle zusätzliche Sprachsegmente, z. B.:
- Deutsche Profile (Locale: Language = de) und englische Profile (Locale: Language = en).
- Ländersegmente wie Profile in Deutschland (Locale: Country = DE), Österreich (Locale: Country = AT) oder andere relevante Märkte.
- Für noch tiefere Analysen kannst du Kombinationen aus Sprache und Land erstellen, z. B. deutsche Profile in Deutschland (Locale = de_DE) oder englische Profile in Deutschland (Locale = en_DE).
- Beim Versand nutzt du dein Hauptsegment als 'Send to'-Zielgruppe und schließt die Sprach- oder Länder-Segmente aus, die du nicht targeten möchtest.
Versand nach Sprache
Nutze dein normales Segment (bpsw. Engaged (letzte 90 Tage)) und schließe für jede Kampagne einfach die anderen Sprachen aus.
Vorteile
- Du kannst die Performance jeder Kampagne nach Sprache oder Land auswerten.
- Durch die Nutzung von Sprach- oder Ländersegmenten als Excluded-Segmente kannst du diese wiederverwenden, anstatt jedes Mal neue Segmente mit entsprechenden Sprachbezug zu erstellen (wird schnell unübersichtlich).
- Du hast mehr Kontrolle über marktspezifische Kommunikation und Analyse.
Nachteile
- Etwas komplexer zu verwalten (im Vergleich zu Option 1), da du immer mit Exclusions arbeiten musst (z. B. für deutsche Mails englische Profile ausschließen — und umgekehrt).
- Du musst für jede Sprache manuell eine separate E-Mail erstellen.
- Der Kampagnenaufbau dauert länger als bei einer einzigen übersetzten Kampagne.
Wähle diesen Ansatz, wenn du besseres Reporting und mehr Kontrolle nach Sprache, Land oder Markt möchtest.
Fazit
Mit dem neuen Übersetzungs-Feature ist das Thema Multi-Language in Klaviyo deutlich einfacher geworden. Wenn du die Schritte in diesem Guide befolgst, solltest du ein sauberes Setup erhalten, bei dem die Locale zuverlässig aus Shopify übernommen wird, SignUps in der richtigen Sprache erscheinen und (DOI) Mails immer in der richtigen Sprache rausgehen.
Dieser Guide konzentriert sich ausschließlich auf das mehrsprachige Setup in Klaviyo.
Seit 2026 unterstützt Klaviyo auch Shopify Markets über sogenannte Locale Aware Catalogs. Dadurch kannst du marktspezifische Produktdaten aus Shopify in Klaviyo synchronisieren, einschließlich Sprache, Währung, Preisen und lokalisierten Produkt-URLs — sodass deine E-Mails immer die richtigen Produktinformationen für jeden Markt anzeigen.
Alles hat geklappt — dein Guide ist unterwegs.
Schau gleich in dein Postfach. Falls du nichts siehst, prüfe auch Spam oder Promotions.
Keine Zeit alles selbst zu machen?
Lass dein Multi-Language Setup direkt von uns umsetzen
Wir setzen dein Multi-Language System komplett für dich auf — sauber strukturiert und direkt einsatzbereit in Shopify & Klaviyo.
- Migration deines bestehenden Sprach-Setups
- Bereinigung deiner Klaviyo Language Properties
- Shopify-Lokalisierung sauber integrieren
- Flows und Segmente strukturiert aufbauen
- Skalierbare Struktur für mehrere Märkte