TL;DR
Birden fazla GTM container kullanmak 2015’ten beri resmi olarak destekleniyor. Ancak tüm container’lar aynı dataLayer’ı paylaşmalı. Farklı dataLayer isimleri kullanmak trigger sorunlarına ve veri kaybına yol açar. Modern GTM kurulumlarında Consent Mode v2 (GDPR/KVKK), Server-side tagging ve GA4 event schema zorunlu bileşenler haline geldi.
| Konu | 2019 Yaklaşımı | 2025+ Güncel Durum |
|---|---|---|
| dataLayer | Her GTM için farklı isim | Tek dataLayer zorunlu |
| Instantiation | dataLayer = [{...}] | window.dataLayer = window.dataLayer || [] |
| Analytics | Universal Analytics | GA4 (UA deprecated) |
| Privacy | Opsiyonel | Consent Mode v2 zorunlu |
| Tagging | Client-side only | Server-side tercih |
Neden Çoklu GTM Gerekir?
Çoğu durumda tek GTM container en iyi çözümdür. Ancak şu senaryolarda birden fazla container kaçınılmaz olabilir:
- Farklı ekipler/ajanslar: Reklam ajansı kendi tag’lerini yönetmek istiyor
- Erişim kontrolü: Bazı tag’lere sadece belirli kişilerin erişimi olmalı
- Multi-tenant yapılar: Aynı domain’de farklı iş birimlerinin bağımsız tracking ihtiyacı
- Vendor gereksinimleri: Üçüncü parti yazılımlar kendi GTM’lerini zorunlu kılıyor
Önemli: Ajans veya vendor’ın kendi GTM container’ını kurmasını istemesi durumunda, önce sizin GTM’nize erişim vermek tercih edilmeli. Bu sayede değişiklikler üzerinde tam görünürlük sağlanır.
dataLayer: Eski vs Güncel Yaklaşım
Eski Yaklaşım (2019)
2019’daki öneri: Her GTM container için farklı dataLayer ismi kullanılabilir. Örneğin birinci container
dataLayer, ikinci containerveriKatmanikullanabilir.
<!-- 2019: Farklı dataLayer isimleri (ARTIK ÖNERİLMİYOR) -->
<script>(...,'dataLayer','GTM-XXXX');</script>
<script>(...,'veriKatmani','GTM-YYYY');</script>
Güncel Yaklaşım (2025+)
Google’ın güncel dokümantasyonu açıkça belirtiyor:
“Using more than one data layer can cause some triggers to stop working and could have other implications.” Kaynak: Google Tag Manager Developer Guide
Tüm container’lar aynı dataLayer’ı paylaşmalı:
<!-- Doğru: Tek dataLayer, çoklu container -->
<script>
window.dataLayer = window.dataLayer || [];
</script>
<!-- GTM Container 1 -->
<script>(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-XXXX');</script>
<!-- GTM Container 2 -->
<script>(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-YYYY');</script>
dataLayer Instantiation
Eski yöntem (sorunlu):
dataLayer = [{'pageTitle': 'Anasayfa'}];Bu kullanım mevcut dataLayer’ı tamamen siler.
Doğru yöntem:
// Güvenli instantiation - mevcut veriyi korur
var dataLayer = window.dataLayer = window.dataLayer || [];
// Veri ekleme her zaman push() ile
dataLayer.push({
'pageTitle': 'Anasayfa',
'pageType': 'home'
});
Çoklu Container’da Dikkat Edilmesi Gerekenler
1. Ortak dataLayer = Ortak Event’ler
Tüm container’lar aynı dataLayer’ı paylaştığı için, bir container’ın push ettiği event diğer container’lar tarafından da görülür. Bu durum:
Avantaj: Veri tutarlılığı sağlar Risk: İstenmeyen tag tetiklenmeleri olabilir
Çözüm: Event isimlerini spesifik tutun. gaEvent yerine agency_remarketing_click gibi benzersiz isimler kullanın.
2. Event Naming Convention
// ❌ Yanlış: Generic event ismi
dataLayer.push({ 'event': 'click' });
// ✅ Doğru: Spesifik ve namespace'li
dataLayer.push({ 'event': 'brand_cta_click' });
dataLayer.push({ 'event': 'agency_form_submit' });
3. PII (Kişisel Veri) Riski
Ortak dataLayer’da push edilen tüm veriler tüm container’lara açıktır. Bir container PII (isim, e-posta, telefon) push ederse, diğer container’lar da bu veriye erişebilir.
// ⚠️ Dikkat: Bu veri TÜM container'lara görünür
dataLayer.push({
'event': 'form_submit',
'userEmail': 'user@example.com', // PII!
'userName': 'John Doe' // PII!
});
Consent Mode v2 Entegrasyonu
GDPR, KVKK ve diğer gizlilik düzenlemeleri için Consent Mode v2 artık zorunlu.
Temel Kurulum
// GTM snippet'inden ÖNCE
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
// Varsayılan consent durumu (kullanıcı izni öncesi)
gtag('consent', 'default', {
'ad_storage': 'denied',
'ad_user_data': 'denied',
'ad_personalization': 'denied',
'analytics_storage': 'denied'
});
// Kullanıcı izin verdikten sonra güncelleme
gtag('consent', 'update', {
'ad_storage': 'granted',
'ad_user_data': 'granted',
'ad_personalization': 'granted',
'analytics_storage': 'granted'
});
Bölgesel Consent Ayarları
// AB kullanıcıları için varsayılan denied
gtag('consent', 'default', {
'ad_storage': 'denied',
'analytics_storage': 'denied',
'region': ['AT', 'BE', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE',
'FI', 'FR', 'DE', 'GR', 'HU', 'IE', 'IT', 'LV',
'LT', 'LU', 'MT', 'NL', 'PL', 'PT', 'RO', 'SK',
'SI', 'ES', 'SE']
});
// Diğer bölgeler için granted
gtag('consent', 'default', {
'ad_storage': 'granted',
'analytics_storage': 'granted'
});
GA4 Event Schema (Enhanced Ecommerce Yerine)
Eski yaklaşım (Universal Analytics Enhanced Ecommerce):
dataLayer.push({ 'event': 'addToCart', 'ecommerce': { 'currencyCode': 'TRY', 'add': { 'products': [{ 'id': '123', 'name': 'Ürün', 'price': 99.90 }] } } });
GA4 Ecommerce Event Schema:
dataLayer.push({ ecommerce: null }); // Önceki ecommerce verisini temizle
dataLayer.push({
'event': 'add_to_cart',
'ecommerce': {
'currency': 'TRY',
'value': 99.90,
'items': [{
'item_id': '123',
'item_name': 'Ürün Adı',
'item_brand': 'Marka',
'item_category': 'Kategori',
'price': 99.90,
'quantity': 1
}]
}
});
GA4 Standart Event’leri
| Event | Açıklama |
|---|---|
view_item | Ürün detay sayfası görüntüleme |
add_to_cart | Sepete ekleme |
remove_from_cart | Sepetten çıkarma |
begin_checkout | Checkout başlatma |
add_payment_info | Ödeme bilgisi girişi |
add_shipping_info | Kargo bilgisi girişi |
purchase | Satın alma tamamlama |
Server-Side GTM
2025’te Server-side GTM enterprise projeler için standart haline geldi.
Avantajları
- Performans: Client-side script yükü azalır
- Gizlilik: First-party context’te veri işleme
- Ad-blocker bypass: Server-side istekler bloklanmaz
- Veri kontrolü: PII maskeleme ve filtreleme
Temel Mimari
[Browser] → [Client-side GTM] → [Server-side GTM Container] → [GA4, Ads, Meta...]
↓
[First-party domain]
Platform Entegrasyonları: Shopify
Shopify, GTM’yi Custom Pixel olarak sandbox ortamında çalıştırır. Bu yapı güvenlik sağlar ancak bazı kısıtlamalar getirir.
Önemli: Shopify’da GTM kurulumu ileri düzey JavaScript bilgisi gerektirir. Custom pixel’ler Shopify tarafından desteklenmez, sorun çözümü sizin sorumluluğunuzdadır.
Shopify Sandbox Kısıtlamaları
- DOM’a doğrudan erişim sınırlı
document.cookieerişimi yoklocalStorage/sessionStoragesınırlı- Üçüncü parti script’ler sandbox içinde çalışır
GTM Custom Pixel Kurulumu
// dataLayer ve gtag tanımı
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
// GTM snippet (HTML tag'leri olmadan)
(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');
// Consent Mode v2
gtag('consent', 'update', {
'ad_storage': 'granted',
'analytics_storage': 'granted',
'ad_user_data': 'granted',
'ad_personalization': 'granted',
});
Shopify Event’lerini GTM’ye Aktarma
Shopify’ın analytics.subscribe() API’si ile standart event’leri dinleyip dataLayer’a push edebilirsiniz:
// Sayfa görüntüleme
analytics.subscribe("page_viewed", (event) => {
window.dataLayer.push({
event: "page_viewed",
timestamp: event.timestamp,
client_id: event.clientId,
url: event.context.document.location.href,
page_title: event.context.document.title,
});
});
// Ürün görüntüleme
analytics.subscribe("product_viewed", (event) => {
window.dataLayer.push({
event: "product_viewed",
timestamp: event.timestamp,
client_id: event.clientId,
url: event.context.document.location.href,
product_id: event.data?.productVariant?.product?.id,
product_title: event.data?.productVariant?.title,
product_sku: event.data?.productVariant?.sku,
});
});
// Sepete ekleme
analytics.subscribe("product_added_to_cart", (event) => {
window.dataLayer.push({
event: "product_added_to_cart",
timestamp: event.timestamp,
client_id: event.clientId,
url: event.context.document.location.href,
price: event.data?.cartLine?.merchandise?.price?.amount,
product_title: event.data?.cartLine?.merchandise?.product?.title,
quantity: event.data?.cartLine?.quantity,
total_cost: event.data?.cartLine?.cost?.totalAmount?.amount,
});
});
// Checkout tamamlama
analytics.subscribe("checkout_completed", (event) => {
window.dataLayer.push({
event: "checkout_completed",
timestamp: event.timestamp,
token: event.data?.checkout?.token,
client_id: event.clientId,
email: event.data?.checkout?.email,
orderId: event.data?.checkout?.order?.id,
currency: event.data?.checkout?.currencyCode,
value: event.data?.checkout?.totalPrice?.amount,
tax: event.data?.checkout?.totalTax?.amount,
shipping: event.data?.checkout?.shippingLine?.price?.amount,
});
});
Shopify → GA4 Event Mapping
| Shopify Event | GTM Trigger | GA4 Event |
|---|---|---|
page_viewed | Custom Event | page_view |
product_viewed | Custom Event | view_item |
product_added_to_cart | Custom Event | add_to_cart |
product_removed_from_cart | Custom Event | remove_from_cart |
cart_viewed | Custom Event | view_cart |
checkout_started | Custom Event | begin_checkout |
checkout_address_info_submitted | Custom Event | add_shipping_info |
payment_info_submitted | Custom Event | add_payment_info |
checkout_completed | Custom Event | purchase |
Eski dataLayer.push Kodlarını Migrate Etme
Eski yöntem (theme.liquid içinde):
<script> dataLayer.push({ event: 'email_signup', email: customer.email }); </script>
Yeni yöntem (Shopify.analytics.publish ile):
<!-- theme.liquid içinde -->
<script>
Shopify.analytics.publish('email_signup', { email: customer.email });
</script>
// Custom pixel içinde
analytics.subscribe("email_signup", (event) => {
window.dataLayer.push({
'event': 'email_signup',
'email': event.customData.email,
});
});
GTM’de Trigger Kurulumu
Her Shopify event’i için GTM’de Custom Event trigger oluşturun:
- Triggers → New → Custom Event
- Event name:
checkout_completed(veya ilgili event) - This trigger fires on: All Custom Events
- Tag’i bu trigger’a bağlayın
GA4 Tag Konfigürasyonu
Tag Type: Google Analytics: GA4 Event
Measurement ID: G-XXXXXXXX
Event Name: purchase (veya ilgili GA4 event)
Event Parameters:
- transaction_id: {{DLV - orderId}}
- value: {{DLV - value}}
- currency: {{DLV - currency}}
- items: {{DLV - items}}
Test: Shopify Pixel Helper ve Google Tag Assistant birlikte kullanın. Tag Assistant’ın “Troubleshoot tag” özelliği sandbox içindeki pixel’leri algılamaz, dataLayer’ı manuel kontrol edin.
noscript Tag’leri
Her GTM container için noscript tag’i de eklenmelidir:
<!-- GTM Container 1 noscript -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- GTM Container 2 noscript -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-YYYY"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
Test ve Debug
GTM Preview Mode
Her iki container için de ayrı ayrı Preview Mode aktif edilmeli:
- GTM-XXXX için Preview başlat
- GTM-YYYY için ayrı sekmede Preview başlat
- Hedef sayfada her iki debug panel’i kontrol et
Tag Assistant
Google Tag Assistant ile:
- Hangi tag’lerin tetiklendiğini
- dataLayer içeriğini
- Consent durumunu kontrol edin
Container ID ile Debug
// Belirli container'ın durumunu kontrol
console.log(window.google_tag_manager['GTM-XXXX']);
console.log(window.google_tag_manager['GTM-YYYY']);
Yaygın Hatalar ve Çözümleri
| Hata | Sebep | Çözüm |
|---|---|---|
| Trigger’lar çalışmıyor | Farklı dataLayer isimleri | Tek dataLayer kullan |
| Veri kaybı | dataLayer = [] kullanımı | window.dataLayer = window.dataLayer || [] |
| Duplicate event’ler | Generic event isimleri | Namespace’li isimler kullan |
| PII sızıntısı | Ortak dataLayer’da hassas veri | Veriyi sunucu tarafında işle |
| Consent ihlali | Consent Mode eksik | Consent Mode v2 entegre et |
Kaynaklar
- Google Tag Manager Data Layer Documentation
- Consent Mode Implementation Guide
- GA4 Ecommerce Events Reference
- Server-side Tagging Guide
- Shopify GTM Custom Pixel Tutorial
- 01 Tüm GTM container'ları tek dataLayer paylaşmalı
- 02 dataLayer instantiation: window.dataLayer = window.dataLayer || []
- 03 Consent Mode v2 GDPR/KVKK için zorunlu
- 04 Server-side GTM performans ve gizlilik için tercih edilmeli
- 05 GA4 event-driven model, Universal Analytics deprecated
+ Birden fazla GTM container kullanabilir miyim?
Evet, 2015'ten beri resmi olarak destekleniyor. Ancak tüm container'lar aynı dataLayer'ı paylaşmalı.
+ Her GTM için farklı dataLayer kullanmalı mıyım?
Hayır. Google'ın güncel önerisi tüm container'ların tek dataLayer kullanmasıdır. Farklı dataLayer'lar trigger sorunlarına yol açabilir.
+ Consent Mode v2 nedir ve neden gerekli?
GDPR/KVKK uyumluluğu için zorunlu olan kullanıcı onay yönetim sistemidir. Tag'lerin kullanıcı iznine göre çalışmasını sağlar.
+ Server-side GTM kullanmalı mıyım?
Performans, gizlilik ve ad-blocker bypass için önerilir. Özellikle enterprise projeler için 2025'te standart haline geldi.
+ Shopify'da GTM nasıl kurulur?
Custom Pixel olarak kurulur. Sandbox ortamında çalışır, analytics.subscribe() ile Shopify event'leri dinlenir ve dataLayer'a push edilir.