Da biste dodali data layer na Shopify Plus, instalirajte Google Tag Manager u theme.liquid i iz teme šaljite GA4 ecommerce događaje na stranicama prodavnice, a zatim u Settings > Customer events dodajte custom pixel koji GTM-u šalje događaje iz checkouta i kupovine. Kod teme se ne izvršava u checkoutu, pa piksel pokriva sve od begin_checkout do purchase.
Vodič prolazi kroz šest koraka sa kodom koji možete da prilagodite, a zatim kroz testiranje i česte greške. Zašto su šema događaja, imenovanje i pravila saglasnosti baš ovakvi, objašnjavamo u tekstu najbolje prakse za Shopify Plus data layer.
Šta vam treba pre početka?
- Odluka o aplikaciji Google & YouTube. Aplikacija već šalje
view_item,add_to_cart,begin_checkout,purchasei druge događaje u GA4 (Google). Ako ostane povezana sa GA4, ne šaljite iste događaje u isti GA4 property iz GTM-a, jer će se kupovine brojati dva puta. - Dva GTM web containera, jedan za temu i jedan za custom pixel. Ovo je naša preporuka, a ne Shopify pravilo: tako se okidači iz prodavnice ne aktiviraju u sandboxu piksela.
- Podešena customer privacy podešavanja i cookie banner u Shopify-u.
- Kopija aktivne teme. U Online Store > Themes kliknite ... pored teme, izaberite Duplicate i radite na kopiji.
Korak 1: Kako da instalirate GTM sa podrazumevanom saglasnošću?
Otvorite kopiju teme preko ... > Edit code. Napravite snippet data-layer.liquid (popunićete ga u koraku 2). U layout/theme.liquid ga ubacite unutar <head>, posle {{ content_for_header }}, a odmah iza njega nalepite head deo GTM container koda iz Admin > Install Google Tag Manager:
{{ content_for_header }}
{% render 'data-layer' %}
<!-- Google Tag Manager container code from GTM goes here -->
Redosled je bitan. Google podrazumevane vrednosti saglasnosti moraju da se izvrše pre bilo kog taga (Google), a snippet koristi window.Shopify, koji učitava content_for_header.
Korak 2: Kako iz teme da šaljete saglasnost, kontekst stranice i dodavanje u korpu?
Nalepite ovaj kod u snippets/data-layer.liquid. On sve signale saglasnosti postavlja na denied, a zatim ih ažurira iz Shopify Customer Privacy API-ja, koji kombinuje vaša podešavanja privatnosti, lokaciju posetioca i njegov izbor. Osim toga, šalje kontekst stranice i definiše pomoćnu funkciju za add_to_cart.
<script>
window.dataLayer = window.dataLayer || [];
function gtag() { dataLayer.push(arguments); }
// 1. Consent defaults, before GTM loads
gtag('consent', 'default', {
analytics_storage: 'denied',
ad_storage: 'denied',
ad_user_data: 'denied',
ad_personalization: 'denied'
});
// 2. Real status from Shopify's Customer Privacy API
function sendConsent() {
var privacy = window.Shopify && window.Shopify.customerPrivacy;
if (!privacy) return;
var marketing = privacy.marketingAllowed() ? 'granted' : 'denied';
gtag('consent', 'update', {
analytics_storage: privacy.analyticsProcessingAllowed() ? 'granted' : 'denied',
ad_storage: marketing,
ad_user_data: marketing,
ad_personalization: marketing
});
}
if (window.Shopify && window.Shopify.loadFeatures) {
window.Shopify.loadFeatures(
[{ name: 'consent-tracking-api', version: '0.2' }],
function (error) { if (!error) sendConsent(); }
);
}
document.addEventListener('visitorConsentCollected', sendConsent);
// 3. Page context (no personal data)
dataLayer.push({
page_type: {{ request.page_type | json }},
language: {{ request.locale.iso_code | json }},
currency: {{ cart.currency.iso_code | json }},
customer_logged_in: {% if customer %}true{% else %}false{% endif %}
});
// 4. Helper for add_to_cart, called from your cart JavaScript
window.pushAddToCart = function (item, quantity) {
var price = item.final_price / 100;
dataLayer.push({ ecommerce: null });
dataLayer.push({
event: 'add_to_cart',
ecommerce: {
currency: {{ cart.currency.iso_code | json }},
value: price * quantity,
items: [{
item_id: String(item.sku || item.variant_id),
item_name: item.product_title,
item_variant: item.variant_title,
item_brand: item.vendor,
price: price,
quantity: quantity
}]
}
});
};
</script>
Filter json ispisuje bezbedne JavaScript stringove. Cene iz Ajax Cart API-ja su u najmanjoj jedinici valute, pa ih funkcija deli sa 100.
Korak 3: Kako da pošaljete view_item sa stranice proizvoda?
Napravite snippet data-layer-product.liquid sa kodom ispod i ubacite ga na kraj glavne sekcije proizvoda pomoću {% render 'data-layer-product', product: product %}. U temi Dawn to je sections/main-product.liquid. Online Store 2.0 teme nemaju fajl šablona product.liquid, pa tražite u folderu sections/.
{%- assign variant = product.selected_or_first_available_variant -%}
<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({ ecommerce: null });
dataLayer.push({
event: 'view_item',
ecommerce: {
currency: {{ cart.currency.iso_code | json }},
value: {{ variant.price | divided_by: 100.0 }},
items: [{
item_id: {{ variant.sku | default: variant.id | append: '' | json }},
item_name: {{ product.title | json }},
item_variant: {{ variant.title | json }},
item_brand: {{ product.vendor | json }},
item_category: {{ product.type | json }},
price: {{ variant.price | divided_by: 100.0 }},
quantity: 1
}]
}
});
</script>
Liquid cene su u najmanjoj jedinici valute (Shopify), zato divided_by: 100.0. Ovde ne koristite money filtere, jer vraćaju formatiran tekst. Događaj view_item_list na stranicama kolekcija pravi se na isti način, sa po jednim artiklom za svaki proizvod iz collection.products.
Korak 4: Kako da aktivirate add_to_cart iz koda korpe?
Teme dodaju proizvode u korpu na različite načine, pa window.pushAddToCart pozovite na mestu gde tema dobija uspešan odgovor od /cart/add.js. U temi Dawn to je skripta forme proizvoda. Odgovor je JSON dodate stavke korpe (Shopify):
const quantity = Number(formData.get('quantity') || 1);
fetch(window.Shopify.routes.root + 'cart/add.js', { method: 'POST', body: formData })
.then((response) => response.json())
.then((item) => {
if (item.status) return; // error response, nothing was added
window.pushAddToCart(item, quantity);
// ...the theme's own cart update code continues here
});
Prosledite količinu koju je posetilac izabrao, a ne onu iz odgovora: ako je artikal već bio u korpi, odgovor sadrži novu ukupnu količinu. Ako tema ima više načina dodavanja u korpu (quick add, upsell aplikacije), alternativa je da se umesto toga pretplatite na product_added_to_cart u pikselu iz koraka 5. Koristite jedan izvor, ne oba.
Korak 5: Kako da custom pixelom šaljete događaje iz checkouta i kupovine?
Shopify checkout, Thank you i Order status stranice više ne izvršavaju kod teme niti Additional scripts. Additional scripts i checkout.liquid su ugašeni na Thank you i Order status stranicama 28. avgusta 2025. (Shopify). Pikseli se učitavaju na svim ovim stranicama (Shopify Help Center). Piksel dodajete ovako (Shopify Help Center):
- Idite na Settings > Customer events i kliknite Add custom pixel.
- Unesite naziv, na primer "GTM checkout", i kliknite Add pixel.
- U delu Customer privacy postavite Permission na Required i izaberite svrhe koje vašim tagovima trebaju, najčešće Analytics i Marketing. Data sale podesite prema tagovima koje koristite.
- Nalepite kod ispod u prozor Code, sa ID-jem container-a za piksel umesto
GTM-XXXXXXX. - Kliknite Save, pa Connect pixel.
// Paste as JavaScript only: no <script> tags in a custom pixel
window.dataLayer = window.dataLayer || [];
function gtag() { dataLayer.push(arguments); }
// Consent mode from Shopify's privacy status
let privacy = init.customerPrivacy;
function sendConsent(mode) {
const marketing = privacy.marketingAllowed ? 'granted' : 'denied';
gtag('consent', mode, {
analytics_storage: privacy.analyticsProcessingAllowed ? 'granted' : 'denied',
ad_storage: marketing,
ad_user_data: marketing,
ad_personalization: marketing
});
}
sendConsent('default');
api.customerPrivacy.subscribe('visitorConsentCollected', (event) => {
privacy = event.customerPrivacy;
sendConsent('update');
});
// GTM loader (the head snippet from GTM, without the script tags)
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');
// Same item ID rule as the theme: SKU, else variant ID
function toItems(checkout) {
return checkout.lineItems.map((line, index) => ({
item_id: String(line.variant?.sku || line.variant?.id),
item_name: line.variant?.product?.title || line.title,
item_variant: line.variant?.title,
item_brand: line.variant?.product?.vendor,
price: Number(line.variant?.price?.amount),
quantity: line.quantity,
index: index
}));
}
// value = subtotal before shipping and tax; change it to match your definition
function pushCheckout(name, event, extra) {
const checkout = event.data.checkout;
dataLayer.push({ ecommerce: null });
dataLayer.push({
event: name,
page_location: event.context.window.location.href,
ecommerce: Object.assign({
currency: checkout.currencyCode,
value: Number(checkout.subtotalPrice?.amount),
items: toItems(checkout)
}, extra || {})
});
}
analytics.subscribe('checkout_started', (e) => pushCheckout('begin_checkout', e));
analytics.subscribe('checkout_shipping_info_submitted', (e) => pushCheckout('add_shipping_info', e));
analytics.subscribe('payment_info_submitted', (e) => pushCheckout('add_payment_info', e));
analytics.subscribe('checkout_completed', (e) => {
const checkout = e.data.checkout;
const codes = (checkout.discountApplications || [])
.filter((d) => d.type === 'DISCOUNT_CODE')
.map((d) => d.title);
pushCheckout('purchase', e, {
transaction_id: checkout.order?.id,
tax: Number(checkout.totalTax?.amount || 0),
shipping: Number(checkout.shippingLine?.price?.amount || 0),
coupon: codes.join(',')
});
});
Kako ovo radi: piksel se izvršava u sandboxed iframe-u, pa ima sopstveni window.dataLayer i ne može da čita niti menja vašu stranicu (Shopify). init.customerPrivacy i visitorConsentCollected drže consent mode usklađenim (Shopify). Putanje polja su iz dokumentacije za checkout_completed, a checkout_completed se aktivira jednom po checkoutu, na prvoj upsell stranici ako koristite post-purchase ponude. Pošto window.location u sandboxu nije URL vaše prodavnice, kod šalje page_location iz event.context, kako predlaže Shopify GTM vodič.
Imajte u vidu da Shopify ne pruža podršku za kod custom piksela, a isti vodič navodi da klikovi na spoljne linkove i drugi okidači zasnovani na DOM-u ne rade u sandboxu.
Korak 6: Kako da podesite GTM?
- Okidači: napravite Custom Event okidač za svaki naziv događaja:
view_itemiadd_to_cartu container-u teme;begin_checkout,add_shipping_info,add_payment_infoipurchaseu container-u piksela. - Google tag: u oba container-a dodajte GA4 measurement ID. U container-u piksela postavite konfiguracioni parametar
send_page_viewnafalse, jer tema već šalje preglede stranica, a URL iz sandboxa bi zagadio izveštaje. - Event tag: napravite tag Google Analytics: GA4 Event sa Event Name
{{Event}}. U More Settings > Ecommerce izaberite Send Ecommerce data i Data Source Data Layer, kako opisuje Google vodič. U container-u piksela dodajte parametar događajapage_locationiz Data Layer Variable. - Ostale promenljive: dodajte Data Layer Variable za
page_typeicustomer_logged_inako ih želite kao parametre. - Publish: svaki container objavite kao imenovanu verziju.
Kako da testirate podešavanje?
- Prodavnica: otvorite GTM Preview za container teme. Proverite da se
view_itempojavljuje na stranici proizvoda sa tačnom cenom i valutom, aadd_to_cartposle dodavanja proizvoda. - Checkout: opcija Troubleshoot tag u Tag Assistant-u ne prepoznaje Google tagove unutar custom piksela. Koristite Shopify Pixel Helper da vidite da događaji stižu do piksela (Shopify Help Center), a GA4 DebugView da vidite šta stiže u GA4.
- Test porudžbina: napravite porudžbinu u test režimu vašeg provajdera plaćanja. Potvrdite jedan
purchasesatransaction_id,value,currencyiitems, i proverite da li se događaji iz checkouta nastavljaju u istoj GA4 sesiji kao događaji iz prodavnice. - Posle lansiranja: prve nedelje svakog dana uporedite kupovine u GA4 sa Shopify porudžbinama, a zatim jednom nedeljno.
Koje su najčešće greške?
| Greška | Rešenje |
|---|---|
| Kod za kupovinu ostao u Additional scripts | Više se ne izvršava na Thank you stranici. Prebacite ga u custom pixel. |
Universal Analytics objekti (ecommerce.detail, actionField, transactionTotal) | Napravite ih ponovo sa GA4 nazivima događaja i nizom items. |
| Automatski pregledi stranica ostali uključeni u container-u piksela | Tamo postavite send_page_view na false. Preglede stranica šalje container teme. |
Cene ispisane money filterima | Za brojčane vrednosti koristite divided_by: 100.0. |
| Različiti ID-jevi artikala u temi i pikselu | Na oba mesta koristite isto pravilo: SKU ili ID varijante. |
| Isti container ID u temi i pikselu, sa All Pages okidačima | Koristite poseban container za piksel ili ograničite njegove okidače na nazive događaja iz checkouta. |
Većina prodavnica može da prati ove korake bez izmena. Ako vaša ima prilagođenu korpu, više aplikacija u checkoutu ili praćenje koje se već ne slaže sa brojem porudžbina u Shopify-u, možemo da ga postavimo i testiramo umesto vas u okviru usluge prilagođavanja Shopify Plus checkouta.
FAQ
Gde se u Shopify-u stavlja kod za data layer?
Kod za prodavnicu ide u temu: snippet koji se ubacuje u layout/theme.liquid za podatke na celom sajtu i snippet u glavnoj sekciji proizvoda za podatke o proizvodu. Kod za checkout i kupovine ide u custom pixel u Settings > Customer events.
Mogu li da pratim kupovine iz teme?
Ne. Thank you i Order status stranice su deo Shopify checkouta i ne učitavaju fajlove teme. Umesto toga se pretplatite na checkout_completed u pikselu.
Da li GTM Preview mode radi za custom pixel?
Shopify vodič ne opisuje GTM Preview za piksele, a opcija Troubleshoot tag u Tag Assistant-u ne može da prepozna Google tagove unutar piksela. Shopify preporučuje Pixel Helper. Kombinujte ga sa GA4 DebugView.
Da li mi za ovo treba Shopify Plus?
Ne. Data layer u temi i custom pikseli rade i na drugim planovima. Plus dodaje checkout UI ekstenzije na koracima information, shipping i payment, koje mogu da šalju dodatne sopstvene događaje vašem pikselu (Shopify).
Zašto GA4 pokazuje manje kupovina od Shopify-a?
Posetioci koji odbiju saglasnost, blokatori oglasa i zaštita od praćenja u pregledačima uklanjaju događaje koje Shopify i dalje beleži kao porudžbine. Stabilna razlika je normalna. Nagla promena obično znači pokvaren snippet, isključen piksel ili duplog pošiljaoca.
Skalirate se na Shopify Plus-u?
Migracija, B2B, arhitektura, performanse — vodimo angažmane koje druge agencije vraćaju.
Checklista koju prolazimo pre nego što dotaknemo kod klijenta
Stiže vam na email, uz nekoliko kratkih poruka u naredne dve nedelje: šta najčešće vidimo na Shopify prodavnicama i šta zaista pomaže.
Želite više naših tekstova u Google pretrazi? Dodajte Codersy kao željeni izvor.
Dodaj Codersy na Google(otvara se u novom prozoru)
