> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.onesignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Google Tag Manager kurulumu

> Google Tag Manager (GTM) kullanarak web sitenize OneSignal Web Push'u ekleyin; service worker kurulumu, başlatma ve etiketleri güvenli bir şekilde ayarlamayı içerir.

Bu kılavuz, Google Tag Manager (GTM) kullanarak OneSignal Web SDK'sını nasıl yükleyip başlatacağınızı, ardından isteğe bağlı olarak başlatma sonrasında External ID ve OneSignal Etiketlerini nasıl ayarlayacağınızı gösterir.

## Ön Koşullar

* HTTPS'yi destekleyen bir site.
* Sitenin container'ı için GTM'de değişiklikleri yayınlayabilmeniz.
* Tamamladınız: OneSignal [Web SDK kurulumu](./web-sdk-setup) akışını **Siteye Kod Ekle** adımına kadar. Bu size şunları sağlar:
  * Bir OneSignal Web Push uygulaması ve App ID.
  * [OneSignal Service Worker](./onesignal-service-worker) kurulumu.

## Kurulum

### 1. OneSignal web uygulamanızı kurun

**Siteye Kod Ekle** adımına ulaşana kadar [Web SDK kurulumunu](./web-sdk-setup) takip edin. OneSignal App ID'yi buradan alacaksınız.

<Frame caption="Bu adıma ulaştığınızda, kodun Google Tag Manager ile çalışması için bazı ayarlamalar yapmanız gerekecektir.">
  <img src="https://mintcdn.com/onesignal/Y9PryqrHCRmPv_BC/images/web-push/add-code-to-site.png?fit=max&auto=format&n=Y9PryqrHCRmPv_BC&q=85&s=445d73fafe6bd92c5a6dcfbac563c1ee" alt="OneSignal Web SDK kurulum panosunda Siteye Kod Ekle adımı" width="2588" height="1638" data-path="images/web-push/add-code-to-site.png" />
</Frame>

<Warning>
  OneSignal Service Worker dosyasını doğrudan sunucunuza yüklemeniz gerekir. Bkz. [OneSignal Service Worker](./onesignal-service-worker).
</Warning>

### 2. GTM değişkenleri oluşturun

GTM etiketlerinde referans verebileceğiniz değerler için GTM değişkenleri oluşturun. Değişken kullanmak, değerlerin sabit kodlanmasını önler ve kurulumunuzun bakımını kolaylaştırır.

**`ONESIGNAL_APP_ID` değişkeni oluşturun**

1. GTM'de **Variables > New** kısmına gidin.
2. **Constant** seçin.
3. Adını `ONESIGNAL_APP_ID` olarak belirleyin.
4. Değeri OneSignal App ID'niz olarak ayarlayın.
5. Kaydedin.

<Frame caption="OneSignal App ID değişkeni oluşturma">
  <img src="https://mintcdn.com/onesignal/wJS3gHTEqDzyW0IP/images/web-push/gtm-app-id-variable.png?fit=max&auto=format&n=wJS3gHTEqDzyW0IP&q=85&s=8a7752f1d4095d4c8e6b8119a9de2bfc" alt="Google Tag Manager'da OneSignal App ID değişkeni oluşturma" width="2378" height="1656" data-path="images/web-push/gtm-app-id-variable.png" />
</Frame>

<Check>
  Artık GTM'de herhangi bir yerde App ID'nizi `{{ ONESIGNAL_APP_ID }}` kullanarak referans verebilirsiniz.
</Check>

**`ONESIGNAL_EXTERNAL_ID` değişkeni oluşturun (Önerilen)**

Kullanıcıları harici bir tanımlayıcı ile ilişkilendiriyorsanız bu değişkeni kullanın (örneğin, veritabanınızdan veya kimlik doğrulama sisteminizden bir kullanıcı ID'si).

Değerin sitenizde nasıl mevcut olduğuna göre değişken türünü seçin. Yaygın seçenekler:

* Data Layer Variable (önerilen)
* First-Party Cookie
* DOM Variable (gelişmiş)

### 3. OneSignal init etiketini oluşturun

1. GTM'de **Tags > New** kısmına gidin.
2. Etiketi adlandırın: `OneSignal - Init`
3. Tag Type: **Custom HTML**
4. Aşağıdaki kodu yapıştırın.
5. **Advanced Settings > Tag firing options** altında **Once per page** olarak ayarlayın.
6. **Triggering** altında **Initialization - All Pages** seçin.

```html HTML theme={null}
<!--
  OneSignal – Web SDK initialization using Google Tag Manager

  This snippet:
  - Loads the OneSignal Web SDK
  - Initializes OneSignal with your App ID
  - Enables the Subscription Bell (notifyButton)

  Works for most sites out of the box.
-->

<!-- 1. Load the OneSignal Web SDK (v16) -->
<!-- This script must load on every page where you want OneSignal available -->
<script
  src="https://cdn.onesignal.com/sdks/web/v16/OneSignalSDK.page.js"
  defer>
</script>

<script>
  // Ensure the GTM dataLayer exists
  // Used here only to optionally push a "OneSignalInitialized" event
  window.dataLayer = window.dataLayer || [];

  // OneSignalDeferred is a queue that runs once the SDK is fully loaded
  window.OneSignalDeferred = window.OneSignalDeferred || [];

  // 2. Initialize OneSignal once the SDK is ready
  window.OneSignalDeferred.push(function (OneSignal) {

    OneSignal.init({
      /*
        REQUIRED
        It is recommended to set the OneSignal App ID as a GTM variable.
        You can find this in your OneSignal Dashboard under:
        Settings > Keys & IDs
      */
      appId: "{{ONESIGNAL_APP_ID}}",

      /*
        OPTIONAL – ONLY NEEDED IF YOUR SERVICE WORKER IS NOT AT THE ROOT

        If your service worker is hosted at:
          /OneSignalSDKWorker.js

        …then you should NOT set serviceWorkerPath or serviceWorkerParam.

        Uncomment and update the options below ONLY if your service worker
        is hosted in a subdirectory (for example: /push/onesignal/).
      */

      //serviceWorkerPath: "push/onesignal/OneSignalSDKWorker.js",
      //serviceWorkerParam: { scope: "/push/onesignal/" },

      /*
        OPTIONAL
        Enable the OneSignal Subscription Bell (notifyButton),
        which allows users to subscribe or unsubscribe from notifications.
        For more prompt options, see: https://documentation.onesignal.com/docs/en/permission-requests
      */
      notifyButton: {
        enable: true
      }
    })
    .then(function () {
      // OneSignal initialized successfully
      console.log("[OneSignal] init success");

      // Recommended: push an event to GTM for triggering other tags
      window.dataLayer.push({
        event: "OneSignalInitialized"
      });
    })
    .catch(function (e) {
      // Initialization failed (invalid App ID, missing service worker, etc.)
      console.log("[OneSignal] init failed", e);
    });
  });
</script>
```

<Frame caption="OneSignal - Init etiketini yapılandırma">
  <img src="https://mintcdn.com/onesignal/Y9PryqrHCRmPv_BC/images/web-push/gtm-init-tag.png?fit=max&auto=format&n=Y9PryqrHCRmPv_BC&q=85&s=6cec423472cb84777bddd893a59c83ff" alt="Google Tag Manager'da OneSignal - Init etiketini yapılandırma" width="2442" height="2296" data-path="images/web-push/gtm-init-tag.png" />
</Frame>

<Warning>
  Bir onay banner'ı / CMP kullanıyorsanız, aşağıdaki [Consent Mode ve gizlilik hususları](#consent-mode-and-privacy-considerations) seçeneklerine bakın.
</Warning>

### 4. External ID ve Etiketleri ayarlayın

[External ID](./users#external-id) ayarlamak isteğe bağlıdır ancak önerilir çünkü cihazlar arasında kullanıcıları tanımlamanıza ve backend'inizle senkronize olmanıza olanak tanır.

**ONESIGNAL\_EXTERNAL\_ID'yi dataLayer'a gönderin**

Bu örnek, GTM'nin adım 2'de oluşturulan `ONESIGNAL_EXTERNAL_ID` değişkeni aracılığıyla okuyabilmesi için bir kullanıcı ID'sini dataLayer'a nasıl gönderebileceğinizi gösterir.

```html HTML theme={null}
<script>
  window.dataLayer = window.dataLayer || [];

  // Get your user ID from your database or auth system.
  // Ensure this is a string value.
  var userId = "your_user_id_here";

  dataLayer.push({
    ONESIGNAL_EXTERNAL_ID: String(userId),
  });
</script>
```

**External ID'yi ayarlamak için GTM Etiketi oluşturun**

Etiket yapılandırması:

* Etiket adı: `OneSignal – Set External ID`
* Etiket türü: **Custom HTML**
* Etiket tetikleme seçenekleri: **Once per page**
* Tetikleyici:
  * `OneSignalInitialized` için özel olay tetikleyicisi oluşturun (yukarıdaki **OneSignal - Init** etiketinde ayarlanmıştır) ve
  * İsteğe bağlı olarak, kullanıcı ID'sinin sayfa yüklemesinde mevcut olduğunu biliyorsanız.

<Warning>
  External ID'yi ayarlamak için gereken yöntem, `externalId`'nin bir string olduğu `OneSignal.login(externalId)` yöntemidir.

  `{{ONESIGNAL_EXTERNAL_ID}}` boşsa (veya GTM "undefined" / "null" değerini koyarsa), login çağrısı atlanacak ve External ID ayarlanmayacaktır. Bu yaygın bir GTM zamanlama sorunudur.
</Warning>

<CodeGroup>
  ```html External ID'yi ayarlamak için temel örnek theme={null}
  <script>
    // OneSignalDeferred ensures this runs after the OneSignal SDK is ready
    window.OneSignalDeferred = window.OneSignalDeferred || [];

    window.OneSignalDeferred.push(function (OneSignal) {
      /*
        Read the External ID from Google Tag Manager.
        This should be a GTM variable (Data Layer Variable or Custom JS Variable).
      */
      var externalId = "{{ONESIGNAL_EXTERNAL_ID}}";

      console.log("[OneSignal] raw external ID from GTM:", externalId);

      /*
        Basic validation:
        - GTM may substitute undefined/null as strings
        - OneSignal.login requires a string
      */
      if (!externalId || externalId === "undefined" || externalId === "null") {
        console.log("[OneSignal] External ID missing, skipping login");
        return;
      }

      // Ensure the External ID is a clean string
      externalId = String(externalId).trim();

      console.log("[OneSignal] Calling OneSignal.login with External ID:", externalId);

      /*
        Log the user into OneSignal using the External ID.
        This links the current browser/device to this user.
      */
      OneSignal.login(externalId)
        .then(function () {
          console.log("[OneSignal] External ID set successfully:", externalId);
        })
        .catch(function (e) {
          console.log("[OneSignal] Failed to set External ID", e);
        });
    });
  </script>
  ```

  ```html External ID ayarlanmıyorsa denemek için gelişmiş örnek theme={null}
  <script>
    window.dataLayer = window.dataLayer || [];
    window.OneSignalDeferred = window.OneSignalDeferred || [];

    OneSignalDeferred.push(function (OneSignal) {
      var rawExternalId = "{{ONESIGNAL_EXTERNAL_ID}}";

      // ---- Helpers ----
      function log() {
        console.log.apply(console, ["[OneSignal External ID]"].concat([].slice.call(arguments)));
      }

      function normalizeExternalId(v) {
        // GTM commonly substitutes these as strings
        if (
          v === undefined ||
          v === null ||
          v === "undefined" ||
          v === "null"
        ) return null;

        var s = String(v).trim();
        if (!s.length) return null;

        return s;
      }

      function pushDL(eventName, extra) {
        try {
          var payload = Object.assign({ event: eventName }, extra || {});
          window.dataLayer.push(payload);
        } catch (e) {
          // no-op
        }
      }

      function readStateSnapshot() {
        var snapshot = {
          onesignalId: null,
          externalId: null,
          pushSubscriptionId: null
        };

        try {
          snapshot.onesignalId = OneSignal.User && OneSignal.User.onesignalId;
          snapshot.externalId = OneSignal.User && OneSignal.User.externalId;
          snapshot.pushSubscriptionId =
            OneSignal.User &&
            OneSignal.User.PushSubscription &&
            OneSignal.User.PushSubscription.id;
        } catch (e) {
          log("Error reading OneSignal.User state", e);
        }

        return snapshot;
      }

      function isExternalIdApplied(targetExternalId) {
        var current = normalizeExternalId(OneSignal.User && OneSignal.User.externalId);
        return current === targetExternalId;
      }

      // ---- Initial logging ----
      log("Tag fired. rawExternalId:", rawExternalId, "type:", typeof rawExternalId);

      var externalId = normalizeExternalId(rawExternalId);
      log("Normalized externalId:", externalId, "type:", typeof externalId);

      if (!externalId) {
        log("Not calling login(): externalId missing/invalid");
        pushDL("OneSignalExternalIdMissing", { reason: "invalid_or_missing_external_id" });
        return;
      }

      // Optional: enable verbose OneSignal logs during testing
      if (OneSignal.Debug && OneSignal.Debug.setLogLevel) {
        OneSignal.Debug.setLogLevel("trace");
        log("Enabled OneSignal Debug log level: trace");
      }

      // ---- Attach User State observer ----
      var changeFired = false;

      OneSignal.User.addEventListener("change", function (event) {
        changeFired = true;

        log("User change event fired:", event);

        var snapshot = readStateSnapshot();
        log("User state snapshot:", snapshot);

        // Helpful: push snapshot-ish DL event (optional)
        pushDL("OneSignalUserStateChanged", {
          onesignal_id: snapshot.onesignalId || "",
          external_id: normalizeExternalId(snapshot.externalId) || "",
          push_subscription_id: snapshot.pushSubscriptionId || ""
        });
      });

      // ---- Login + confirm + retry ----
      var attempt = 0;
      var MAX_RETRIES = 3;
      var CONFIRM_WINDOW_MS = 1500;
      var BASE_BACKOFF_MS = 500;

      function doLogin() {
        attempt += 1;
        changeFired = false;

        log("Calling OneSignal.login()", { externalId: externalId, attempt: attempt });

        OneSignal.login(externalId)
          .then(function () {
            log("OneSignal.login() promise resolved");
            waitForConfirmation();
          })
          .catch(function (e) {
            log("OneSignal.login() promise rejected", e);
            retry("promise_rejected");
          });
      }

      function waitForConfirmation() {
        var start = Date.now();

        (function check() {
          if (isExternalIdApplied(externalId)) {
            log("Confirmed externalId applied via state check:", externalId);

            var snapshot = readStateSnapshot();
            log("Final state snapshot:", snapshot);

            pushDL("OneSignalExternalIdSet", {
              external_id: externalId,
              attempt: attempt,
              push_subscription_id: snapshot.pushSubscriptionId || ""
            });

            return;
          }

          if (changeFired) {
            log("Change event observed but externalId not yet reflected; waiting...");
          }

          if (Date.now() - start >= CONFIRM_WINDOW_MS) {
            log("No confirmation within window", {
              attempt: attempt,
              changeFired: changeFired,
              currentExternalId: normalizeExternalId(OneSignal.User && OneSignal.User.externalId)
            });

            retry("no_confirmation");
            return;
          }

          setTimeout(check, 100);
        })();
      }

      function retry(reason) {
        if (attempt >= MAX_RETRIES) {
          log("Giving up after max retries", { attempts: attempt, reason: reason });

          var snapshot = readStateSnapshot();
          log("State at give-up:", snapshot);

          pushDL("OneSignalExternalIdSetFailed", {
            external_id: externalId,
            reason: reason,
            attempts: attempt,
            push_subscription_id: snapshot.pushSubscriptionId || ""
          });

          return;
        }

        var delay = BASE_BACKOFF_MS * Math.pow(2, attempt - 1);
        log("Retrying login after delay", { delayMs: delay, reason: reason, nextAttempt: attempt + 1 });

        setTimeout(doLogin, delay);
      }

      // If already applied, don't spam login()
      if (isExternalIdApplied(externalId)) {
        log("ExternalId already applied; skipping login.", externalId);

        var snapshot = readStateSnapshot();
        log("Current state snapshot:", snapshot);

        pushDL("OneSignalExternalIdAlreadySet", {
          external_id: externalId,
          push_subscription_id: snapshot.pushSubscriptionId || ""
        });

        return;
      }

      // Kick it off
      doLogin();
    });
  </script>
  ```
</CodeGroup>

#### Etiketleri ayarlayın

Bu adım, Web SDK kullanarak [OneSignal Etiketlerini](./add-user-data-tags) gönderir.

Etiket yapılandırması:

* Ad: `OneSignal - Add Tags`
* Etiket Türü: **Custom HTML**
* Etiket tetikleme seçenekleri: **Once per page**
* Tetikleyici:
  * `OneSignalInitialized` ve
  * Etiket verilerinin mevcut olduğu koşulunuz (örneğin: giriş sonrası, profil sayfasında, satın alma sonrası).

Bu kodu yapıştırın ve örnek etiket TAG ve VALUE'yu değiştirin.

```html HTML theme={null}
<script>
  window.OneSignalDeferred = window.OneSignalDeferred || [];
  window.OneSignalDeferred.push(function (OneSignal) {
    OneSignal.User.addTags({
      TAG_1: "VALUE_1",
      TAG_2: "VALUE_2",
    });
  });
</script>
```

<Note> Yalnızca kullanıcı verilerine sahip olduğunuzda etiketler gönderin (örneğin: giriş yaptıktan sonra, bir profil yüklendikten sonra veya bilinen bir dönüşüm olayından sonra). </Note>

### Consent Mode ve gizlilik hususları

Siteniz Consent Mode / bir CMP kullanıyorsa, OneSignal'in ne zaman yüklenmesi gerektiğine karar verin:

* Yalnızca onaydan sonra (AB/Birleşik Krallık için yaygın), veya
* Hemen (varsayılan olarak "işlevsel" depolamaya izin verilen yerlerde yaygın).

GTM, kullanıcı onayına göre etiket davranışını yönetmek için Consent Initialization tetikleyicisi ve etiket düzeyinde onay kontrollerini destekler. Ancak, OneSignal ayrıca SDK'nın ne zaman yükleneceğini kontrol etmek için gizlilik onay yöntemleri sağlar.

* [Kişisel verilerin işlenmesi](./handling-personal-data)
* [Web SDK Gizlilik Yöntemleri](./web-sdk-reference#privacy)

***

## Test

1. GTM'de Preview modunu açın.
2. Sitenizi yükleyin ve onaylayın:
   * `OneSignal - Init` bir kez tetiklenir.
   * `OneSignalInitialized`, GTM olay zaman çizelgesinde görünür (olay push'unu tuttuyseniz).
3. Web sitenize abone olun. İstem ayrıntıları için [Web izin istemleri](./permission-requests)'ne bakın.
4. OneSignal panosunda **Audience > Subscriptions**'a gidin ve onaylayın:
   * Kabul ettikten sonra bir Abonelik görünür.
   * Bir External ID ayarladıysanız görünür olur.
5. **Messages > New Push**'tan bir test push gönderin.

<Check> Başlatma çalışıyorsa, kabul ettikten sonra OneSignal'de aboneliklerin göründüğünü göreceksiniz. </Check>

### Sorun Giderme

* Init etiketi tetiklenir ancak SDK asla yüklenmez
  * Content Security Policy (CSP)'nin `https://cdn.onesignal.com`'u engelleyip engellemediğini kontrol edin.
  * Reklam engelleyicileri/betik engelleyicileri kontrol edin.

* `dataLayer` hataları
  * Herhangi bir `dataLayer.push()` çağrısından önce `window.dataLayer = window.dataLayer || []`'nin ayarlandığından emin olun.

* Yinelenen istemler / yinelenen SDK yüklemesi
  * OneSignal'i site kodu, bir CMS eklentisi veya başka bir GTM etiketi aracılığıyla da yüklemediğinizden emin olun.

* Add Tags çalışır ancak OneSignal'de görünmez
  * Trigger Group'un `OneSignalInitialized`'i beklediğini onaylayın.
  * Kullanıcı eylem tetikleyicinizin gerçekten tetiklendiğini onaylayın.
  * Etiketlerin geçerli anahtar/değer çiftleri olduğunu ve [Plan limitleri](https://onesignal.com/pricing) içinde olduğunu onaylayın.

<Warning>
  Hala yardıma ihtiyacınız varsa, yaygın düzeltmeler için [Web SDK Sorun Giderme](./troubleshooting-web-push)'ye bakın.
</Warning>

## Sonraki adımlar

* [Web izin istemleri](./permission-requests)
* [Etiketler](./add-user-data-tags)
* [Web SDK referansı](./web-sdk-reference)

***
