Skip to main content
This guide shows you how to load and initialize the OneSignal Web SDK using Google Tag Manager (GTM), then optionally send External ID and OneSignal Tags after initialization.

Prerequisites

  • A site that supports HTTPS.
  • You can publish changes in GTM for the site’s container.
  • Complete the OneSignal Web SDK setup flow until you reach the step Add Code to Site. If you do this, you will have:

Setup

1. Set up your OneSignal web app

Follow Web SDK setup until you reach the step Add Code to Site. This is where you will get the OneSignal App ID.

Once you reach this step, you will need to make some adjustments to the code to work with Google Tag Manager.

You will need to upload the OneSignal Service Worker file to your server directly. More details found in the OneSignal Service Worker guide.

2. Create GTM variables

Create GTM variables for values you may reference across GTM tags. Using variables avoids hardcoding values and makes your setup easier to maintain. Create a OneSignal App ID variable
  1. In GTM, go to Variables > New.
  2. Choose Constant.
  3. Name it os_app_id.
  4. Set the value to your OneSignal App ID.
  5. Save.

Creating a OneSignal App ID variable

You can now reference your App ID anywhere in GTM using {{os_app_id}}.
Create an External ID variable (Recommended) Use this variable if you associate users with an external identifier (for example, a user ID from your database or auth system). Choose the variable type based on how the value is available on your site. Common options:
  • Data Layer Variable (recommended)
  • First-Party Cookie
  • DOM Variable (advanced)
Example: Data Layer Variable
  1. In GTM, go to Variables > New.
  2. Choose Data Layer Variable.
  3. Name it external_id.
  4. Set the Data Layer Variable Name to external_id.
  5. Do not set a default value.
  6. Save.
An example of how to push the value into the dataLayer will be provided in the next section.
Create a OneSignal ID variable (Optional) Use this variable if you want to reference the OneSignal ID in GTM (for example, an External ID is not set).
  1. In GTM, go to Variables > New.
  2. Variable Type: Data Layer Variable.
  3. Name it onesignal_id.
  4. Set the Data Layer Variable Name to onesignal_id.
  5. Do not set a default value.
  6. Save.
An example of how to push the value into the dataLayer will be provided in the next section.
The OneSignal ID is generated after subscription. If you plan to populate this value, you must explicitly push it into the dataLayer from a OneSignal callback.
Do not assume onesignal_id is immediately available on page load. It only exists after the user subscribes and the SDK returns the value.

3. Create the OneSignal init tag

  1. In GTM, go to Tags > New.
  2. Name the tag: OneSignal - Init
  3. Tag Type: Custom HTML
  4. Paste the code below
HTML
<script>
  // Ensure dataLayer exists before pushing events
  window.dataLayer = window.dataLayer || [];

  // OneSignal v16 GTM-friendly loader + init
  window.OneSignalDeferred = window.OneSignalDeferred || [];

  (function loadOneSignalSDK() {
    // Prevent double-loading if another tag/theme/plugin already loaded it
    if (window.OneSignal || document.getElementById('onesignal-sdk')) return;

    var s = document.createElement('script');
    s.id = 'onesignal-sdk';
    s.src = 'https://cdn.onesignal.com/sdks/web/v16/OneSignalSDK.page.js';
    s.async = true;

    s.onload = function () {
      // Queue init after SDK loads
      window.OneSignalDeferred.push(function (OneSignal) {
        OneSignal.init({
          appId: "{{os_app_id}}"
        })
        .then(function () {
          // Optional: use this as a GTM trigger signal for dependent tags
          window.dataLayer.push({ event: "OneSignalInitialized" });
        })
        .catch(function (e) {
          // Avoid breaking other tags; log for debugging
          console.error("OneSignal initialization failed:", e);
          window.dataLayer.push({
            event: "OneSignalInitFailed",
            oneSignalError: (e && e.message) ? e.message : String(e)
          });
        });
      });
    };

    s.onerror = function () {
      window.dataLayer.push({ event: "OneSignalSdkLoadFailed" });
    };

    document.head.appendChild(s);
  })();
</script>
  1. Configure the timing under Advanced Settings > Tag firing options to Once per page.
  2. Under Triggering, select Initialization - All Pages.

Configuring the OneSignal - Init tag

If you use a consent banner / CMP, see Consent Mode and privacy considerations options below.

4. Set External ID & Tags

Setting the External ID is optional but recommended because it allows you to identify users across devices and syncs with your backend.

Set external_id & caputure the onesignal_id

Use this tag when you want to:
  • Identify users in OneSignal with your own user ID (external_id)
  • Capture the OneSignal-generated ID for analytics or downstream GTM usage when no external ID exists
This assumes you are pushing the external_id into the dataLayer and using the {{external_id}} variable from step 2 above. For example:
HTML
<script>
  window.dataLayer = window.dataLayer || [];
  dataLayer.push({
    external_id: "user_12345"
  });
</script>
Tag configuration
  • Tag name: OneSignal – Set External ID or Get OneSignal ID
  • Tag type: Custom HTML
  • Tag firing options: Once per page (recommended)
  • Trigger: Use with event OneSignalInitialized (set in the above OneSignal - Init tag)
HTML
<script>
  window.dataLayer = window.dataLayer || [];
  window.OneSignalDeferred = window.OneSignalDeferred || [];

  // Helper function to validate the external ID
  function isValidExternalId(val) {
    if (val == null) return false;
    var s = String(val).trim().toLowerCase();
    if (!s) return false;
    return s !== "undefined" && s !== "null" && s !== "(not set)";
  }

  // Push Subscription Change Listener
  function pushSubscriptionChangeListener(event) {
    console.log("subscription ID", event.current.id);
    console.log("event.current.optedIn", event.current.optedIn);
    // Save the OneSignal ID to the dataLayer
    var oneSignalId = OneSignal.User && OneSignal.User.onesignalId;
    if (oneSignalId && event.current.optedIn) {
      console.log("oneSignalId: ", oneSignalId);
      dataLayer.push({
        event: "OneSignalIdAvailable",
        onesignal_id: oneSignalId
      });
    }
  }

  OneSignalDeferred.push(function (OneSignal) {
    // Save the external ID to the dataLayer
    var externalId = "{{external_id}}";
    if (isValidExternalId(externalId)) {
      console.log("externalId: ", externalId);
      OneSignal.login(String(externalId).trim())
        .then(function () {
          dataLayer.push({
            event: "OneSignalExternalIdSet",
            external_id: String(externalId).trim()
          });
        })
        .catch(function () {
          dataLayer.push({ event: "OneSignalExternalIdSetFailed" });
        });
    }

    // Set up Subscription Change Listener
    OneSignal.User.PushSubscription.addEventListener("change", pushSubscriptionChangeListener);
  });
</script>

Set Data Tags

This step sends User Data Tags to OneSignal using the Web SDK. Tag configuration
  • Name: OneSignal - Add Tags.
  • Tag Type: Custom HTML.
  • Tag firing options: Once per page (recommended)
  • Trigger:
    • Use with event OneSignalInitialized (set in the above OneSignal - Init tag)
    • Your condition for the tag to fire (e.g. “Login success”, “Profile page”, “Purchase”, etc.)
Paste this code and replace the example tag TAG and VALUE.
HTML
<script>
  window.OneSignalDeferred = window.OneSignalDeferred || [];
  window.OneSignalDeferred.push(function(OneSignal) {
    OneSignal.User.addTags({
      "TAG_1": "VALUE_1",
      "TAG_2": "VALUE_2"
    });
  });
</script>
Only send tags when you have the user data available (e.g., after login, after a profile loads, or after a known conversion event).
If your site uses Consent Mode / a CMP, decide whether OneSignal should load:
  • Only after consent (common for EU/UK), or
  • Immediately (common where “functional” storage is allowed by default).
GTM supports a Consent Initialization trigger and tag-level consent controls to manage tag behavior based on user consent. However, OneSignal also provides privacy consent methods to control when the SDK loads.

Testing

  1. In GTM, open Preview mode.
  2. Load your site and confirm:
    • OneSignal - Init fires once.
    • OneSignalInitialized appears in the GTM event timeline (if you kept the event push).
  3. Subscribe to your website. See Web permission prompts for prompting details.
  4. In the OneSignal dashboard, go to Audience > Subscriptions and confirm a Subscription appears after you opt in. You should also see an External ID if you set one.
  5. Send a test push from Messages > New Push.
If initialization is working, you’ll see the SDK loaded on the page and subscriptions appearing in OneSignal after opt-in.

Troubleshooting

  • Init tag fires, but SDK never loads
    • Check for Content Security Policy (CSP) blocking https://cdn.onesignal.com.
    • Check for ad blockers/script blockers.
  • dataLayer errors
    • Ensure window.dataLayer = window.dataLayer || [] is set before any dataLayer.push() calls.
  • Duplicate prompts / duplicate SDK load
    • Make sure you are not also loading OneSignal via site code, a CMS plugin, or another GTM tag.
  • Add Tags runs but doesn’t appear in OneSignal
    • Confirm the Trigger Group waits for OneSignalInitialized.
    • Confirm your user action trigger actually fires.
    • Confirm tags are valid key/value pairs and within Plan limits.
If you still need help, see Web SDK troubleshooting for common fixes.

Next steps