Skip to content

[Bug]: OneSignal.init() hangs on subsequent page navigations in iOS Safari PWA after push subscription is registered #1452

@sienori

Description

@sienori

What happened?

OneSignal.init() hangs for approximately 30 minutes when navigating to a page that calls init() in an iOS Safari PWA (added to home screen), after push notification permission has been granted and a subscription has been registered.

The issue does not occur on the first visit or before push registration. It only manifests after a push subscription exists.
This issue does not occur on macOS Chrome.

What browsers are you seeing the problem on?

Safari PWA — added to home screen

What operating system are you running?

iOS 18.3.2 (iPhone) / iOS 26.3.1 (iPad)

Steps to reproduce?

  1. Add the site as a PWA (Add to Home Screen) and open Page A.
    • init() completes successfully. ("!!!! OneSignal initialized" is logged.)
  2. Tap the link to navigate to Page B.
  3. Tap the link to navigate to Page A.
    • init() completes successfully.
  4. Tap the "Register" button to subscribe to push notifications.
    • Push subscription is created; test notifications are received.
  5. Tap the link to navigate to Page B.
  6. Tap the link to navigate to Page A.
    • init() hangs for 30 minutes. ("!!!! OneSignal initialized" is not logged until 30 minutes later.)

Minimal Reproduction Code

Page A (/A):

<!DOCTYPE html>
<html>
<head>
  <title>Test Page A</title>
  <script src="<https://cdn.onesignal.com/sdks/web/v16/OneSignalSDK.page.js>" defer></script>
  <script>
    console.log("!!!! OneSignal initialize");
    window.OneSignalDeferred = window.OneSignalDeferred || [];
    OneSignalDeferred.push(async function(OneSignal) {
      await OneSignal.init({
        appId: "YOUR_APP_ID"
      });
      console.log("!!!! OneSignal initialized");
    });
  </script>
</head>
<body>
  <h1>Test Page A</h1>
  <a href='/B'>Page B</a>
  <button onclick="requestNotificationPermission()">Register</button>
  <script>
    async function requestNotificationPermission() {
      window.OneSignalDeferred = window.OneSignalDeferred || [];
      OneSignalDeferred.push(async function(OneSignal) {
        await OneSignal.Notifications.requestPermission();
      });
    }
  </script>
</body>
</html>

Page B (/B): A simple page with a link back to Page A.

What did you expect to happen?

OneSignal.init() should resolve every time the page is loaded, regardless of whether a push subscription already exists.

Actual Behavior

When a push subscription already exists, OneSignal.init() hangs for approximately 30 minutes on subsequent navigations. The initialization stalls after [WM] Page listening and does not proceed to internalInit() / sessionInit() / establishSWChannel.

After 30 minutes, the SDK re-triggers the initialization flow from [WM] Page listening and eventually completes successfully (see "Recovery" log below).

Relevant log output

Successful initialization (before push registration)

[Log] !!!! OneSignal initialize (ja, line 9)
[Warning] PushSubscriptionNamespace: skipping initialization. One or more required params are falsy: initialize: false, subscription: undefined (OneSignalSDK.page.es6.js, line 1)
[Info] Web SDK loaded (version 160603, Browser environment). (OneSignalSDK.page.es6.js, line 1)
[Debug] Current Page URL: <https://xxxxx> (OneSignalSDK.page.es6.js, line 1)
[Debug] init() (OneSignalSDK.page.es6.js, line 1)
[Debug] Browser Environment: safari 18.3 (OneSignalSDK.page.es6.js, line 1)
[Debug] Final web app config: – {appId: "xxxxx", hasUnsupportedSubdomain: false, siteName: "xxxxx", …} (OneSignalSDK.page.es6.js, line 1)
{appId: "xxxxx", hasUnsupportedSubdomain: false, siteName: "xxxxx", origin: "<https://xxxxx>", restrictedOriginEnabled: false, …}Object
[Debug] CoreModule.init() (OneSignalSDK.page.es6.js, line 1)
[Warning] PushSubscriptionNamespace: skipping initialization. One or more required params are falsy: initialize: false, subscription: undefined (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getIdentityModel() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPropertiesModel() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModel() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModelByLastKnownToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getSubscriptionOfTypeWithToken({"type":"Push","token":""}) (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getAllPushSubscriptionModels() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModelByCurrentToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] [WM] Page listening (<https://xxxxxx>) (OneSignalSDK.page.es6.js, line 1)
[Info] Set pageTitle to be 'xxxxx'. (OneSignalSDK.page.es6.js, line 1)
[Debug] internalInit() (OneSignalSDK.page.es6.js, line 1)
[Debug] shouldInstallWorker state: – "None" (OneSignalSDK.page.es6.js, line 1)
[Debug] Page views: tab=2, total=3 (OneSignalSDK.page.es6.js, line 1)
[Debug] sessionInit() (OneSignalSDK.page.es6.js, line 1)
[Debug] establishSWChannel (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModel() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModelByLastKnownToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getSubscriptionOfTypeWithToken({"type":"Push","token":""}) (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getAllPushSubscriptionModels() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModelByCurrentToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] isOptedOut() (OneSignalSDK.page.es6.js, line 1)
[Debug] isOptedOut() (OneSignalSDK.page.es6.js, line 1)
[Info] handleAutoResubscribe – {autoResubscribe: true, isOptedOut: false} (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModel() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModelByLastKnownToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getSubscriptionOfTypeWithToken({"type":"Push","token":""}) (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getAllPushSubscriptionModels() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModelByCurrentToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] (Browser) » initializeInternal (OneSignalSDK.page.es6.js, line 1)
[Debug] Checking sub expiration (OneSignalSDK.page.es6.js, line 1)
[Log] !!!! OneSignal initialized (ja, line 15)
[Debug] Sub not expired (OneSignalSDK.page.es6.js, line 1)
[Debug] (Browser) » initialize (OneSignalSDK.page.es6.js, line 1)

Failed initialization (after push registration — hangs)

[Log] !!!! OneSignal initialize (ja, line 9)
[Warning] PushSubscriptionNamespace: skipping initialization. One or more required params are falsy: initialize: false, subscription: undefined (OneSignalSDK.page.es6.js, line 1)
[Info] Web SDK loaded (version 160603, Browser environment). (OneSignalSDK.page.es6.js, line 1)
[Debug] Current Page URL: <https://xxxxx> (OneSignalSDK.page.es6.js, line 1)
[Debug] init() (OneSignalSDK.page.es6.js, line 1)
[Debug] Browser Environment: safari 18.3 (OneSignalSDK.page.es6.js, line 1)
[Debug] Final web app config: – {appId: "xxxxx", hasUnsupportedSubdomain: false, siteName: "xxxxx", …} (OneSignalSDK.page.es6.js, line 1)
{appId: "xxxxx", hasUnsupportedSubdomain: false, siteName: "xxxxx", origin: "<https://xxxxx>", restrictedOriginEnabled: false, …}Object
[Debug] CoreModule.init() (OneSignalSDK.page.es6.js, line 1)
[Warning] PushSubscriptionNamespace: skipping initialization. One or more required params are falsy: initialize: false, subscription: undefined (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getIdentityModel() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPropertiesModel() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModel() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModelByLastKnownToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getSubscriptionOfTypeWithToken({"type":"Push","token":"<https://web.push.apple.com/xxxxx>"}) (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getAllPushSubscriptionModels() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModelByCurrentToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] [WM] Page listening (<https://xxxxx>) (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getSubscriptionOfTypeWithToken({"type":"Push","token":"<https://web.push.apple.com/xxxxx>"}) (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getAllPushSubscriptionModels() (OneSignalSDK.page.es6.js, line 1)

Recovery after ~30 minutes idle (initialization eventually resumes and completes)

[Debug] CoreModuleDirector.getPushSubscriptionModelByCurrentToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] [WM] Page listening (<https://xxxxx>) (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getSubscriptionOfTypeWithToken({"type":"Push","token":"<https://web.push.apple.com/xxxxx>"}) (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getAllPushSubscriptionModels() (OneSignalSDK.page.es6.js, line 1)
[Info] Set pageTitle to be 'XXXXX'. (OneSignalSDK.page.es6.js, line 1)
[Debug] internalInit() (OneSignalSDK.page.es6.js, line 1)
[Debug] shouldInstallWorker state: – "OneSignal Worker" (OneSignalSDK.page.es6.js, line 1)
[Info] Checking SW version... (OneSignalSDK.page.es6.js, line 1)
[Debug] [WM] Page->SW unicast 'GetWorkerVersion' (OneSignalSDK.page.es6.js, line 1)
[Debug] [WM] Page->SW direct 'GetWorkerVersion' (OneSignalSDK.page.es6.js, line 1)
[Debug] [WM] Page received: – {command: "GetWorkerVersion", payload: "160603"} (OneSignalSDK.page.es6.js, line 1)
[Info] SW version current: 160603 (OneSignalSDK.page.es6.js, line 1)
[Debug] Page views: tab=4, total=5 (OneSignalSDK.page.es6.js, line 1)
[Debug] sessionInit() (OneSignalSDK.page.es6.js, line 1)
[Debug] establishSWChannel (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModel() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModelByLastKnownToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getSubscriptionOfTypeWithToken({"type":"Push","token":"<https://web.push.apple.com/xxxxx>"}) (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getAllPushSubscriptionModels() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModelByCurrentToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getSubscriptionOfTypeWithToken({"type":"Push","token":"<https://web.push.apple.com/xxxxx>"}) (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getAllPushSubscriptionModels() (OneSignalSDK.page.es6.js, line 1)
[Debug] isOptedOut() (OneSignalSDK.page.es6.js, line 1)
[Debug] isOptedOut() (OneSignalSDK.page.es6.js, line 1)
[Info] handleAutoResubscribe – {autoResubscribe: true, isOptedOut: false} (OneSignalSDK.page.es6.js, line 1)
[Debug] shouldInstallWorker state: – "OneSignal Worker" (OneSignalSDK.page.es6.js, line 1)
[Info] Checking SW version... (OneSignalSDK.page.es6.js, line 1)
[Debug] [WM] Page->SW unicast 'GetWorkerVersion' (OneSignalSDK.page.es6.js, line 1)
[Debug] [WM] Page->SW direct 'GetWorkerVersion' (OneSignalSDK.page.es6.js, line 1)
[Debug] [WM] Page received: – {command: "GetWorkerVersion", payload: "160603"} (OneSignalSDK.page.es6.js, line 1)
[Info] SW version current: 160603 (OneSignalSDK.page.es6.js, line 1)
[Debug] SW ready, continuing subscription (OneSignalSDK.page.es6.js, line 1)
[Debug] Existing push sub options present (OneSignalSDK.page.es6.js, line 1)
[Debug] Subscribing with options: – {userVisibleOnly: true, applicationServerKey: ArrayBuffer} (OneSignalSDK.page.es6.js, line 1)
{userVisibleOnly: true, applicationServerKey: ArrayBuffer}Object
[Debug] CoreModuleDirector.getPushSubscriptionModel() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModelByLastKnownToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getSubscriptionOfTypeWithToken({"type":"Push","token":"<https://web.push.apple.com/xxxxx>"}) (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getAllPushSubscriptionModels() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModelByCurrentToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getSubscriptionOfTypeWithToken({"type":"Push","token":"<https://web.push.apple.com/xxxxx>"}) (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getAllPushSubscriptionModels() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getIdentityModel() (OneSignalSDK.page.es6.js, line 1)
[Debug] (Browser) » register (OneSignalSDK.page.es6.js, line 1)
[Debug] checkAndTriggerSubscriptionChanged() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModel() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModelByLastKnownToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getSubscriptionOfTypeWithToken({"type":"Push","token":"<https://web.push.apple.com/xxxxx>"}) (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getAllPushSubscriptionModels() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModelByCurrentToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getSubscriptionOfTypeWithToken({"type":"Push","token":"<https://web.push.apple.com/xxxxx>"}) (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getAllPushSubscriptionModels() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModel() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModelByLastKnownToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getSubscriptionOfTypeWithToken({"type":"Push","token":"<https://web.push.apple.com/xxxxx>"}) (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getAllPushSubscriptionModels() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModelByCurrentToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getSubscriptionOfTypeWithToken({"type":"Push","token":"<https://web.push.apple.com/xxxxx>"}) (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getAllPushSubscriptionModels() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModel() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModelByLastKnownToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getSubscriptionOfTypeWithToken({"type":"Push","token":"<https://web.push.apple.com/xxxxx>"}) (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getAllPushSubscriptionModels() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModelByCurrentToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getSubscriptionOfTypeWithToken({"type":"Push","token":"<https://web.push.apple.com/xxxxx>"}) (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getAllPushSubscriptionModels() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModel() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModelByLastKnownToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getSubscriptionOfTypeWithToken({"type":"Push","token":"<https://web.push.apple.com/xxxxx>"}) (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getAllPushSubscriptionModels() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getPushSubscriptionModelByCurrentToken() (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getSubscriptionOfTypeWithToken({"type":"Push","token":"<https://web.push.apple.com/xxxxx>"}) (OneSignalSDK.page.es6.js, line 1)
[Debug] CoreModuleDirector.getAllPushSubscriptionModels() (OneSignalSDK.page.es6.js, line 1)
[Debug] (Browser) » initializeInternal (OneSignalSDK.page.es6.js, line 1)
[Debug] Checking sub expiration (OneSignalSDK.page.es6.js, line 1)
[Log] !!!! OneSignal initialized (ja, line 15)
[Debug] Sub not expired (OneSignalSDK.page.es6.js, line 1)
[Debug] setupOnFocusAndOnBlurForSession (OneSignalSDK.page.es6.js, line 1)
[Debug] (Browser) » initialize (OneSignalSDK.page.es6.js, line 1)

Analysis

Comparing the two logs, the key differences are:

  1. Successful init: getSubscriptionOfTypeWithToken is called with an empty token (""), and the flow continues to Set pageTitle → internalInit() → sessionInit() → establishSWChannel → completion.
  2. Failed init: getSubscriptionOfTypeWithToken is called with a real Apple push token (https://web.push.apple.com/...), and the flow stalls after [WM] Page listening. It does not proceed to internalInit() for ~30 minutes.

This suggests the SDK may be waiting on a Service Worker response or some asynchronous operation related to the existing push subscription that does not resolve promptly in the iOS Safari PWA environment on subsequent navigations.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions