Bessere Performance bei Google Ads, Meta & Co
Conversion-Tracking in Shopify ist komplex. Dauernd ändert sich etwas und die Kommunikation von Shopify selbst ist häufig verwirrend.
Wir zeigen, wie man die meistens Conversions in Google Ads, Meta Ads, TikTok Ads, usw. misst. Inklusive erprobtem JavaScript-Code zum Kopieren.
Conversion-Tracking ermöglicht, das Nutzerverhalten auf der Website genauer zu analysieren. Man kann den Erfolg einer Marketingkampagne präzise nachvollziehen und Optimierungen vornehmen. Das ist unerlässlich, um die Zielgruppe besser zu verstehen und noch um sie gezielter ansprechen und überzeugen zu können.
Es gibt vier verschiedene Möglichkeiten, Conversion-Tracking in Shopify aufzusetzen:
Unsere Einschätzung
Wer es mit Tracking ernst meint, der sollte auf Tracking mit dem Google Tag Manager setzen. Wer noch am Anfang steht, kann die entsprechenden Apps einsetzen.
Über den Autor
Julian Kleinknecht ist Geschäftsführer bei ConversionBoosting und unterstützt Unternehmen seit mehr als 14 Jahren bei Webanalyse und Tracking. Er teilt Erkenntnisse hier, auf LinkedIn und auf YouTube.
Wir haben Tracking schon über 100 mal für Shopify integriert. Alles in diesem Beitrag basiert auf echter Erfahrung.
Die Kundenereignisse sind Shopifys Antwort auf das Problem, dass Tracking-Codes bisher an verschiedenen Stellen verstreut im Shop-Theme implementiert wurden.
Bisher konnte recht einfach JavaScript-Code in den Shop eingefügt werden, der die Funktionalität des Shops beeinträchtigt hat. Mit den Kundenereignissen wird das Theme komplett vom Tracking getrennt. Außerdem findet man alle Tracking-Codes an einer Stelle.
Nachdem man einen neuen Eintrag angelegt hat, wird in ein Freitextfeld direkt der JavaScript-Code integriert. Für Google Ads wird zum Beispiel die gtag-Bibliothek verwendet.
Nur der Google Tag Manager sowie der dataLayer wird über die Kundenereignisse bzw. eine App integriert (mehr dazu weiter unten). Das eigentliche Tracking erfolgt dann im Google Tag Manager selbst.
Für alle großen Anbieter gibt es Apps, die einem das Tracking sehr erleichtern
Diese Apps sind sehr einfach einzurichten. Man verbindet seinen Account beim jeweiligen Anbieter. Fertig.
Die Apps haben aber auch große Nachteile.
Unsere Einschätzung
Wer es mit Tracking ernst meint, der sollte auf Tracking mit dem Google Tag Manager setzen. Nur wer noch am Anfang steht, kann die Vertriebskanäle einsetzen.
Unter Einstellungen
> Checkout
findet man diese Box.
Dort kann beliebiger JavaScript-Code eingefügt werden, der auf der Danke-Seite ausgeführt wird.
Aber: Wenn man mithilfe der “Checkout Extensibility” auf eine neue Danke-Seite umstellt, dann funktioniert das Tracking mithilfe der “Zusätzliche Skripte für die Bestellstatus-Seite” nicht mehr. Die Skripte werden nicht mehr ausgeführt.
Und ab dem 28. August 2025 werden alle Shops automatisch auf die neue Danke-Seite umgestellt.
Unsere Einschätzung
Jetzt schon auf alternative Methoden umstellen.
Wer unserer Empfehlung folgt und das Tracking via Google Tag Manager (GTM) aufsetzt, der steht vor der Frage, wie man den GTM am besten integriert. Diese Möglichkeiten gibt es:
Sowie oben das Tracking für Google Ads direkt in die Kundenereignisse integriert wurde, kann man auch den GTM-Code und dataLayer dort integrieren:
Hintergrund: Kundenereignisse werden in iframe ausgeführt
Technisch gesehen wird aus jedem der Kundenereignisse ein eigener iframe:
Die Tracking-Skripte werden in einer Sandbox ausgeführt, können also insbesondere den normalen Shop nicht mehr beeinträchtigen. Denn iframes sind komplett vom Shop-Code abgekapselt. JavaScript-Fehler oder CSS-Code haben keinen Einfluss auf den normalen Shop.
Mit dedizierten Apps kann der GTM injiziert werden. Unsere Wahl dafür ist die App „Stape Server GTM“ (auch einsetzbar ohne Server Side GTM).
Nach Installation und Aktivieren im Theme trägt man den GTM-Code ein:
Um den passenden dataLayer zu erhalten, aktiviert man im Tab „Data Layer“ die Checkbox:
Statt einer App kann man den GTM auch direkt ins Theme integrieren:
Im Checkout gibt es nur die Möglichkeit der Kundenereignisse. Aber im Shop selbst hat man die Wahl. Deshalb:
Unsere Einschätzung
Innerhalb des Shops die Stape-App verwenden. Die GTM-Vorschau funktioniert und man hat gleich den passenden dataLayer.
Im Checkout die Kundenereignisse verwenden. Sicherstellen, dass der GTM nur innerhalb des Checkouts ausgeführt wird.
Diesen Code in die Kundenereignisse einfügen.
Wichtig: Dies ist nur der Code für den Checkout. Für die restlichen Shop empfehlen wir die Implementierung von GTM und dataLayer via Stape-App (siehe oben).
if (init.context.document.location.href.indexOf("/checkouts/") > -1) {
// GTM + context
// hier GTM einfügen
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'context_data',
fired_from: 'customer_event',
page_location: init.context.document.location.href,
page_referrer: init.context.document.referrer,
page_title: init.context.document.title,
page_path: init.context.document.location.pathname,
search_param: init.context.document.location.search,
hash_param: init.context.document.location.hash,
language: init.context.navigator.language,
screen_width: init.context.window.outerWidth,
screen_height: init.context.window.outerHeight,
user_agent: init.context.navigator.userAgent,
});
analytics.subscribe("page_viewed", (event) => {
window.dataLayer.push({
event: "page_view",
fired_from: 'customer_event',
timestamp: event.timestamp,
id: event.id,
url: event.context.document.location.href,
page_path: init.context.document.location.pathname,
page_title: event.context.document.title,
});
});
analytics.subscribe("checkout_started", (event) => {
var data = event.data.checkout.lineItems;
var cb_items = data.map((eachItem) => {
var item_started = {
item_id: eachItem.id,
item_name: eachItem.title,
item_variant: eachItem?.variant.title,
item_variant_id: eachItem?.variant.id,
item_sku: eachItem?.variant.sku,
currency: eachItem.variant.price.currencyCode,
item_brand: eachItem.variant.product.vendor,
price: eachItem.variant.price.amount,
quantity: eachItem.quantity,
}
return item_started;
});
window.dataLayer.push({
event: "begin_checkout",
fired_from: 'customer_event',
timestamp: event.timestamp,
id: event.id,
token: event.data?.checkout?.token,
ecommerce: {
currency: event.data?.checkout?.currencyCode,
value: event.data?.checkout?.totalPrice?.amount,
items: cb_items
},
});
});
analytics.subscribe("checkout_completed", (event) => {
var data = event.data.checkout.lineItems;
var cb_remarketing_items = data.map((eachItem) => {
var item_remarketing = {
id: "shopify_DE_" + eachItem.variant.id + "_" + eachItem.variant.product.id,
google_business_vertical: 'retail'
};
return item_remarketing;
});
var cb_items = data.map((eachItem) => {
var item_purchase = {
item_id: eachItem.id,
item_name: eachItem.title,
item_variant: eachItem?.variant.title,
item_variant_id: eachItem?.variant.id,
item_sku: eachItem?.variant.sku,
currency: eachItem.variant.price.currencyCode,
item_brand: eachItem.variant.product.vendor,
price: eachItem.variant.price.amount,
quantity: eachItem.quantity,
}
return item_purchase;
});
cb_first_name = "";
cb_last_name = "";
cb_city = "";
cb_postal_code = "";
cb_country = "";
if (event.data.checkout.shippingAddress != null) {
cb_first_name = event.data.checkout.shippingAddress.firstName;
cb_last_name = event.data.checkout.shippingAddress.lastName;
cb_city = event.data.checkout.shippingAddress.city;
cb_postal_code = event.data.checkout.shippingAddress.zip;
cb_country = event.data.checkout.shippingAddress.country;
}
function format_phone(phone) {
var standardCountryCode = '+49';
if (!phone) {
return undefined;
}
var countryCodeNoPlus = standardCountryCode.replace('+', '');
phone = phone.replace(/[^\d+]/g, '');
if (phone.startsWith('+') && !phone.startsWith(standardCountryCode)) {
return phone;
} else if (phone.startsWith('00') && !phone.startsWith('00' + countryCodeNoPlus)) {
return '+' + phone.substr(2);
}
if (!phone.startsWith(standardCountryCode) &&
!phone.startsWith('00' + countryCodeNoPlus) &&
phone.startsWith('0')) {
phone = phone.substr(1);
}
if (phone.startsWith(standardCountryCode)) {
return phone;
} else if (phone.startsWith('00' + countryCodeNoPlus)) {
return standardCountryCode + phone.substr(2 + countryCodeNoPlus.length);
} else {
return standardCountryCode + phone;
}
}
cb_phone = format_phone(event.data.checkout.shippingAddress.phone);
window.dataLayer.push({
event: "purchase",
fired_from: 'customer_event',
timestamp: event.timestamp,
id: event.id,
token: event.data?.checkout?.token,
url: event.context.document.location.href,
user_data: {
"email": event.data.checkout.email,
"phone_number": cb_phone,
"address": {
"first_name": cb_first_name,
"last_name": cb_last_name,
"city": cb_city,
"postal_code": cb_postal_code,
"country": cb_country
}
},
remarketing_items: cb_remarketing_items,
ecommerce: {
currency: event.data?.checkout?.totalPrice.currencyCode,
value: event.data?.checkout?.totalPrice.amount,
transaction_id: event.data?.checkout?.order?.id || event.data?.checkout.token,
shipping: event.data?.checkout?.shippingLine?.price.amount || event.data?.checkout.shipping_line?.price.amount || 0,
tax: event.data?.checkout?.totalTax?.amount || 0,
items: cb_items,
coupon: event.data?.checkout?.discountApplications?.[0]?.title || "",
discount_amount: event.data?.checkout?.lineItems?.reduce((sum, item) => {
const itemDiscount = item.discountAllocations?.reduce((a, d) => {
return a + (parseFloat(d.amount?.amount) || 0);
}, 0);
return sum + itemDiscount;
}, 0) || 0
},
new_customer: event.data?.checkout?.order?.customer?.isFirstOrder || false,
voucher_code: event.data?.checkout?.discountApplications?.[0]?.code || "",
});
});
analytics.subscribe("payment_info_submitted", (event) => {
window.dataLayer.push({
event: "payment_info_submitted",
fired_from: 'customer_event',
timestamp: event.timestamp,
id: event.id,
token: event.data?.checkout?.token,
url: event.context.document.location.href,
});
});
analytics.subscribe("checkout_address_info_submitted", (event) => {
window.dataLayer.push({
event: "checkout_address_info_submitted",
fired_from: 'customer_event',
timestamp: event.timestamp,
id: event.id,
token: event.data?.checkout?.token,
url: event.context.document.location.href,
});
});
analytics.subscribe("checkout_contact_info_submitted", (event) => {
window.dataLayer.push({
event: "checkout_contact_info_submitted",
fired_from: 'customer_event',
timestamp: event.timestamp,
id: event.id,
token: event.data?.checkout?.token,
});
});
}
Shopify macht einem die Qualitätssicherung des Trackings leider unnötig kompliziert.
Da der GTM in einem iframe integriert ist (siehe Hintergrundinformationen oben), lädt die Vorschau des Tag Managers nicht. Wenn man den GTM, wie oben empfohlen, innerhalb des Shops über die App von Stape integriert, tritt das Problem dort nicht auf.
Im Checkout – und insbesondere auf der Danke-Seite – kann keine Qualitätssicherung des GTM durchführen. Die Vorschau lädt einfach nicht.
Man kann sich jedoch eine eigene Vorschau innerhalb der Browser-Konsole erstellen. Dann wird wenigstens der Inhalt des dataLayer zum jeweiligen Zeitpunkt ausgegeben:
Hierzu ergänzt man bei allen Events einen Parameter wie fired_from = customer_event
. In unserem JavaScript-Code (siehe oben) ist dies schon vorhanden.
Im GTM erstellt man folgendes Tag:
<script>
console.log("__Shopify dataLayer", {"event": {{Event}}, "dataLayer": {{latest dataLayer}} })
</script>
Der Code für die Variable latest dataLayer
lautet:
function() {
return {{dataLayer}}[{{dataLayer}}.length-1];
}
Und die Variable dataLayer
ist einfach definiert als:
Im Server-GTM kann man Daten nicht nur an GA4, Meta Ads, Google Ads, usw. senden. Sondern auch an eine Google-Sheets-Datei. In diesem Beispiel fügen wir bei jedem Kauf eine weitere Zeile mit Informationen zum Käufer (wie die Transaktions-ID, Umsatz, Cookie-Werte und gemachte Angaben) zum Google Sheet hinzu:
Auf diese Weise kann man sicherstellen, dass alle Daten, die an die Tool übergeben werden, auch korrekt sind. Im obigen Beispiel fällt auch, das in der vorletzten Zeile eine Transaktion doppelt gemessen wurde. Ohne das Google Sheets wäre dieser Fehler wahrscheinlich nicht ausgefallen.
Aus Tracking-Sicht sind diese die wichtigsten Anforderungen an das Consent-Tool:
Unser Empfehlung ist Pandectes. Vor allem der schnelle Support zeichnet das Tool aus
Über den Autor
Julian Kleinknecht ist Geschäftsführer bei ConversionBoosting und unterstützt Unternehmen seit mehr als 14 Jahren bei Webanalyse und Tracking. Er teilt Erkenntnisse hier, auf LinkedIn und auf YouTube.