Notification Listener Documentation – Windows 10


New in Anniversary Update (build 14352 or newer): Notification Listener is a new feature in the Anniversary Update of Windows 10 that allows apps to access the user’s notifications on Mobile and Desktop. Note that you must target SDK 14332 or newer to use the Notification Listener.

Smartwatches can use Notification Listener to send the phone’s notifications to the wearable device. Home automation apps could perform actions when certain notifications are received, like if you receive a notification from your best friend.

At its core, Listener allows…

Adding the capability for Listener

You must add a capability to your app manifest for Listener. Right now, the capability must be added by manually editing the Pacakge.appxmanifest file…

  1. Add a namespace for uap3
  2. Add uap3 to the IgnorableNamespaces
  3. Add the uap3 capability with the name “userNotificationListener”

Ignore the blue line, it’ll compile.

<?xml version="1.0" encoding="utf-8"?>
<Package
    xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
    xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
    xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
    xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
    IgnorableNamespaces="uap mp uap3">
  ...
  <Capabilities>
    <Capability Name="internetClient" />
    <uap3:Capability Name="userNotificationListener" />
  </Capabilities>
</Package>

Checking whether Listener is supported

If your app supports older versions of Windows 10, you need to check whether the Listener is supported. You do this by using ApiInformation. If Listener isn’t supported, avoid executing any calls to the Listener API’s.

if (ApiInformation.IsTypePresent("Windows.UI.Notifications.Management.UserNotificationListener"))
{
    // Listener supported!
}

else
{
    // Older version of Windows, no Listener
}

Requesting access to use Listener

Since this API allows access to the user’s notifications, the user needs to grant permission for your app to access their notifications. During your app’s first-run experience, you should request access to use Listener. If you want, you can show some preliminary UI that explains why your app needs access to the user’s notifications before you call RequestAccessAsync, so that the user understands why they should allow access.

// Get the listener
UserNotificationListener listener = UserNotificationListener.Current;

// And request access to the user's notifications (must be called from UI thread)
UserNotificationListenerAccessStatus accessStatus = await listener.RequestAccessAsync();

switch (accessStatus)
{
    // This means the user has granted access.
    case UserNotificationListenerAccessStatus.Allowed:

        // Yay! Proceed as normal
        break;

    // This means the user has denied access.
    // Any further calls to RequestAccessAsync will instantly
    // return Denied. The user must go to the Windows settings
    // and manually allow access.
    case UserNotificationListenerAccessStatus.Denied:

        // Show UI explaining that listener features will not
        // work until user allows access.
        break;

    // This means the user closed the prompt without
    // selecting either allow or deny. Further calls to
    // RequestAccessAsync will show the dialog again.
    case UserNotificationListenerAccessStatus.Unspecified:

        // Show UI that allows the user to bring up the prompt again
        break;
}

The user can revoke access at any time via Windows Settings. Therefore, your app should always check the access status via the GetAccessStatus method before executing any major blocks of code. If the user revokes access, the API’s will silently fail rather than throwing an exception (for example, the API to get all notifications will simply return an empty list).

Read-access to the user’s notifications

With the Listener, you can get a list of the user’s current notifications. Simply call the GetNotificationsAsync method, and specify the type of notifications you want to get (currently, the only type of notifications supported are Toast Notifications).

// Get the toast notifications
IReadOnlyList<UserNotification> notifs = await listener.GetNotificationsAsync(NotificationKinds.Toast);

Displaying the notifications

Each notification is represented as a UserNotification, which provides information about the app that the notification is from, the time the notification was created, the notification’s ID, and the notification itself.

Note: We recommend surround all your code for processing a single notification in a try/catch, in case an unexpected exception occurs when you are capturing a single notification. There might be a bug in your code, or there might be a bug in the Windows platform – in either case, you shouldn’t completely fail to display other notifications just because of one specific notification.

public sealed class UserNotification
{
    public AppInfo AppInfo { get; }
    public DateTimeOffset CreationTime { get; }
    public uint Id { get; }
    public Notification Notification { get; }
}

Using AppInfo, you can obtain the information necessary to display the notification…

// Select the first notification
UserNotification notif = notifs[0];

// Get the app's display name
string appDisplayName = notif.AppInfo.DisplayInfo.DisplayName;

// Get the app's logo
BitmapImage appLogo = new BitmapImage();
RandomAccessStreamReference appLogoStream = notif.AppInfo.DisplayInfo.GetLogo(new Size(16, 16));
await appLogo.SetSourceAsync(await appLogoStream.OpenReadAsync());

The content of the notification itself, like the notification text, is contained in the Notification property. This property contains the visual portion of the notification. If you are familiar with sending notifications on Windows, you will notice that the Visual and Bindings properties in the Notification object match to what developers send when popping a notification.

We want to look for the Toast binding (for error-proof code, you should check that the binding isn’t null). From the binding, you can obtain the text elements. You can choose to display as many text elements as you would like. Ideally, you should display them all. You can choose to treat the text elements differently; for example, treat the first one as title text, and subsequent as body text.

// Get the toast binding, if present
NotificationBinding toastBinding = notif.Notification.Visual.GetBinding(KnownNotificationBindings.ToastGeneric);

if (toastBinding != null)
{
    // And then get the text elements from the toast binding
    IReadOnlyList<AdaptiveNotificationText> textElements = toastBinding.GetTextElements();

    // Treat the first text element as the title text
    string titleText = textElements.FirstOrDefault()?.Text;

    // We'll treat all subsequent text elements as body text,
    // joining them together via newlines.
    string bodyText = string.Join("\n", textElements.Skip(1).Select(t => t.Text));
}

Remove a specific notification

If your wearable or service allows the user to dismiss notifications, you can remove the actual notification so the user doesn’t see it later on their phone or PC. Simply provide the notification ID (obtained from the UserNotification object) of the notification you’d like to remove…

// Remove the notification
listener.RemoveNotification(notifId);

Clear all notifications

Use this with caution. You should only clear all notifications if your wearable or service displays ALL notifications. If your wearable or service only displays certain notifications, when the user clicks your “Clear notifications” button, the user is only expecting those specific notifications to be removed… however, calling the Clear API would actually cause all the notifications, including ones that your wearable or service wasn’t displaying, to be removed.

// Clear all notifications. Use with caution.
listener.ClearNotifications();

Background task trigger for notification added/dismissed

In order for your app to listen to notifications, you will likely need to set up a background task, so that you can know when a notification was added or dismissed regardless of whether your app is currently running.

Thanks to the single process model added in the Anniversary Update, adding background tasks is extremely easy. In your main app’s code, after you have obtained the user’s access to Notification Listener and obtained access to run background tasks, simply register a new background task, and set the UserNotificationChangedTrigger using the Toast kind.

// TODO: Request/check Listener access via UserNotificationListener.Current.RequestAccessAsync

// TODO: Request/check background task access via BackgroundExecutionManager.RequestAccessAsync

// If background task isn't registered yet
if (!BackgroundTaskRegistration.AllTasks.Any(i => i.Value.Name.Equals("UserNotificationChanged")))
{
    // Specify the background task
    var builder = new BackgroundTaskBuilder()
    {
        Name = "UserNotificationChanged"
    };

    // Set the trigger for Listener, listening to Toast Notifications
    builder.SetTrigger(new UserNotificationChangedTrigger(NotificationKinds.Toast));

    // Register the task
    builder.Register();
}

Then, in your App.xaml.cs, override the OnBackgroundActivated method if you haven’t yet, and use a switch statement on the task name to determine which of your many background task triggers was invoked.

protected override async void OnBackgroundActivated(BackgroundActivatedEventArgs args)
{
    var deferral = args.TaskInstance.GetDeferral();

    switch (args.TaskInstance.Task.Name)
    {
        case "UserNotificationChanged":
            await MyWearableHelpers.SyncNotifications();
            break;
    }

    deferral.Complete();
}

The background task is simply a shoulder tap. It does not provide any information about which specific notification was added or removed. When your background task is triggered, you should sync the notifications on your wearable so that they reflect the notifications in the platform. This ensures that if your background task fails, notifications on your wearable can still be recovered the next time your background task executes.

For the implementation of the SyncNotifications method, please see Determining which notifications were added and removed below.

Determining which notifications were added and removed

In order to determine which notifications have been added or removed (syncing notifications with your wearable), you have to calculate the delta between your current notification collection, and the notifications in the platform.

// Get all the current notifications from the platform
IReadOnlyList<UserNotification> userNotifications = await listener.GetNotificationsAsync(NotificationKinds.Toast);

// Obtain the notifications that our wearable currently has displayed
IList<uint> wearableNotificationIds = GetNotificationsOnWearable();

// Copy the currently displayed into a list of notification ID's to be removed
var toBeRemoved = new List<uint>(wearableNotificationIds);

// For each notification in the platform
foreach (UserNotification userNotification in userNotifications)
{
    // If we've already displayed this notification
    if (wearableNotificationIds.Contains(userNotification.Id))
    {
        // We want to KEEP it displayed, so take it out of the list
        // of notifications to remove.
        toBeRemoved.Remove(userNotification.Id);
    }

    // Othwerise it's a new notification
    else
    {
        // Display it on the Wearable
        SendNotificationToWearable(userNotification);
    }
}

// Now our toBeRemoved list only contains notification ID's that no longer exist in the platform.
// So we will remove all those notifications from the wearable.
foreach (uint id in toBeRemoved)
{
    RemoveNotificationFromWearable(id);
}

Foreground event for notification added/dismissed

Known Issue: The foreground event DOES NOT WORK (we’re looking at fixing that in the future). If you have a scenario that requires the foreground event, please let us know. However, most (if not all) scenarios should actually use the background task anyways, since your app most likely needs to be woken up in the background for notification events. For example, your wearable accessory app is rarely in the foreground, and needs to know about new notifications from the background.

Additionally, thanks to the single process model, it’s effortless to use background task triggers from within your foreground app. So if you do need to receive foreground events, just use the background trigger with single process model.

// Subscribe to foreground event
listener.NotificationChanged += Listener_NotificationChanged;

private void Listener_NotificationChanged(UserNotificationListener sender, UserNotificationChangedEventArgs args)
{
    // NOTE: This event DOES NOT WORK. Use the background task instead.
}

Known Issues

  • Investigating: Text elements that are inside group/subgroups (like Weather toast notifications) are returned (expected behavior is that only top-level text elements are returned)
  • On the backlog for future: Foreground event for NotificationChanged doesn’t fire
Comments (34)

  1. Neil Kay says:

    Interesting stuff, Andrew. I watched a couple of the action center / toast build conferences, and this feels like it could be useful and a time saver on cross platform notification infrastructure.

    We have a use case that feels like this can help, but it’s not one covered in the build sessions nor can I find any documentation online.

    We have a heavy desktop PC (win32) application – kind of like embedded software for a physical machine (let’s call it a robot) – which an operator will push a button and come back to it hours later when it should be done. If there’s errors, we want to alert them to go back to the machine. We have sample code to cause a toast to be sent, so if the operator is logged into another PC, then the toast can be seen. We were desiring this also to be able to send the toast to mobile (if they are using Windows Phone or Cortana on Android/iOS).

    There isn’t and would never be a full App of our product on mobile, as it’s far too heavy and requires PC drivers to move the hardware (robot). We were thinking would would need to start writing a Xamarin app in order to get push notifications displayed on their mobile.

    What we saw at build seems like it opens up new, simpler, possibilities. However, the mirroring of the mobile notifications demod seemed to be synching mobile TO PC, but not the other way. i.e. For us, we want a notification our Application creates on a PC, which appears in the PC Action Center, we want to synch so it also shows as a mobile notification. Is that currently possible with the mirrored notifications? Initial tests didn’t appear to work, even though I’m running Win10 latest, I’m signed in to same microsoft account on both, and I’ve got latest Cortana on Android (side loaded as not released in UK yet)…

    Are the mirrored notifications supposed to be bi-directional, either now, or potentially in the not too distant future?
    If currently it’s only mirroring mobile to PC, would writing a light mobile App of the same name/ID as our desktop app, where the notification listener technique (published here) is used to look for notifications from our PC application, and generating local notifications on the phone, work for this scenario?

    Thanks

    1. andrewbares7 says:

      Hey Neil! Your best option right now would be to make a basic mobile app that users install on their phones, which you can then send push notifications to. The app wouldn’t need to do anything else, so it should be relatively simple.

      You’re correct that notification mirroring only works from Mobile to PC, and not the other direction. We’ve considered doing the other direction, but we’re not sure most users would find that valuable. But we haven’t closed the door on it. There’s just no immediate plans.

      Rather than writing an app that uses Notification Listener on the PC and then sends the notifications to the phone (which would mean writing two apps, or at least two major components), I would go with the solution I proposed at the beginning – because in either case you still need your user to install something on their phone.

  2. Ehad Akeila says:

    Hi Andrew,

    Thanks a lot for sharing this. I’m still in the process of testing feature. I noticed that “Listener_NotificationChanged” event is not triggered in the foreground. The background process seems to work fine.

    Also, I was wondering if the following events can be captured in this feature:
    – When a phone call is received. I dont think this will be placed in the notification until the call is missed. Is this correct?
    – Is there any events/control for the main music in the phone/PC. It would be useful to control the running music from external device like smartwatch for example.

    Kind Regards
    Ehad

    1. andrewbares7 says:

      Hey Ehad! Hmm, I’ll check out the foreground event and see if it doesn’t work for me either, I’m not sure if I ever tried that one out since the primary use case is background tasks (since most apps wouldn’t be running while listening to notifications). But either way, if it’s broken, that’s a good find, so thanks!

      Phone calls – those actually use toast notifications, so they should theoretically appear in the listener. I haven’t tested that though.

      Media controls – Our team doesn’t own that, and I’m not sure if there’s a public API available for that. Accessory apps like Microsoft Band historically used AccessoryManager, which includes access to things like notifications, and I believe media controls, but AccessoryManager is hidden behind a restricted capability and we’re working on deprecating it (hence why we created Notification Listener, which is a public capability). Try posting this question on the MSDN forums.

      1. Ehad Akeila says:

        Hi Andrew,

        I’ve been experimenting with this API. I found out another thing. The phone call itself is not placed in the notification while the call is in progress. It is only available in the notification once the call is missed. Is this something you can fix as part of this feature or is it the responsibility of another team?

        Kind Regards
        Ehad

        1. andrewbares7 says:

          Ah dang, that’s too bad phone calls don’t come through. However, with the current limited information that the Listener provides (it doesn’t include any buttons from the toast), it wouldn’t be very useful surfacing those phone calls anyways, since you wouldn’t be able to answer/reject.

          There’s an API for phone calls: Windows.ApplicationModel.Calls. But it doesn’t look like it includes events for incoming calls.

          I’m not sure whether incoming calls will become their own thing, separate from notifications. There’s good arguments for both options. We’ll just have to see what the future brings!

          1. Ehad Akeila says:

            Hi Andrew,

            I really hope these phone call events can be triggered. Otherwise, those notification API will be less useful for wearables.
            On another note, I’m not sure if you are aware of this issue. The notification event so far gives me the source and content of the notification, however, I could not find where to get the sender or the subject if it is an email. I’ve tested that in some apps like facebook, sms and viber. I’m not sure if this is an issue or is it something I didnt do properly!

            Kind Regards
            Ehad

        2. andrewbares7 says:

          (seems like I can’t reply to your most recent comment, so replying up here)

          Notifications don’t have any strongly typed information like email sender or email subject. Notifications are just a set of text elements. We show how to retrieve those in the “Displaying the notifications” section, basically: toastBinding.GetTextElements();

    2. andrewbares7 says:

      After testing, it looks like you’re right, the foreground NotificationChanged event doesn’t work! Whoops 😛 We’re working on a fix. I’ll reply to this when the fix is in Insider builds.

      1. Ehad Akeila says:

        Thanks for the update 😉

        1. Ehad Akeila says:

          Ok, here are another thing to test. The “toastBinding” returns null when the notification is Facebook or Email. I’ve tested with alarm and it works. So far I can capture the source of all notifications

          1. andrewbares7 says:

            That’s another known big that we’ve fixed (those notifications were using the legacy ToastText02/etc toast payloads). I don’t think our fix for that is in Insider builds yet. I need to update the article with a Known Preview Issues section.

            Either way, you should always check whether the toast binding is null for error proof code, and then skip those notifications. They’ll start working soon though!

        2. andrewbares7 says:

          Hey Ehad, I have an update about the foreground event bug.

          The foreground event won’t work for the Anniversary Update. We’ll look at fixing that in the future. You’ll have to use the background trigger instead. Hopefully that’s fine for your app?

          1. Ehad Akeila says:

            Sorry I just noticed your post. I think it’s fine. I was only using it to test the notifications in the background 😉

  3. Is this API available for HTML-based apps?

    1. andrewbares7 says:

      Yep! All UWP API’s should work in Javascript UWP apps!

  4. Sergey Vasiliev says:

    Hi! That is great, but. How should I deal with it if my wearable is a “write-only” device? It’s just a display without any memory. I have no way to “sync”. AccessoryManager API has it’s own “per-app” queue for each event.
    Should I create some history cache in my app?

    1. andrewbares7 says:

      Hey Sergey! Yep, you should create a cache in your app. The easiest thing to do would be to use local settings, and store a list of uint in a setting entry.

      Using the code in the “Determining which notifications were added and removed” section, the GetNotificationsOnWearable() method would simply return the list value from your settings, and then at the end of that entire code section, you can update the list in settings by simply using a linq query to select the current notification ID’s, something like: userNotifications.Select(n => n.Id).ToList();

  5. Ehad Akeila says:

    Hi Andrew,

    I’ve started experiencing instability issues with the Notifications feature in the latest build 10.0.14385. Sometimes the backgroundtask is not triggered at all. And recently I tracked the issue and discovered that the app crashes when calling:

    IReadOnlyList notifs = await listener.GetNotificationsAsync(NotificationKinds.Toast);

    The error is :The data is invalid. (Exception from HRESULT: 0x8007000D)

    I don’t know if there is something wrong with my app or the new build has introduced something I’m not aware of..

    Kind Regards
    Ehad

    1. andrewbares7 says:

      I think there were a few bugs around the 14385 build that could be causing that. I’m not seeing any exceptions on 14387 today, I’ve been monitoring it today.

      Were you seeing this on Mobile or Desktop?

      1. Ehad Akeila says:

        It was more on Mobile. Desktop was a bit more stable. On mobile, the error used to be annoying but after some time it’s been working well.

    2. andrewbares7 says:

      As for the reliability and timeliness of the background task, we found an issue where it will occasionally be delayed, especially on Mobile in cases where there are battery concerns.

      We’re looking at a fix, it’d help to know if you’re planning on releasing an app using this, and therefore we know someone would benefit!

      1. Ehad Akeila says:

        Hi Andrew,

        Thanks for the update. I’ve been testing this feature for about over week. It’s working well so far especially after installing the latest Windows 10 builds. Do you know when we can start publishing apps with this feature? I’m not sure if everything will be ready on August, 2nd.

        Kind Regards
        Ehad

        1. andrewbares7 says:

          That’s awesome to hear! Do you mind sharing what app you’re creating? We’d love to know how you’re using the Listener! You can find our email address in the Notifications Visualizer app (on the About page) if you don’t want to share your app publically.

          As for releasing apps that use the Anniversary Update SDK… you have to wait till the official SDK is available, unfortunately you’re not able to submit apps using the preview SDK. I don’t know the timeline for when the official SDK will be released (and I probably wouldn’t be able to share that information anyways).

          1. EhadAkeila says:

            Yes sure. I’ll contact you soon.

  6. Jahankohan says:

    Hi Andrew,

    Thanks for your great support,

    I’ve got some trouble with this, here is my questions:

    1- What build version of windows insider should I use? Currently I’m using insider build 14366.0, should I Change it?
    2- What changes/upgrades should I do in Visual studio? Currently I’m using visual studio v3.
    3- Is there any sample that I can use? any thing I can learn from? I just find a documentation of it but it is not completely practical?

    Thanks.

    1. andrewbares7 says:

      Hey Reza!

      1. If you’re talking about the OS that you’re using on your computer/phone, I would definitely recommend upgrading to build 14393 (the latest Insider build), there were a number of Listener bug fixes that probably weren’t available in your current build.

      If you’re talking about which SDK to use, I believe the 14366 SDK is the latest one available? The SDK won’t change anything – our bug fixes all occurred in the OS itself.

      2. Doesn’t matter which version of Visual Studio you use – Update 3 is the latest, that’ll be fine.

      3. We have a sample app that replicates Action Center, you can check it out here: https://github.com/WindowsNotifications/NotificationListenerActionCenterApp

      We don’t have any other samples. What type of sample would you find most useful? I’d love to know, so that we know what we should focus on!

      Thanks!
      Andrew

  7. Luis Silva says:

    Hey there!

      string titleText = textElements.FirstOrDefault()?.Text;

    and

      string bodyText = string.Join(“\n”, textElements.Skip(1).Select(t => t.Text));

    are returning non-alphabetical characters (low-values mixed with letters).

    Kind Regards
    Luis Silva

    1. andrewbares7 says:

      Hmm interesting, do you have a specific repro of that issue? Is it happening for every single notification? Or just a specific app?

      Mobile or Desktop? What build are you running? What language/culture is your machine?

  8. EhadAkeila says:

    Hi Andrew,

    I noticed a similar thing with the new update (version 14905). Apps like timer and some games have the first value (usually the name of the app) is returned as the path (@C:/…..).

    Kind Regards
    Ehad

    1. andrewbares7 says:

      Hmm interesting, are these all third party apps/games? Can you give me specific names of the apps? I’m not seeing any “C:” paths from my phone, but I likely don’t have those same apps installed. Thanks!

      1. Ehad Akeila says:

        Hi Andrew,
        Sorry for the late reply. I just saw your comment. I happened on some games that send notifications. I’ll try to capture that when it happens again.

        Kind Regards
        Ehad

      2. Ehad Akeila says:

        Hi Andrew,

        I just captured one of the apps. It’s a game called Dragon Mania Legends. The first line of the notification is:
        “@C:\Data\Programs\{8ae2ccd0-4c54-4951-bf0f-83d714fc0dc0\-Install”