Getting Started

This is a developer's guide for setting up Airship web push notifications.

Setting up your website for web notifications is straightforward. This guide will take you through the required steps to configure your site in the Airship dashboard and add the required components to begin registering users for notifications.

 Note

An additional step is required if your site is not fully HTTPS. We'll provide a workaround script for these sites during the setup process. This workaround is not required for non-HTTPS sites on Safari.

The Airship Web SDK is hosted on a secure CDN (content delivery network). In order to enable web push notifications you will add two components to your site, and optionally a third component for sites that aren't fully HTTPS:

  1. An asynchronous loading snippet that allows use of the SDK before and after it is fully loaded.

  2. A service worker that handles incoming push requests and communicates with the Airship service.

  3. For non-secure (non-HTTPS) sites only: An HTML bridge.

Resources


 Note

Supported Browsers

  • Desktop: Google Chrome, Mozilla Firefox, Opera, and Safari.

  • Android Mobile: Google Chrome, Mozilla Firefox, Opera, Microsoft Edge.

Airship Setup

Begin by configuring your site in the dashboard.

  1. Complete the steps in Configure Web Notifications. When you complete these steps, your setup files will be placed in a ZIP file.

  2. Unzip the downloaded file to access your setup files for the remaining steps.

Add JavaScript Snippet

In your unzipped directory, locate snippet.html. This file provides an asynchronous loading snippet that allows use of the Web SDK before it loads, and comes populated with the configuration values required for your site.

snippet.html
<script type="text/javascript">
!function(n,t,c,e,u){function r(n){try{f=n(u)}catch(n){return h=n,void i(p,n)}i(s,f)}function i(n,t){for(var c=0;c<n.length;c++)d(n[c],t);
}function o(n,t){return n&&(f?d(n,f):s.push(n)),t&&(h?d(t,h):p.push(t)),l}function a(n){return o(!1,n)}function d(t,c){
n.setTimeout(function(){t(c)},0)}var f,h,s=[],p=[],l={then:o,catch:a,_setup:r};n[e]=l;var v=t.createElement("script");
v.src=c,v.async=!0,v.id="_uasdk",v.rel=e,t.head.appendChild(v)}(window,document,'https://web-sdk.urbanairship.com/notify/v1/ua-sdk.min.js',
  'UA', // This value can be changed to use a custom variable name.
  {
  appKey: 'YOUR-APP-KEY',
  token: 'BEARERTOKEN-FROM-UA',

  // Safari Web Push only
  websitePushId: 'WEBSITE-PUSH-ID-FROM-UA',
  // Open Web Push Protocol only.
  vapidPublicKey: 'WEB-PUSH-KEY-FROM-UA',
  // Only needed when used on insecure hosts:
  secureIframeUrl: 'https://your.secure.domain/path/to/web-push-secure-bridge.html'
  })
</script>

You should place the snippet on all pages of your site.

UA Object

The loading snippet adds a UA object to the global scope. This object provides promise-like then and catch functions. They can be called as many times as you'd like and can be chained like promises.

UA.then(function(sdk) {
  console.log(sdk.channel.id)
}).catch(function(err) {
  console.log(err)
})

// Multiple calls have no additional expense.
UA.then(function(sdk) {
  $('#register').show()
  $('#register').click(function(ev) { sdk.register() })
})

UA.then(cb) Takes a callback function that is called with sdk as its only argument. It is only called if the SDK loads successfully and the browser supports all features. All other features of the SDK can be used from here.

UA.catch(cb) Takes a callback function that is called with the error object as its only argument. It is only called if the SDK encounters an error while loading or the browser is unsupported.

UA.then will only be called when the SDK has been loaded and if the browser supports the SDK's features. Do not rely on it being called in every browser. Because of this it is good practice to not enable UA SDK-specific parts of your UI until the SDK has loaded.

Unsupported browsers will call .catch(), which likewise will only be called if loading the SDK has an error.

Service Worker

When configured for Open Web Push Protocol browsers (Chrome, Firefox, Opera, Edge), web push employs a service worker, which runs as a background process until woken up to perform SDK tasks, e.g., displaying notifications.

 Note

When desktop Safari is the only browser configured for web push, there is no service worker.

A service worker called push-worker.js is one of the setup files generated when you configure your project for web push in Airship Setup.

push-worker.js
importScripts('https://web-sdk.urbanairship.com/notify/v1/ua-sdk.min.js')
uaSetup.worker(self, {
  appKey: 'YOUR-APP-KEY',
  vapidPublicKey: 'WEB-PUSH-KEY-FROM-UA',
  token: 'BEARERTOKEN-FROM-UA',

  // The icon and title that your push notification will use if the
  // notification payload does not include them.
  defaultIcon: 'https://upload.wikimedia.org/220px-Urban_Airship_Logo.jpg',
  defaultTitle: 'My Cool Website',

  // A URL that clicking a notification will open if you select "Home Page"
  // as your action. If no url is supplied clicking a notification will simply
  // close it.
  defaultActionURL: 'https://example.com',
})
 Tip

For further reading on service workers, see these excellent primers from Google and Mozilla:

Service Worker Location

It is imperative that you place the service worker in the root directory of your site at the beginning of your implementation so that your entire website is within the scope of the worker.

The JavaScript snippet that you added to your site pages contains a URL for push-worker.js** and assumes it is placed in the root.

If you are unable to place it in the root, your entire site may not be able to access the service.

If you need to combine the push worker with an existing service worker, you may need to specify a new location for your worker file. You can do this by adding a workerUrl: '/service-worker.js', setting to your on-page snippet, inside your service worker, and to your secure-bridge.html if you're using one.

Troubleshooting: Duplicate Web Notifications

If for any reason you have moved the service worker, e.g., from a non-root location to the root directory, users may receive duplicate push notifications.

This is because users may have a browser-cached service worker running even though the file has been moved, and subscriptions are tied to push worker location. If they register again with the new (or newly-moved) service worker, they will have a new channel ID.

 

Add a new push-worker.js in prior location of service worker to unsubscribe users from duplicate notifications
self.onactivate = function (ev) {
  self.registration.pushManager.getSubscription().then(subscription => {
    if (subscription) {
      subscription.unsubscribe()
    }
  })
}

To help out in situations like this, we have provided a bit of code (think of it as a “cleanup” service worker) that can be placed at the location of the original service worker. The process here is simple. All you have to do is put this code in a push-worker.js file placed where your previous service worker lived.

Once you’ve done this, browsers will detect the change and unsubscribe any subscriptions tied to that worker location. And don’t worry, this will not affect your Airship channels or any registrations tied to any other service worker locations.

Secure Domain Bridge (HTTP Scenarios Only)

If you checked the Secure Bridge box when configuring your Open Web Push Protocol push in step 1, you will have secure-bridge.html in your setup files.

secure-bridge.html
<!DOCTYPE html>
<html><head></head><body>
    <script type="text/javascript" rel="secureBridge" src="https://web-sdk.urbanairship.com/notify/v1/ua-sdk.min.js"></script>
    <script type="text/javascript">uaSetup.secureBridge({
        appKey: 'YOUR-APP-KEY'
    })</script>
</body></html>
 Note

If you configure Safari only, you will not have a Secure Bridge option.

In mixed-HTTPS situations you will need to add a web-push-secure-bridge.html on your secure domain that contains this HTML, and make sure your uaSetup() call includes the correct path to it.

See these instructions to complete this step, if necessary: Secure Integration.

Send Your First Push Notification

Now that you have configured your project for web push and are able to register users, it's time to send a test notification. You can do this via either the dashboard or our API.

To send a push via the dashboard, see the Web Push Notification Tutorial.

To send a web push via our API, two examples are provided below, one only to web browsers, and one to web, iOS, and Android.

Web Only Push

In this example, we will introduce the push object, the required request body for sending a notification via the push API, using the three required attributes audience, device_types, and notification.

Audience
We'll start with the simplest audience selector possible: an individual channel ID. For testing purposes, you can retrieve your channel ID from a registered browser by entering UA.then(sdk => console.log(sdk.channel.id)) in the JavaScript console.
Device Types
Since we are only sending to web devices, we will specify the "web" device type as an array of one. In the next example, we will include additional device types.

Alternatively, you could specify the special string "all", which maps to all configured platforms for your project, e.g., "device_types": "all".
Notification
Finally, we will specify the values for our test notification, including the alert text, and web push-specific attributes that we will include in the web platform override object. Platform overrides can be used either to override a value for a specific platform or to specify values that are only applicable to that platform.
Example Request: Web only push
POST /api/push HTTP/1.1
Authorization: Basic <master authorization string>
Content-Type: application/json
Accept: application/vnd.urbanairship+json; version=3;

{
   "audience": {
      "channel": "<YOUR_CHANNEL_ID>"
   },
   "device_types": [
      "web"
   ],
   "notification": {
      "alert": "Hello, Web!",
      "web": {
         "title": "My First Web Push Title",
         "require_interaction": true,
         "icon": {
            "url": "https://example.com/icon.png"
         }
      }
   }
}

Push to Multiple Platforms

This example illustrates sending a push notification to a named user, "sven_svensson", who is registered on multiple platforms, including web.

In the top-level notification attribute of the payload, the value for the alert property is "Hello, World!". Since we want our web users to experience the most relevant content possible, we are going to use the web override on the notification object to specify the more appropriate "Hello, Web!" alert message for web users.

Example Request: Push to multiple platforms
POST /api/push HTTP/1.1
Authorization: Basic <master authorization string>
Content-Type: application/json
Accept: application/vnd.urbanairship+json; version=3;

{
   "audience": {
      "named_user": "sven_svensson"
   },
   "device_types": [
      "web",
      "ios",
      "android"
   ],
   "notification": {
      "alert": "Hello, World!",
      "web": {
         "alert": "Hello, Web!",
         "title": "My First Web Push Title",
         "require_interaction": true,
         "icon": {
            "url": "https://example.com/icon.png"
         }
      }
   }
}

Additional Resources

Web SDK

This section is an introduction to the Web SDK and associated methods.

Please visit our Airship Web SDK Reference for a complete reference.

UaSDK

The main Web SDK object. It can not be instantiated manually. It is returned by the async loader.

Register

Follow these steps to register the current browser with Airship.

  • Fetch the browser's subscription object, prompting the user for permission if necessary.

  • Collect browser information for out-of-the-box tag segmentation.

  • Register with Airship and resolve the returned channel object.

  • Resolves an error that can be caught if there is an error while registering or the browser is not a secure context. See canRegister.

Example registration
UA.then(function(sdk) {
  sdk.register() // Returns Channel object
})

Filter Out Non-Compliant Browsers

Filter out any browsers that do not support web push. The SDK is supported on HTTP locations where it can NOT register, provided that the secure bridge is enabled.

Example filter
UA.then(function(sdk) {
  sdk.isSupported // Returns bool
})

Validate Browser Support and Security

Make sure that the current browser has web push features AND is in a secure context capable of attempting registration.

Example
UA.then(function(sdk) {
  sdk.canRegister // Returns bool
})

This is true if the browser isSupported and if window.isSecureContext is true.

 Note

Safari can register Safari users with Airship from insecure domains without the use of the secure bridge. Any domain that is running the SDK and configured in the Allowed Domains section of the Safari configuration in Airship can register Safari users. The SDK cannot verify that it is on an allowed domain before attempting to register users. Attempting to register users on a domain that is not explicitly allowed in your Safari configuration will fail.

Channel Object

If a browser has registered, sdk.channel will give you the channel object for that browser.

Example
UA.then(function(sdk) {
  // Return the current Channel ID
  sdk.channel.id // Returns String

  // Return the opted-in status
  sdk.channel.optedIn // Returns bool

  // Opt this device out of web push
  sdk.channel.optOut() // Returns true if successful
  // In order to opt back in you must call `sdk.register()` again.
})
 Note

sdk.channel returns null if unregistered.

Event Listeners

The main SDK object fires a channel event when a channel is registered, loaded or changed.

UA.then(function(sdk) {
  sdk.addEventListener('channel', function(ev) {
    ev.channel === sdk.channel
  })
})

The main SDK object fires a tags event any time the tags change.

UA.then(function(sdk) {
  sdk.addEventListener('tags', function(ev) {
    ev.tags === sdk.channel.tags.list
  })
})

If you are on an HTTPS page that is in-scope of your push-worker.js: The main SDK object fires a push event when the browser receives a push.

UA.then(function(sdk) {
  sdk.addEventListener('push', function(ev) {
    // ev.push is the push payload object
  })
})