binpress

Building Useful Notifications with HTML5 APIs

Many users keep loads of tabs open in their browsers these days. Stuff they’re working on, things they want to read later, Twitter feeds. How is your site or application going to stand out anymore? What if you really want to draw a users attention? HTML 5 supplies us with a few JavaScript API additions that can help.

  • The Page Visibility API is the first. This allows you to get events if your application tab is moved away from the user but remains active.
  • The Web Notification API is the next. This allows you to create a pop-up that informs the user with your message.
  • Third is the Vibration API. It’s a tiny API but it adds a physical aspect to notifications.

If you look at the supported platforms you’ll see that the Page Visibility is supported on most current platforms. Web notifications are widely supported on desktop browsers, but mobile browsers unfortunately lack in support. Only the latest Android Browser supports it (not even Chrome for Android). Somewhat disappointing, I agree. The vibration API is better supported browser-wise (although not by iOS…) but — as you probably imagined — it’s a lost cause on most desktops and laptops.

Support may vary, but that can only improve over time. So let’s see how we can make the most out of it. First, I’ll show you how to use the individual APIs.

Vibration API

I’ll first blow you way with this awesome API. It allows you to make a user’s device vibrate

  1. //Make it vibrate for 300ms
  2. window.navigator.vibrate(300);
  3.  
  4. //But you can define patterns as well... on, off, on times in sequence
  5. window.navigator.vibrate([300,100,300])

Insultingly simple, I agree. One thing to note on the patterns though: I’ve found that for Android at least, the first buzz isn’t always treated correctly. If you use the pattern in my example, you might notice that the first vibration is considerably shorter than the second one. You might want to experiment a bit with it to get the result you’re after.

Page Visibility API

Next is a more interesting API. By registering your event handler to this you can get a signal whether or not your page is visible to the user. The example below is partially borrowed from MDN, but I tried to show which parts you’ll need for which web browser.

  1. // Currently different browsers have different events
  2. var hidden, visibilityChange;
  3. if (typeof document.hidden !== 'undefined') {
  4.     // Opera 12.10, Firefox >=18, Chrome >=31, IE11
  5.     hidden = 'hidden';
  6.     visibilityChangeEvent = 'visibilitychange';
  7. } else if (typeof document.mozHidden !== 'undefined') {
  8.     // Older firefox
  9.     hidden = 'mozHidden';
  10.     visibilityChangeEvent = 'mozvisibilitychange';
  11. } else if (typeof document.msHidden !== 'undefined') {
  12.     // IE10
  13.     hidden = 'msHidden';
  14.     visibilityChangeEvent = 'msvisibilitychange';
  15. } else if (typeof document.webkitHidden !== 'undefined') {
  16.     // Chrome <31 and Android browser (4.4+ !)
  17.     hidden = 'webkitHidden';
  18.     visibilityChangeEvent = 'webkitvisibilitychange';
  19. }
  20.  
  21. // Event handler: log change to browser console
  22. function visibleChangeHandler() {
  23.     if (document[hidden]) {
  24.         console.log('Page is not visible\n');
  25.     } else {
  26.         console.log('Page is visible\n');
  27.     }
  28. }
  29.  
  30. //Register event handler
  31. if (typeof document.addEventListener === 'undefined' ||
  32.              typeof document[hidden] === 'undefined'   ) {
  33.     console.log('Page Visibility API isn't supported, sorry!');
  34. } else {
  35.     document.addEventListener(visibilityChangeEvent, visibleChangeHandler, false);
  36. }

This example will support almost all versions of browsers that have implemented the event. If you’re looking to support only the most current browsers then you can do it much easier by registering the visibilitychange event. You can make it even easier on yourself by using the Visibility.js wrapper library which adds a hack to support older web browsers, should you need to.

As with the previous API, there are some notes to be made; desktop browsers will fire the event nicely when your tab loses focus. Unfortunately, you can’t depend on the event if your user switches to an other application than the web browser. Switching apps on Android fires the event in Chrome, Firefox and Opera (sorry, no iOS for me).

Web Notification API

The first thing to note when you apply the web notifications API is that you’ll need user consent to show a notification. This is probably better because your alerts could become annoying pretty fast, so respect your user by making sure notifications benefit, and don’t pester, them.

Using the API requires us to look for different window elements because older browsers might have this implemented in a prefixed manner:

  1. // Determine the correct object to use
  2. var notification = window.Notification || window.mozNotification || window.webkitNotification;
  3.  
  4. // The user needs to allow this
  5. if ('undefined' === typeof notification)
  6.     alert('Web notification not supported');
  7. else
  8.     notification.requestPermission(function(permission){});
  9.  
  10. // A function handler
  11. function Notify(titleText, bodyText)
  12. {
  13.     if ('undefined' === typeof notification)
  14.         return false;       //Not supported....
  15.     var noty = new notification(
  16.         titleText, {
  17.             body: bodyText,
  18.             dir: 'auto', // or ltr, rtl
  19.             lang: 'EN', //lang used within the notification.
  20.             tag: 'notificationPopup', //An element ID to get/set the content
  21.             icon: '' //The URL of an image to be used as an icon
  22.         }
  23.     );
  24.     noty.onclick = function () {
  25.         console.log('notification.Click');
  26.     };
  27.     noty.onerror = function () {
  28.         console.log('notification.Error');
  29.     };
  30.     noty.onshow = function () {
  31.         console.log('notification.Show');
  32.     };
  33.     noty.onclose = function () {
  34.         console.log('notification.Close');
  35.     };
  36.     return true;
  37. }

Here’s what you’ll see when you supply some text and an icon URL:

notification

Combining them all

Let’s see how we can combine these APIs together. I suggest the following scenario:

  • I’ll assume you already have some sort of notification queue in your application that you can query.
  • We periodically query the back end for notifications to show.
  • We only push a notification if the page isn’t visible and combine it with vibration, otherwise some foreground notification queue is assumed to show the notification.
  • If we can’t send the notification, we fall back to changing the tab title so that we might get a user’s attention.

Here’s the code:

  1. //Register event and requests permission
  2. document.addEventListener('visibilitychange', visibleChangeHandler, false);
  3. var notification = window.Notification || window.mozNotification || window.webkitNotification;
  4. notification.requestPermission(function(permission){});
  5.  
  6. //Poll our backend for notifications, set some reasonable timeout for your application
  7. window.setInterval(function() {
  8.     console.log('poll...');
  9.     jQuery.ajax({
  10.         url: 'site/notifyQueue',
  11.         dataType: 'json',
  12.         data: {userid:'1234', token:'other data'},    //Include your own data, think about CSRF!
  13.         success: function(data, status) {
  14.             notificationPoster(data, status);
  15.         }
  16.     });
  17. }, 5000);    //poll every 5 secs.
  18.  
  19. var originalTitle = '', messageCount = 0;
  20. function notificationPoster(data, status)
  21. {
  22.     if (document['hidden']) {
  23.         console.log('page not visible, use notification and vibrate');
  24.         //Vibrate and try to send notification
  25.         window.navigator.vibrate(500);
  26.         if (false == Notify(data.title, data.body)) {
  27.             //Fallback signaling which updates the tab title
  28.             if ('' == originalTitle)
  29.                 originalTitle = document.title;
  30.             messageCount++;
  31.             document.title = '('+messageCount+' messages!) '+originalTitle;
  32.         } else {
  33.             //Notification was shown
  34.         }
  35.     }
  36.     else {
  37.         console.log('page visible, push to normal notification queue');        
  38.         doYourOwnSignaling(data);
  39.  
  40.         //Reset fallback handling
  41.         messageCount = 0;
  42.         if ('' != originalTitle)
  43.             document.title = originalTitle;
  44.         originalTitle = '';
  45.     }
  46. }

Obviously, I’ve left out the actual notification implementation if the page is visible. That’s outside of the scope of this tutorial. I do, of course, have some suggestions for that:

  • noty.js, which is available here on Binpress, has a simple interface which you can send your message to immediately.
  • Alternatively Notifier.js implements a very nice style that resembles the browser type notifications on screen.
  • Try Google, there are so many out there….

It’s up to you really, you can implement it yourself or use one of the many libraries out there.

I hope these examples give you some inspiration to implement these APIs in your own application. Do let us know if this worked for you, or better yet, how you’ve improved it. Good luck!

Author: Arno Slatius

Scroll to Top