> ## 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.

# Configuration de Google Tag Manager

> Ajoutez OneSignal Web Push à votre site web en utilisant Google Tag Manager (GTM), incluant la configuration du service worker, l'initialisation et la configuration sécurisée des balises.

Ce guide vous montre comment charger et initialiser le SDK Web OneSignal en utilisant Google Tag Manager (GTM), puis définir éventuellement un External ID et envoyer des balises OneSignal après l'initialisation.

## Prérequis

* Un site qui prend en charge HTTPS.
* Vous pouvez publier des modifications dans GTM pour le conteneur du site.
* Vous avez complété le flux de [configuration du SDK Web](./web-sdk-setup) OneSignal jusqu'à **Ajouter le code au site**. Cela vous donne :
  * Une application OneSignal Web Push et un App ID.
  * La configuration du [OneSignal Service Worker](./onesignal-service-worker).

## Configuration

### 1. Configurez votre application web OneSignal

Suivez la [configuration du SDK Web](./web-sdk-setup) jusqu'à atteindre l'étape **Ajouter le code au site**. C'est ici que vous obtiendrez l'OneSignal App ID.

<Frame caption="Une fois que vous atteignez cette étape, vous devrez apporter quelques ajustements au code pour qu'il fonctionne avec Google Tag Manager.">
  <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="Étape Ajouter le code au site dans le tableau de bord de configuration du SDK Web OneSignal" width="2588" height="1638" data-path="images/web-push/add-code-to-site.png" />
</Frame>

<Warning>
  Vous devez télécharger le fichier OneSignal Service Worker directement sur votre serveur. Consultez [OneSignal Service Worker](./onesignal-service-worker).
</Warning>

### 2. Créez des variables GTM

Créez des variables GTM pour les valeurs que vous référencez dans les balises. Cela évite de coder en dur les valeurs et facilite la maintenance de votre configuration.

**Créez une variable `ONESIGNAL_APP_ID`**

1. Dans GTM, allez dans **Variables > New**.
2. Choisissez **Constant**.
3. Nommez-la `ONESIGNAL_APP_ID`
4. Définissez la valeur sur votre OneSignal App ID.
5. Enregistrez

<Frame caption="Création d'une variable OneSignal App ID">
  <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="Création d'une variable OneSignal App ID dans Google Tag Manager" width="2378" height="1656" data-path="images/web-push/gtm-app-id-variable.png" />
</Frame>

<Check>
  Vous pouvez maintenant référencer votre App ID n'importe où dans GTM en utilisant `{{ ONESIGNAL_APP_ID }}`.
</Check>

**Créez une variable `ONESIGNAL_EXTERNAL_ID` (Recommandé)**

Utilisez cette variable si vous associez des utilisateurs à un identifiant externe (par exemple, un ID utilisateur de votre base de données ou système d'authentification).

Choisissez un type de variable en fonction de l'emplacement de la valeur sur votre site. Options courantes :

* Data Layer Variable (recommandé)
* First-Party Cookie
* DOM Variable (avancé)

### 3. Créez la balise d'initialisation OneSignal

1. Dans GTM, allez dans **Tags > New**
2. Nommez la balise : `OneSignal - Init`
3. Tag Type : **Custom HTML**
4. Collez le code ci-dessous.
5. Sous **Advanced Settings > Tag firing options**, définissez **Once per page**.
6. Sous **Triggering**, sélectionnez **Initialization - All Pages**.

```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="Configuration de la balise OneSignal - Init">
  <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="Configuration de la balise OneSignal - Init dans Google Tag Manager" width="2442" height="2296" data-path="images/web-push/gtm-init-tag.png" />
</Frame>

<Warning>
  Si vous utilisez une bannière de consentement / CMP, consultez les options [Consent Mode et considérations de confidentialité](#consent-mode-and-privacy-considerations) ci-dessous.
</Warning>

### 4. Définissez l'External ID et les balises

La définition de l'[External ID](./users#external-id) est optionnelle mais recommandée car elle vous permet d'identifier les utilisateurs sur plusieurs appareils et de synchroniser avec votre backend.

**Envoyer `ONESIGNAL_EXTERNAL_ID` dans le dataLayer**

Cet exemple montre comment vous pouvez transmettre un ID utilisateur dans le dataLayer afin que GTM puisse le lire via la variable `ONESIGNAL_EXTERNAL_ID` (créée à l'étape 2).

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

**Créez une balise GTM pour définir l'External ID**

Configuration de la balise :

* Nom de la balise : `OneSignal – Set External ID`
* Type de balise : **Custom HTML**
* Options de déclenchement : **Once per page**
* Déclencheur :
  * Créez un déclencheur d'événement personnalisé pour `OneSignalInitialized` (défini dans la balise **OneSignal - Init** ci-dessus) et
  * Éventuellement si vous savez que l'ID utilisateur est disponible au chargement de la page.

<Warning>
  La méthode requise pour définir l'External ID est `OneSignal.login(externalId)` où `externalId` est une chaîne.

  Si `{{ONESIGNAL_EXTERNAL_ID}}` est vide (ou si GTM substitue "undefined" / "null"), l'appel login sera ignoré et l'External ID ne sera pas défini. C'est un problème de timing GTM courant.
</Warning>

<CodeGroup>
  ```html Exemple de base pour définir l'External ID 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 Exemple avancé à essayer si l'External ID n'est pas défini 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>

#### Définir les balises

Cette étape envoie des [balises OneSignal](./add-user-data-tags) à l'aide du SDK Web.

Configuration de la balise :

* Nom : `OneSignal - Add Tags`
* Type de balise : **Custom HTML**
* Options de déclenchement : **Once per page**
* Déclencheur :
  * `OneSignalInitialized`, et
  * Votre condition pour que les données de balise soient disponibles (par exemple : après la connexion, sur une page de profil, après un achat).

Collez ce code et remplacez l'exemple de balise TAG et VALUE.

```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> N'envoyez des balises que lorsque vous avez les données utilisateur disponibles (par exemple : après la connexion, après le chargement d'un profil ou après un événement de conversion connu). </Note>

### Consent Mode et considérations de confidentialité

Si votre site utilise Consent Mode / un CMP, décidez si OneSignal doit se charger :

* Seulement après consentement (courant pour l'UE/Royaume-Uni), ou
* Immédiatement (courant là où le stockage "fonctionnel" est autorisé par défaut).

GTM prend en charge un déclencheur d'initialisation du consentement et des contrôles de consentement au niveau de la balise pour gérer le comportement des balises en fonction du consentement de l'utilisateur. Cependant, OneSignal fournit également des méthodes de consentement de confidentialité pour contrôler quand le SDK se charge.

* [Gestion des données personnelles](./handling-personal-data)
* [Méthodes de confidentialité du SDK Web](./web-sdk-reference#privacy)

***

## Tests

1. Dans GTM, ouvrez le mode Preview.
2. Chargez votre site et confirmez :
   * `OneSignal - Init` se déclenche une fois.
   * `OneSignalInitialized` apparaît dans la chronologie des événements GTM (si vous avez conservé le push d'événement).
3. Abonnez-vous à votre site web. Consultez [Demandes de permission web](./permission-requests) pour les détails des invites.
4. Dans le tableau de bord OneSignal, allez dans **Audience > Subscriptions** et confirmez :
   * Un abonnement apparaît après avoir accepté.
   * Un External ID est visible si vous en avez défini un.
5. **Envoyez un push de test depuis Messages > New Push.**

<Check> Si l'initialisation fonctionne, vous verrez les abonnements apparaissant dans OneSignal après avoir accepté. </Check>

### Dépannage

* La balise Init se déclenche, mais le SDK ne se charge jamais
  * Vérifiez si la Content Security Policy (CSP) bloque `https://cdn.onesignal.com`.
  * Vérifiez les bloqueurs de publicité/bloqueurs de scripts.
* Erreurs de `dataLayer`
  * Assurez-vous que `window.dataLayer = window.dataLayer || []` est défini avant tout appel `dataLayer.push()`.
* Invites en double / chargement en double du SDK
  * Assurez-vous de ne pas charger OneSignal via le code du site, un plugin CMS ou une autre balise GTM.
* Add Tags s'exécute mais n'apparaît pas dans OneSignal
  * Confirmez que le Trigger Group attend `OneSignalInitialized`.
  * Confirmez que votre déclencheur d'action utilisateur se déclenche réellement.
  * Confirmez que les balises sont des paires clé/valeur valides et dans les [limites du plan](https://onesignal.com/pricing).

<Warning>
  Si vous avez encore besoin d'aide, consultez [Dépannage du SDK Web](./troubleshooting-web-push) pour les corrections courantes.
</Warning>

## Prochaines étapes

* [Demandes de permission web](./permission-requests)
* [Balises](./add-user-data-tags)
* [Référence du SDK Web](./web-sdk-reference)

***
