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’inize 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.” — 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, email, 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’i 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’e 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.