Using Notifications API combined with page visibility API

David Carr

6 min read - 11th Feb, 2016

HTML 5 has some great API’s one of which is the notifications api which lets you set browser notifications to the end user, outside of the website scope so they can be issued when the user switches to another tab or application.

Mozilla Developer Network describes Notifications API best: 

The Notifications API allows web pages to control the display of system notifications to the end user — these are outside the top-level browsing context viewport, so therefore can be displayed even the user has switched tabs or moved to a different app. The API is designed to be compatible with existing notification systems across different platforms.

You should have seen got a popup when first landing on this page if not you may need to reload the page to initialize the permission request, the permission request will permission to show notifications, if accepted notifications can be displayed.

Notification API

The notifications API is JavaScript based. This js code will check if the browser supports the API and then check if permission has been given to run. If no permission request has ran a new request will run.

If granted set isGranted to true this will be used to run the notification next.

//default to false
var isGranted = false;

//check if the browser supports notifications
if (!("Notification" in window)) {
    //console.log("This browser does not support desktop notification");
} else if (Notification.permission === "granted") {
    //set to true
    isGranted = true;
} else if (Notification.permission !== 'denied') {

    //ask user for permission
    Notification.requestPermission(function (permission) {
        if (permission === "granted") {
            //set to true
            isGranted = true;
        }
    });
}

If granted is equal to true. This include the Vibration API to vibrate mobile devices, at the time of writing this IOS is not supported only Android. Pass the number of seconds to milliseconds vibrate.

Next create the notification, for convenience I’m using variables here so it can be wrapped in a function and passed data to it which is displayed further down. The parameters being used are the title, path to an icon and the message to display.

Next get the current document title and store it so it can be manipulated and changes back later. Update the document title as add (new message) before the title, this can be changed to anything you like.

use notification.onclick to watch for click events then direct to the url (again this is a convenience function passed to the function) close the notification window before going to the url.

When the notification window closed set the document title back to the original.

if(isGranted == true){

    //use the vibrate api
    window.navigator.vibrate(500);

    //create a new notification
    var notification = new Notification(title,{ icon: icon , body: body});

    //get the document title and store it
    var originalTitle = document.title;

    //change document title
    document.title = '(new message!) ' + originalTitle;

    //when clicked close the notification and go to the url
    notification.onclick = function () {
        notification.close();
        window.location.href = url;
    };

    //when closing the notification change the document title
    notification.onclose = function () {
        //change document title back to original
            document.title = originalTitle;
    };
}

To call the permissions request:

//request permission
Notification.requestPermission();

I’m wrapping this code inside a function for easy reuse:

function notifyMe(title, body, icon, url) {

Calling the function and passing the data

notifyMe('Hello!', "Hey it's working!", 'https://dcblog.dev/favicon.ico', 'https://dcblog.dev');

This all works really well but alerting users whilst on the website already could be off putting to the user, instead only show the notifications if the user is on another tab and not focusing on the website. 

Page Visibility API

This page visibility api gives the ability to detect is the user is on the page or on another tab using an addEventListener check for when visibilitychange is fired, when it does call visibleChangeHandler this is a custom functon so you can name this anything you like.

document.addEventListener('visibilitychange', visibleChangeHandler, false);

Annoyingly getting this to work on different browsers requests different prefixed, I don’t know why they can’t all use document.hidden!

This snippets checks the different browser prefixed to determine when the page is active or not, then a simple if statement can be used if(document[hidde’]){

function visibleChangeHandler() {

    var hidden, visibilityChange;
    if (typeof document.hidden !== 'undefined') {
        // Opera 12.10, Firefox >=18, Chrome >=31, IE11
        hidden = 'hidden';
        visibilityChangeEvent = 'visibilitychange';
    } else if (typeof document.mozHidden !== 'undefined') {
        // Older firefox
        hidden = 'mozHidden';
        visibilityChangeEvent = 'mozvisibilitychange';
    } else if (typeof document.msHidden !== 'undefined') {
        // IE10
        hidden = 'msHidden';
        visibilityChangeEvent = 'msvisibilitychange';
    } else if (typeof document.webkitHidden !== 'undefined') {
        // Chrome <31 and Android browser (4.4+ !)
        hidden = 'webkitHidden';
        visibilityChangeEvent = 'webkitvisibilitychange';
    }

    //check if document is visible
    if (document[hidden]) {
        console.log('Page is not visible');
    } else {
        console.log('document is not visible');
    }
}

Having this code and open your browser inspector’s console tab move away from the page to another tab and back again the console will update.

Putting it all together

Now lets only show notifications if the user is on a different tab:

//when visibility changes update visibleChangeHandler function
document.addEventListener('visibilitychange', visibleChangeHandler, false);

function visibleChangeHandler() {

    var hidden, visibilityChange;
    if (typeof document.hidden !== 'undefined') {
        // Opera 12.10, Firefox >=18, Chrome >=31, IE11
        hidden = 'hidden';
        visibilityChangeEvent = 'visibilitychange';
    } else if (typeof document.mozHidden !== 'undefined') {
        // Older firefox
        hidden = 'mozHidden';
        visibilityChangeEvent = 'mozvisibilitychange';
    } else if (typeof document.msHidden !== 'undefined') {
        // IE10
        hidden = 'msHidden';
        visibilityChangeEvent = 'msvisibilitychange';
    } else if (typeof document.webkitHidden !== 'undefined') {
        // Chrome <31 and Android browser (4.4+ !)
        hidden = 'webkitHidden';
        visibilityChangeEvent = 'webkitvisibilitychange';
    }

    //check if document is visible
    if (document[hidden]) {
        //Page is not visible
        notifyMe('Hello!', "Hey it's working!", 'https://dcblog.dev/favicon.ico', 'https://dcblog.dev');
    } else {
        //document is not visible do nothing.
    }
}

function notifyMe(title, body, icon, url) {

    //default to false
    var isGranted = false;

    //check if the browser supports notifications
    if (!("Notification" in window)) {
        //console.log("This browser does not support desktop notification");
    } else if (Notification.permission === "granted") {
        //set to true
        isGranted = true;
    } else if (Notification.permission !== 'denied') {

        //ask user for permission
        Notification.requestPermission(function (permission) {
            if (permission === "granted") {
                //set to true
                isGranted = true;
            }
        });
    }

    if(isGranted == true){

        //use the vibrate api
        window.navigator.vibrate(500);

        //create a new notification
        var notification = new Notification(title,{ icon: icon , body: body});

        //get the document title and store it
        var originalTitle = document.title;

        //change document title
        document.title = '(new message!) ' + originalTitle;

        //when clicked close the notification and go to the url
        notification.onclick = function () {
            notification.close();
            window.location.href = url;
        };

        //when closing the notification change the document title
        notification.onclose = function () {
            //change document title back to original
                document.title = originalTitle;
        };
    }

    //request permission
    Notification.requestPermission();
}
0 comments
Add a comment

Copyright © 2024 DC Blog - All rights reserved.