# Veri Katmanı (Data Layer)

window.selwiseLayer ve otomatik event takibi
Kaynak: https://selwise.com/docs/integration/data-layer

Veri Katmanı, Google Tag Manager'a benzer bir **push tabanlı** event katmanıdır. `window.selwiseLayer` dizisine event nesneleri ekleyerek, kod yazmadan veya minimum kodla e-ticaret olaylarını Selwise'a bildirirsiniz.

İki çalışma modu vardır ve ikisi aynı anda kullanılabilir:

1. **Otomatik** — Selwise sayfayı analiz eder ve sayfa/ürün/sepet event'lerini kendiliğinden yakalar.
2. **Manuel push** — `window.selwiseLayer.push({ ... })` ile event'i siz gönderirsiniz.

Ayrıca sitenizde zaten bir GA4/GTM `window.dataLayer` varsa, Selwise bunu **dinleyip** olayları kendi kanonik formatına çevirebilir (bkz. [Harici dataLayer köprüsü](#harici-datalayer-köprüsü)).

> **Önce panelden açın**
>
> Veri katmanı **yeni bir kanalda kapalıdır**. Panelde **Ayarlar → Entegrasyonlar** (Settings → Integrations) → **Data Layer** ekranında **Enable Data Layer** açılmadıkça `window.selwiseLayer` oluşmaz ve aşağıdakilerin hiçbiri çalışmaz. Ekranın her alanı için bkz. [Veri Katmanı Ayarları](/docs/integration/data-layer-settings). Ekran yalnızca web kanallarında vardır.

## Push API

`window.selwiseLayer` bir dizidir. Script yüklenmeden önce bile güvenle kullanmak için önce garanti altına alın, sonra push edin:

```html
<script>
  window.selwiseLayer = window.selwiseLayer || [];
  window.selwiseLayer.push({
    event: 'product_view',
    product: {
      sku: 'SKU-123',
      title: 'Kırmızı Tişört',
      price: 149.90,
      category: 'Tişört',
      currency: 'TRY',
    },
  });
</script>
```

Her push nesnesinde `event` alanı **zorunludur** ve olay adını belirtir. Olaya özel veriler ilgili "zarf" (envelope) altında taşınır: `page`, `product`, `basket`, `checkout`, `user`, `search`, `order`, `custom`, `common`.

> **window.selwiseLayer vs Selwise.pushDataLayer**
>
> Aynı işi `window.Selwise.pushDataLayer({ ... })` ile de yapabilirsiniz. `window.selwiseLayer.push()` script yüklenmeden önce çağrılabilir olması açısından avantajlıdır; kuyruğa alınıp Selwise hazır olduğunda işlenir. Dizinin adı panelde **Variable Name** ile değiştirilebilir (varsayılan `selwiseLayer`); adı değiştirdiyseniz push çağrılarını da değiştirin.

### Throttle ve kapalı modüller

Aynı olay adı ve aynı anahtar (`product.id`, `basket.id`, `checkout.orderNo`, `user.id` veya `search.query`) **1 saniye içinde** tekrar push edilirse ikincisi atlanır. Bu anahtarların hiçbiri yoksa anahtar yalnızca olay adıdır: iki farklı ürün için art arda gönderilen, `id` taşımayan `add_to_cart` push'larından ikincisi de atlanabilir. Aynı anda birden çok ürün için `basket.products` dizisini kullanın.

Bir olayın modülü panelde kapalıysa (örn. **Basket Tracking** kapalıyken `add_to_cart`) push **sessizce işlenmez**. Modül varsayılanları aşağıda.

## Zarflar ve alanlar

### product (ürün)

`product_view`, `product_click`, `product_impression` olaylarında kullanılır.

```js
window.selwiseLayer.push({
  event: 'product_view',
  product: {
    sku: 'SKU-123',        // ZORUNLU — birincil ürün tanımlayıcısı (stok kodu)
    id: 'db-uuid',         // opsiyonel — dahili veritabanı kimliği
    title: 'Kırmızı Tişört',
    price: 149.90,
    category: 'Tişört',
    subCategory: 'Erkek',
    variant: 'M / Kırmızı',
    brand: 'Marka',
    quantity: 1,
    inStock: true,
    url: 'https://magaza.com/urun/sku-123',
    image: 'https://magaza.com/img/sku-123.jpg',
  },
});
```

> **sku birincil anahtardır**
>
> `product.sku`, Selwise'ın ürünü ürün beslemesiyle eşleştirdiği **birincil anahtardır** ve public API'deki `productItemCode` ile aynıdır. Ürün besleme (feed) içindeki stok koduyla birebir aynı olmalıdır. `id` yalnızca opsiyonel dahili kimliktir.

### basket (sepet)

`add_to_cart`, `remove_from_cart`, `update_cart` olaylarında kullanılır.

`total` **sepetteki ürünlerin tamamının** tutarıdır: indirimler düşülmüş, kargo ve hediye paketi gibi ek ücretler hariç (GA4'teki `value` ile aynı tanım). Yalnızca değişen satırın tutarı değildir. Ücretsiz kargo gibi eşikler bu tutara göre yazıldığı için hedef çubuğu da bu değeri okur. Selwise sepetin ölçülmüş değerini bu alandan alır; hedef çubuğu gibi tutar gösteren yüzeyler yalnızca ölçülmüş bir sepetle çizilir. `total` gönderilmeyen bir sepet olayı tutarı değiştirmez. İsteğe bağlı `itemCount` alanı sepetteki toplam ürün adedidir; gönderilmezse satırların `quantity` değerleri toplanır.

```js
window.selwiseLayer.push({
  event: 'add_to_cart',
  basket: {
    step: 'add', // 'add' | 'remove' | 'update'
    currency: 'TRY',
    total: 299.80,   // sepetteki ürünlerin TAMAMI, indirimler sonrası, kargo hariç
    itemCount: 2,    // sepetteki toplam adet (isteğe bağlı)
    products: [
      {
        sku: 'SKU-123',   // ZORUNLU
        quantity: 2,      // ZORUNLU
        price: 149.90,    // birim fiyat
        totalPrice: 299.80,
        title: 'Kırmızı Tişört',
        category: 'Tişört',
        variant: 'M / Kırmızı',
      },
    ],
  },
});
```

### checkout (ödeme adımı) ve order (sipariş)

`checkout_begin`, `checkout_progress`, `checkout_option` için `checkout` zarfı; `purchase` için `order` zarfı kullanılır.

```js
// Ödeme başladı
window.selwiseLayer.push({
  event: 'checkout_begin',
  checkout: {
    step: 1, // 1=sepet, 2=müşteri, 3=ödeme, 4=satın alma
    currency: 'TRY',
    totalPrice: 299.80,
    products: [{ sku: 'SKU-123', quantity: 2, price: 149.90 }],
  },
});

// Satın alma tamamlandı
window.selwiseLayer.push({
  event: 'purchase',
  order: {
    id: 'ORDER-2026-0001', // ZORUNLU
    total: 319.80,
    subtotal: 299.80,
    shippingTotal: 20.00,
    discountTotal: 0,
    taxTotal: 0,
    currency: 'TRY',
    coupon: 'INDIRIM10',
    products: [{ sku: 'SKU-123', quantity: 2, price: 149.90 }],
  },
});
```

> **Satın alma için trackOrder'ı tercih edin**
>
> `purchase` event'ini veri katmanından gönderebilirsiniz; ancak sunucu tarafında güvenilir gelir ilişkilendirmesi için teşekkür sayfasında `window.Selwise.trackOrder(...)` kullanmanız önerilir. İkisini birden kullanıyorsanız çift sayımı önlemek için ayrıntılara bakın: [Sipariş Takibi](/docs/integration/order-tracking).

### user (kullanıcı)

`user_signup`, `user_login`, `user_logout`, `user_update` için.

```js
window.selwiseLayer.push({
  event: 'user_login',
  user: {
    step: 'signin', // 'signup' | 'signin' | 'signout' | 'update'
    id: 'user-42',
    email: 'ayse@example.com', // olaylarda yalnızca SHA-256 karması taşınır
    loggedIn: true,
    newCustomer: false,
    segments: ['vip'],
    // İsteğe bağlı, imzalı kimlik: sunucunuzun ürettiği imza ve zamanı
    idHash: 'SUNUCUNUZUN_URETTIGI_IMZA',
    idHashTs: 1792700000,
  },
});
```

`idHash` ve `idHashTs` olaylara yazılmaz, yalnızca `identify` çağrısına gider; nasıl üretildikleri [İmzalı Kimlik](/docs/integration/identity-verification) sayfasında.

> **E-posta ve kişisel veri**
>
> `user.email` verirseniz widget bunu olaylara **SHA-256 karması** olarak yazar (küçük harfe çevirip kırparak); kimlik eşleşmesi için ise adresi `identify` çağrısına olduğu gibi iletir ve sunucu karma olarak saklar ([Kullanıcı Kimliklendirme](/docs/integration/identify)). Adresi kendiniz karmalayıp göndermeyin; kimlik eşleşmesi bozulur. `fullName`, `firstName`, `lastName`, `gender`, `age` ve `birthday` olaylarda **düz** taşınır; gerekmiyorsa göndermeyin. Kullanıcı takip modülü varsayılan olarak kapalıdır ve yalnızca açıkça etkinleştirilirse çalışır.

### search (arama)

`search_query`, `search_filter`, `search_sort`, `search_page`, `search_results`, `search_instant_open` için.

```js
window.selwiseLayer.push({
  event: 'search_query',
  search: {
    query: 'kırmızı tişört',
    type: 'faceted',        // 'instant' | 'faceted'
    results: 42,
    filters: [{ facet: 'renk', values: ['kırmızı'] }],
    sortBy: 'price',
    sortOrder: 'asc',       // 'asc' | 'desc'
    page: 1,
    perPage: 24,
  },
});
```

### page (sayfa) ve custom (özel)

```js
// Otomatik sayfa takibi kapalıysa manuel sayfa görüntüleme:
window.selwiseLayer.push({
  event: 'page_view',
  page: { type: 'category', title: 'Tişörtler', path: '/kategori/tisort' },
});

// Tamamen özel bir olay:
window.selwiseLayer.push({
  event: 'custom_event',
  custom: { name: 'newsletter_signup', params: { source: 'footer' } },
});
```

Özel olayın adı sırayla `custom.type`, `custom.name`, `event` alanlarından alınır ve `entityType` `custom` olur. Bu ad kanonik bir olay adı değilse (`newsletter_signup` gibi) sunucu olayı `custom_event` olarak saklar ve `Degraded` (Eksik veriyle) işaretler; uyarı kodu `UNSUPPORTED_EVENT_NAME_FALLBACK`'tir. Aşağıdaki tabloda olmayan her `event` adı da aynı yoldan, özel olay gibi işlenir.

## Desteklenen veri katmanı olayları

| Olay adı | Zarf | Açıklama |
| --- | --- | --- |
| `page_view` | `page` | Sayfa görüntüleme |
| `virtual_page_view` | `page` | SPA sanal sayfa geçişi |
| `product_view` | `product` | Ürün detay görüntüleme |
| `product_click` | `product` | Ürün tıklama |
| `product_impression` | `product` | Ürün gösterimi (listede görünme) |
| `add_to_cart` | `basket` | Sepete ekleme |
| `remove_from_cart` | `basket` | Sepetten çıkarma |
| `update_cart` | `basket` | Sepet güncelleme |
| `cart_abandon` | (dahili) | Sepet terk (zaman aşımıyla otomatik) |
| `cart_restore` | `basket` | Terk edilen sepetin geri gelmesi |
| `checkout_begin` | `checkout` | Ödeme başladı |
| `checkout_progress` | `checkout` | Ödeme adımı ilerledi |
| `checkout_option` | `checkout` | Ödeme/kargo seçeneği seçildi |
| `purchase` | `order` | Satın alma tamamlandı |
| `user_signup` | `user` | Kayıt |
| `user_login` | `user` | Giriş |
| `user_logout` | `user` | Çıkış |
| `user_update` | `user` | Profil güncelleme |
| `search_instant_open` | `search` | Anlık arama kutusu açıldı |
| `search_query` | `search` | Arama yapıldı |
| `search_filter` | `search` | Filtre uygulandı |
| `search_sort` | `search` | Sıralama değişti |
| `search_page` | `search` | Sonuç sayfası değişti |
| `search_results` | `search` | Sonuçlar döndü |
| `custom_event` | `custom` | Özel olay |

Tüm kanonik event listesi ve bunların analitikte nasıl kullanıldığı için bkz. [Event Referansı](/docs/integration/events). Tabloda olmayan kanonik adlar (`wishlist`, `cart_view` gibi) `custom` zarfı gibi işlenir: ad korunur, `entityType` `custom` olur.

## Otomatik takip ve platform ön ayarı

Panelde **E-commerce Platform Preset** (E-ticaret Platform Ön Ayarı) hangi platformda olduğunuzu söyler. Seçenekler: `auto` (Auto Detect), `generic`, `akinon`, `ticimax`, `tsoft`, `ikas`, `ideasoft`, `shopify`, `custom` ve `none`. **Varsayılan `generic`'tir**; widget platformu kendiliğinden bulsun istiyorsanız **Auto Detect** seçin. Ön ayarın ne değiştirdiği (dinlenen `dataLayer` adları, Akinon ve IdeaSoft için hazır eşleme, ürün sayfası seçicileri) [Veri Katmanı Ayarları](/docs/integration/data-layer-settings#platform-ön-ayarı) sayfasındadır.

Listede olmayan bir altyapı kullanıyorsanız `custom` seçip sayfa türü desenlerini panelden elle yazabilirsiniz; ürün kodunu DOM'dan bulmak yerine `product.sku` ile manuel push etmek en güvenilir yoldur.

Otomatik takip varsayılanları:

| Modül | Varsayılan | Açıklama |
| --- | --- | --- |
| `page` | Açık | Sayfa görüntülemeleri otomatik yakalanır |
| `product` | Açık | Ürün sayfaları ve dwell-time |
| `basket` | Açık | Sepet olayları |
| `checkout` | Açık | Ödeme adımları |
| `user` | Kapalı | Kullanıcı olayları (gizlilik nedeniyle) |
| `search` | Kapalı | Arama olayları |

Sayfa tipi tespiti için URL kalıpları kullanılır (ör. varsayılan olarak `/product/…`, `/p/…` = ürün, `/cart`, `/basket` = sepet); Türkçe adresli mağazalarda `/urun/…` veya `/sepet` için kalıbı panelde yazmanız gerekir. Kalıplar ve **Page Detection Mode** [Veri Katmanı Ayarları](/docs/integration/data-layer-settings#sayfa-algılama) sayfasında anlatılır.

> **Otomatik yakalanmazsa manuel push edin**
>
> Temanız standart dışıysa (örneğin ürün SKU'su DOM'da bulunamıyorsa), ilgili event'i `window.selwiseLayer.push()` ile manuel gönderin. Manuel push her zaman otomatik tespitten önceliklidir ve en güvenilir yöntemdir.

## Harici dataLayer köprüsü

Sitenizde GA4/GTM için zaten bir `window.dataLayer` varsa Selwise bu diziyi dinleyip olayları kendi kanonik adlarına çevirebilir. Bu, panelde **Use External Data Layer** (varsayılan açık) ve **External Data Layer Name** (varsayılan `dataLayer`) ile yönetilir.

> **Köprü bir eşleme olmadan çalışmaz**
>
> Selwise dış olay adlarını **kendiliğinden tanımaz**. Köprü yalnızca elinde bir eşleme (dış olay adı → Selwise olayı) varsa dinler: **Akinon** ve **IdeaSoft** ön ayarlarında hazır eşleme vardır; başka bir ön ayarda eşleme tanımlanmamışsa dış dizi hiç dinlenmez. Aşağıdaki tablo, GA4 adlarının Selwise karşılıklarına **örnektir**, otomatik uygulanan bir liste değildir.

Eşleme anahtarı olay adı olabilir, `*` içeren bir desen olabilir ya da Enhanced Ecommerce olaylarında `olay:eylem:adım` biçiminde (örn. `eeCheckout:checkout:2`) bileşik bir anahtar olabilir; en özel anahtar kazanır.

Örnek GA4 eşlemeleri:

| GA4 olayı | Selwise olayı |
| --- | --- |
| `view_item` | `product_view` |
| `view_item_list` | `product_impression` |
| `select_item` | `product_click` |
| `add_to_cart` | `add_to_cart` |
| `remove_from_cart` | `remove_from_cart` |
| `begin_checkout` | `checkout_begin` |
| `add_payment_info` | `checkout_progress` |
| `purchase` | `purchase` |
| `search` | `search_query` |
| `login` | `user_login` |
| `sign_up` | `user_signup` |

Köprüyle gelen olaylara `dataSource: datalayer` ve `originalEvent` (dış olayın özgün adı) eklenir; aynı ürün için hem köprü hem otomatik takip `product_view` üretecekse, Akinon ve IdeaSoft ön ayarlarında otomatik olan atlanır.

> **Çift sayımı önleyin**
>
> Hem harici dataLayer köprüsünü hem de manuel `window.selwiseLayer.push()` kullanıyorsanız aynı olayı iki kez göndermemeye dikkat edin. Selwise kısa süreli (1 sn) bir throttle uygular, ancak bu yalnızca aynı ad ve anahtara sahip olayları kapsar; en temiz yaklaşım tek bir kaynağı esas almaktır.

## Yapılandırma

Veri katmanı yapılandırması panelde **Data Layer** ekranından yönetilir ve widget'a `tracking-config` ile iletilir. Her alanın açıklaması: [Veri Katmanı Ayarları](/docs/integration/data-layer-settings). Öne çıkan seçenekler:

| Seçenek | Varsayılan | Açıklama |
| --- | --- | --- |
| `enabled` | `false` | Veri katmanı yeni kanalda kapalıdır |
| `variableName` | `selwiseLayer` | Window değişken adı (en fazla 50 karakter) |
| `platform` | `generic` | E-ticaret platformu ön ayarı |
| `pageDetection` | `auto` | `auto`, `manual` veya `patterns` |
| `autoPageTracking` | `true` | Sayfa görüntülemelerini otomatik yakala |
| `useExternalDataLayer` | `true` | Sitenin `window.dataLayer`'ını dinle (eşleme gerekir) |
| `externalDataLayerName` | `dataLayer` | Dinlenecek harici değişken (en fazla 50 karakter) |
| `cartAbandonmentTimeout` | `30` | Sepet terk süresi, dakika (API 1–240) |
| `bufferSize` | `10` | Bellekte bekleyen olay sayısı (1–100) |
| `flushInterval` | `1000` | Tampon işleme aralığı, ms (100–10000) |
| `testMode` | `false` | Test olayının webhook'lara iletilmesini durdurur |
| `cookieConsent.enabled` | `false` | Çerez onayı denetimi (bkz. [Onay Yönetimi](/docs/integration/consent)) |
