Çoklu Google Tag Manager (GTM) Kurulumu

Birden fazla GTM container kullanırken dikkat edilmesi gereken kritik noktalar, dataLayer yönetimi, Consent Mode v2 ve modern best practice'ler.

Ceyhun Enki Aksan
Ceyhun Enki Aksan Girişimci, Maker

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.

Konu2019 Yaklaşımı2025+ Güncel Durum
dataLayerHer GTM için farklı isimTek dataLayer zorunlu
InstantiationdataLayer = [{...}]window.dataLayer = window.dataLayer || []
AnalyticsUniversal AnalyticsGA4 (UA deprecated)
PrivacyOpsiyonelConsent Mode v2 zorunlu
TaggingClient-side onlyServer-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
dikkat

Ö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 container veriKatmani kullanabilir.

<!-- 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

öneri

Çö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!
});

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'
});
// 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

EventAçıklama
view_itemÜrün detay sayfası görüntüleme
add_to_cartSepete ekleme
remove_from_cartSepetten çıkarma
begin_checkoutCheckout başlatma
add_payment_infoÖdeme bilgisi girişi
add_shipping_infoKargo bilgisi girişi
purchaseSatı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.

dikkat

Ö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.cookie erişimi yok
  • localStorage / sessionStorage sı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 EventGTM TriggerGA4 Event
page_viewedCustom Eventpage_view
product_viewedCustom Eventview_item
product_added_to_cartCustom Eventadd_to_cart
product_removed_from_cartCustom Eventremove_from_cart
cart_viewedCustom Eventview_cart
checkout_startedCustom Eventbegin_checkout
checkout_address_info_submittedCustom Eventadd_shipping_info
payment_info_submittedCustom Eventadd_payment_info
checkout_completedCustom Eventpurchase

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:

  1. TriggersNewCustom Event
  2. Event name: checkout_completed (veya ilgili event)
  3. This trigger fires on: All Custom Events
  4. 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}}
öneri

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:

  1. GTM-XXXX için Preview başlat
  2. GTM-YYYY için ayrı sekmede Preview başlat
  3. 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

HataSebepÇözüm
Trigger’lar çalışmıyorFarklı dataLayer isimleriTek dataLayer kullan
Veri kaybıdataLayer = [] kullanımıwindow.dataLayer = window.dataLayer || []
Duplicate event’lerGeneric event isimleriNamespace’li isimler kullan
PII sızıntısıOrtak dataLayer’da hassas veriVeriyi sunucu tarafında işle
Consent ihlaliConsent Mode eksikConsent Mode v2 entegre et

FAQ

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 ve veri kaybına yol açabilir.

dataLayer’ı yeniden adlandırabilir miyim?

Teknik olarak mümkün ancak önerilmiyor. Yeniden adlandırma sadece çok spesifik edge-case’lerde düşünülmeli.

GDPR, KVKK ve benzeri düzenlemelere tabi siteler için evet. Ayrıca Google Ads conversion tracking için de gerekli.

Server-side GTM ne zaman kullanmalıyım?

Performans kritik projelerde, PII işleme gerektiğinde ve ad-blocker’lardan etkilenen yüksek trafikli sitelerde tercih edilmeli.

Universal Analytics event’lerini GA4’e nasıl migrate ederim?

Enhanced Ecommerce schema’sını GA4 event schema’sına dönüştürün. addToCartadd_to_cart, productsitems gibi mapping’ler gerekli.

Shopify’da GTM nasıl kurulur?

Custom Pixel olarak kurulur. SettingsCustomer eventsAdd custom pixel yolunu izleyin. GTM kodu HTML tag’leri olmadan eklenir ve analytics.subscribe() ile Shopify event’leri dinlenerek dataLayer’a push edilir.

Shopify sandbox kısıtlamaları nelerdir?

DOM’a doğrudan erişim sınırlı, document.cookie erişimi yok, localStorage/sessionStorage kısıtlı. GTM’in bazı özellikleri (scroll tracking, click tracking) sandbox’ta çalışmayabilir.


Key Takeaways

  1. Tek dataLayer kullan — Tüm GTM container’ları aynı dataLayer’ı paylaşmalı
  2. Güvenli instantiationwindow.dataLayer = window.dataLayer || [] kullan
  3. Spesifik event isimleri — Namespace’li, benzersiz event isimleri tercih et
  4. Consent Mode v2 — GDPR/KVKK uyumu için zorunlu
  5. GA4 schema — Universal Analytics deprecated, GA4 event’lerine geç
  6. Server-side düşün — Performans ve gizlilik için server-side GTM değerlendir
  7. Test, test, test — Her değişikliği Preview Mode ve Tag Assistant ile doğrula

Kaynaklar