The data browser is built for Chrome, Firefox, Safari, and IE9 and above. Please upgrade your browser, or download Google Chrome to get the best experience.

Push Notification Guide

If you haven't installed the SDK yet, please head over to the Push QuickStart to get our SDK up and running.

Introduction

Push Notifications are a great way to keep your users engaged and informed about your app. You can reach your entire user base quickly and effectively. This guide will help you through the setup process and the general usage of Parse to send push notifications.

Setting Up Push

Tutorial_link

Follow the iOS push tutorial.

If you want to start using push, start by completing the iOS Push tutorial to learn how to configure your app. Come back to this guide afterwards to learn more about the push features offered by Parse.





Installations

Every Parse application installed on a device registered for push notifications has an associated Installation object. The Installation object is where you store all the data needed to target push notifications. For example, in a baseball app, you could store the teams a user is interested in to send updates about their performance.

In iOS, Installation objects are available through the PFInstallation class, a subclass of PFObject. It uses the same API for storing and retrieving data. To access the current Installation object from your iOS app, use the [PFInstallation currentInstallation] method. The first time you save a PFInstallation, Parse will add it to your Installation class, and it will be available for targeting push notifications as long as its deviceToken field is set.

- (void)application:(UIApplication *)application
        didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    // Store the deviceToken in the current Installation and save it to Parse.
    PFInstallation *currentInstallation = [PFInstallation currentInstallation];
    [currentInstallation setDeviceTokenFromData:deviceToken];
    [currentInstallation saveInBackground];
}

While it is possible to modify a PFInstallation just like you would a PFObject, there are several special fields that help manage and target devices.

  • badge: The current value of the icon badge for iOS apps. Changing this value on the PFInstallation will update the badge value on the app icon. Changes should be saved to the server so that they will be used for future badge-increment push notifications.
  • channels: An array of the channels to which a device is currently subscribed.
  • timeZone: The current time zone where the target device is located. This value is synchronized every time an Installation object is saved from the device (readonly).
  • deviceType: The type of device, "ios", "android", "winrt", "winphone", or "dotnet"(readonly).
  • installationId: Unique Id for the device used by Parse (readonly).
  • deviceToken: The Apple generated token used for iOS devices (readonly).
  • channelUris: The Microsoft-generated push URIs for Windows devices (readonly).
  • appName: The display name of the client application to which this installation belongs (readonly).
  • appVersion: The version string of the client application to which this installation belongs (readonly).
  • parseVersion: The version of the Parse SDK which this installation uses (readonly).
  • appIdentifier: A unique identifier for this installation's client application. In iOS, this is the Bundle Identifier (readonly).

Sending Pushes

There are two ways to send push notifications using Parse: channels and advanced targeting. Channels offer a simple and easy to use model for sending pushes, while advanced targeting offers a more powerful and flexible model. Both are fully compatible with each other and will be covered in this section.

Sending notifications is often done from the Web Console, the REST API or from Cloud Code. However, push notifications can also be triggered by the existing client SDKs. If you decide to send notifications from the client SDKs, you will need to set Client Push Enabled in the Push Notifications settings of your Parse app.

Client_push_settings

Using Channels

The simplest way to start sending notifications is using channels. This allows you to use a publisher-subscriber model for sending pushes. Devices start by subscribing to one or more channels, and notifications can later be sent to these subscribers. The channels subscribed to by a given Installation are stored in the channels field of the Installation object.

Subscribing to Channels

A channel is identified by a string that starts with a letter and consists of alphanumeric characters, underscores, and dashes. It doesn't need to be explicitly created before it can be used and each Installation can subscribe to any number of channels at a time.

Adding a channel subscription can be done using the addUniqueObject: method in PFObject. For example, in a baseball score app, we could do:

// When users indicate they are Giants fans, we subscribe them to that channel.
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation addUniqueObject:@"Giants" forKey:@"channels"];
[currentInstallation saveInBackground];

Once subscribed to the "Giants" channel, your Installation object should have an updated channels field.

Installation_channel

Unsubscribing from a channel is just as easy:

// When users indicate they are no longer Giants fans, we unsubscribe them.
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation removeObject:@"Giants" forKey:@"channels"];
[currentInstallation saveInBackground];

The set of subscribed channels is cached in the currentInstallation object:

NSArray *subscribedChannels = [PFInstallation currentInstallation].channels;

If you plan on changing your channels from Cloud Code or the data browser, note that you'll need to call some form of fetch prior to this line in order to get the most recent channels.

Sending Pushes to Channels

In the iOS SDK, the following code can be used to alert all subscribers of the "Giants" channel that their favorite team just scored. This will display a notification center alert to iOS users and a system tray notification to Android users.

// Send a notification to all devices subscribed to the "Giants" channel.
PFPush *push = [[PFPush alloc] init];
[push setChannel:@"Giants"];
[push setMessage:@"The Giants just scored!"];
[push sendPushInBackground];

If you want to target multiple channels with a single push notification, you can use an NSArray of channels.

NSArray *channels = [NSArray arrayWithObjects:@"Giants", @"Mets", nil];
PFPush *push = [[PFPush alloc] init];

// Be sure to use the plural 'setChannels'.
[push setChannels:channels];
[push setMessage:@"The Giants won against the Mets 2-3."];
[push sendPushInBackground];

Using Advanced Targeting

While channels are great for many applications, sometimes you need more precision when targeting the recipients of your pushes. Parse allows you to write a query for any subset of your Installation objects using the querying API and to send them a push.

Since PFInstallation is a subclass of PFObject, you can save any data you want and even create relationships between Installation objects and your other objects. This allows you to send pushes to a very customized and dynamic segment of your user base.

Saving Installation Data

Storing data on an Installation object is just as easy as storing any other data on Parse. In our Baseball app, we could allow users to get pushes about game results, scores and injury reports.

// Store app language and version
PFInstallation *installation = [PFInstallation currentInstallation];
[installation setObject:YES forKey:@"scores"];
[installation setObject:YES forKey:@"gameResults"];
[installation setObject:YES forKey:@"injuryReports"];
[installation saveInBackground];

You can even create relationships between your Installation objects and other classes saved on Parse. To associate a PFInstallation with a particular user, for example, you can simply store the current user on the PFInstallation.

// Associate the device with a user
PFInstallation *installation = [PFInstallation currentInstallation];
installation[@"user"] = [PFUser currentUser];
[installation saveInBackground];

Sending Pushes to Queries

Once you have your data stored on your Installation objects, you can use a PFQuery to target a subset of these devices. Installation queries work just like any other Parse query, but we use the special static method [PFInstallation query] to create it. We set this query on our PFPush object, before sending the notification.

// Create our Installation query
PFQuery *pushQuery = [PFInstallation query];
[pushQuery whereKey:@"injuryReports" equalTo:YES];

// Send push notification to query
PFPush *push = [[PFPush alloc] init];
[push setQuery:pushQuery]; // Set our Installation query
[push setMessage:@"Willie Hayes injured by own pop fly."];
[push sendPushInBackground];

We can even use channels with our query. To send a push to all subscribers of the "Giants" channel but filtered by those who want score update, we can do the following:

// Create our Installation query
PFQuery *pushQuery = [PFInstallation query];
[pushQuery whereKey:@"channels" equalTo:@"Giants"]; // Set channel
[pushQuery whereKey:@"scores" equalTo:YES];

// Send push notification to query
PFPush *push = [[PFPush alloc] init];
[push setQuery:pushQuery];
[push setMessage:@"Giants scored against the A's! It's now 2-2."];
[push sendPushInBackground];

If we store relationships to other objects in our Installation class, we can also use those in our query. For example, we could send a push notification to all users near a given location like this.

// Find users near a given location
PFQuery *userQuery = [PFUser query];
[userQuery whereKey:@"location"
        nearGeoPoint:stadiumLocation
         withinMiles:[NSNumber numberWithInt:1]]

// Find devices associated with these users
PFQuery *pushQuery = [PFInstallation query];
[pushQuery whereKey:@"user" matchesQuery:userQuery];

// Send push notification to query
PFPush *push = [[PFPush alloc] init];
[push setQuery:pushQuery]; // Set our Installation query
[push setMessage:@"Free hotdogs at the Parse concession stand!"];
[push sendPushInBackground];

Sending Options

Push notifications can do more than just send a message. In iOS, pushes can also include the sound to be played, the badge number to display as well as any custom data you wish to send. An expiration date can also be set for the notification in case it is time sensitive.

Customizing your Notifications

If you want to send more than just a message, you will need to use an NSDictionary to package all of the data. There are some reserved fields that have a special meaning.

  • alert: the notification's message.
  • badge: (iOS only) the value indicated in the top right corner of the app icon. This can be set to a value or to Increment in order to increment the current value by 1.
  • sound: (iOS only) the name of a sound file in the application bundle.
  • content-available: (iOS only) If you are a writing a Newsstand app, or an app using the Remote Notification Background Mode introduced in iOS7 (a.k.a. "Background Push"), set this value to 1 to trigger a background download.
  • action: (Android only) the Intent should be fired when the push is received. If not title or alert values are specified, the Intent will be fired but no notification will appear to the user.
  • title: (Android, Windows 8, and Windows Phone 8 only) the value displayed in the Android system tray or Windows toast notification.

For example, to send a notification that increases the current badge number by 1 and plays a custom sound, you can do the following:

NSDictionary *data = [NSDictionary dictionaryWithObjectsAndKeys:
    @"The Mets scored! The game is now tied 1-1!", @"alert",
    @"Increment", @"badge",
    @"cheering.caf", @"sound",
    nil];
PFPush *push = [[PFPush alloc] init];
[push setChannels:[NSArray arrayWithObjects:@"Mets", nil]];
[push setData:data];
[push sendPushInBackground];

It is also possible to specify your own data in this dictionary. As we'll see in the Receiving Notifications section, you will have access to this data only when the user opens your app via the notification. This can be useful for displaying a different view controller when a user opens certain notifications.

NSDictionary *data = [NSDictionary dictionaryWithObjectsAndKeys:
    @"Ricky Vaughn was injured in last night's game!", @"alert",
    @"Vaughn", @"name",
    @"Man bites dog", @"newsItem",
    nil];
PFPush *push = [[PFPush alloc] init];
[push setQuery:injuryReportsQuery];
[push setChannel:@"Indians"];
[push setData:data];
[push sendPushInBackground];

Whether your push notifications increment the app's badge or set it to a specific value, your app will eventually need to clear its badge. This is covered in Clearing the Badge.

Setting an Expiration Date

When a user's device is turned off or not connected to the internet, push notifications cannot be delivered. If you have a time sensitive notification that is not worth delivering late, you can set an expiration date. This avoids needlessly alerting users of information that may no longer be relevant.

There are two methods provided by the PFPush class to allow setting an expiration date for your notification. The first is expireAtDate: which simply takes an NSDate specifying when Parse should stop trying to send the notification.

// Create date object for tomorrow
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setYear:2014];
[comps setMonth:4];
[comps setDay:15];
NSCalendar *gregorian =
  [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *date = [gregorian dateFromComponents:comps];

// Send push notification with expiration date
PFPush *push = [[PFPush alloc] init];
[push expireAtDate:date];
[push setQuery:everyoneQuery];
[push setMessage:@"Season tickets on sale until April 15th"];
[push sendPushInBackground];

There is however a caveat with this method. Since device clocks are not guaranteed to be accurate, you may end up with inaccurate results. For this reason, the PFPush class also provides the expireAfterTimeInterval: method which accepts an NSTimeInterval object. The notification will expire after the specified interval has elapsed.

// Create time interval
NSTimeInterval interval = 60*60*24*7; // 1 week

// Send push notification with expiration interval
PFPush *push = [[PFPush alloc] init];
[push expireAfterTimeInterval:interval];
[push setQuery:everyoneQuery];
[push setMessage:@"Season tickets on sale until April 21st"];
[push sendPushInBackground];

Targeting by Platform

If you build a cross platform app, it is possible you may only want to target devices of a particular operating system. Advanced Targeting allow you to filter which of these devices are targeted.

The following example would send a different notification to Android, iOS, and Windows 8 users.

PFQuery *query = [PFInstallation query];
[query whereKey:@"channels" equalTo:@"suitcaseOwners"];

// Notification for Android users
[query whereKey:@"deviceType" equalTo:@"android"];
PFPush *androidPush = [[PFPush alloc] init];
[androidPush setMessage:@"Your suitcase has been filled with tiny robots!"];
[androidPush setQuery:query];
[androidPush sendPushInBackground];

// Notification for iOS users
[query whereKey:@"deviceType" equalTo:@"ios"];
PFPush *iOSPush = [[PFPush alloc] init];
[iOSPush setMessage:@"Your suitcase has been filled with tiny apples!"];
[iOSPush setChannel:@"suitcaseOwners"];
[iOSPush setQuery:query];
[iOSPush sendPushInBackground];

// Notification for Windows 8 users
[query whereKey:@"deviceType" equalTo:@"winrt"];
PFPush *winPush = [[PFPush alloc] init];
[winPush setMessage:@"Your suitcase has been filled with tiny glass!"];
[winPush setQuery:query];
[winPush sendPushInBackground];

// Notification for Windows 8 users
[query whereKey:@"deviceType" equalTo:@"winphone"];
PFPush *winPush = [[PFPush alloc] init];
[wpPush setMessage:@"Your suitcase is very hip; very metro."];
[wpPush setQuery:query];
[wpPush sendPushInBackground];

Scheduling Pushes

Sending scheduled push notifications is not currently supported by the iOS SDK. Take a look at the REST API, JavaScript SDK or the Web Console.

Receiving Pushes

As we saw in the Customizing Your Notification section, it is possible to send arbitrary data along with your notification message. We can use this data to modify the behavior of your app when a user opens a notification. For example, upon opening a notification saying that a friend commented on a user's picture, it would be nice to display this picture.

Due to the package size restrictions imposed by Apple, you need to be careful in managing the amount of extra data sent, since it will cut down on the maximum size of your message. For this reason, it is recommended that you keep your extra keys and values as small as possible.

NSDictionary *data = @{
  @"alert": @"James commented on your photo!",
  @"p": @"vmRZXZ1Dvo" // Photo's object id
};
PFPush *push = [[PFPush alloc] init];
[push setQuery:photoOwnerQuery];
[push setData:data];
[push sendPushInBackground];

Responding to the Payload

When an app is opened from a notification, the data is made available in the application:didFinishLaunchingWithOptions: methods through the launchOptions dictionary.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  . . .
  // Extract the notification data
  NSDictionary *notificationPayload = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];

  // Create a pointer to the Photo object
  NSString *photoId = [notificationPayload objectForKey:@"p"];
  PFObject *targetPhoto = [PFObject objectWithoutDataWithClassName:@"Photo"
                                                          objectId:photoId];

  // Fetch photo object
  [targetPhoto fetchIfNeededInBackgroundWithBlock:^(PFObject *object, NSError *error) {
    // Show photo view controller
    if (!error && [PFUser currentUser]) {
      PhotoVC *viewController = [[PhotoVC alloc] initWithPhoto:object];
      [self.navController pushViewController:viewController animated:YES];
    }
  }];
}

If your app is already running when the notification is received, the data is made available in the application:didReceiveRemoteNotification:fetchCompletionHandler: method through the userInfo dictionary.

- (void)application:(UIApplication *)application
      didReceiveRemoteNotification:(NSDictionary *)userInfo 
            fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))handler {
  // Create empty photo object
  NSString *photoId = [userInfo objectForKey:@"p"];
  PFObject *targetPhoto = [PFObject objectWithoutDataWithClassName:@"Photo"
                                                          objectId:photoId];

  // Fetch photo object
  [targetPhoto fetchIfNeededInBackgroundWithBlock:^(PFObject *object, NSError *error) {
    // Show photo view controller
    if (error) {
      handler(UIBackgroundFetchResultFailed);
    } else if ([PFUser currentUser]) {
      PhotoVC *viewController = [[PhotoVC alloc] initWithPhoto:object];
      [self.navController pushViewController:viewController animated:YES];
      handler(UIBackgroundFetchResultNewData);
    } else {
      handler(UIBackgroundModeNoData);
    }
  }];
}

You can read more about handling push notifications in Apple's Local and Push Notification Programming Guide.

Tracking Pushes and App Opens

To track your users' engagement over time and the effect of push notifications, we provide some hooks in the PFAnalytics class. Application opens and push-related open rates will be available in your application's dashboard.

First, add the following to your application:didFinishLaunchingWithOptions: method to collect information about when your application was launched, and what triggered it. The extra checks ensure that, even with iOS 7's more advanced background push features, a single logical app-open or push-open event is counted as such.

if (application.applicationState != UIApplicationStateBackground) {
  // Track an app open here if we launch with a push, unless
  // "content_available" was used to trigger a background push (introduced
  // in iOS 7). In that case, we skip tracking here to avoid double
  // counting the app-open.
  BOOL preBackgroundPush = ![application respondsToSelector:@selector(backgroundRefreshStatus)];
  BOOL oldPushHandlerOnly = ![self respondsToSelector:@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)];
  BOOL noPushPayload = ![launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
  if (preBackgroundPush || oldPushHandlerOnly || noPushPayload) {
    [PFAnalytics trackAppOpenedWithLaunchOptions:launchOptions];
  }
}

Second, if your application is running or backgrounded, the application:didReceiveRemoteNotification: method handles the push payload instead. If the user acts on a push notification while the application is backgrounded, the application will be brought to the foreground. To track this transition as the application being "opened from a push notification," perform one more check before calling any tracking code:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
  if (application.applicationState == UIApplicationStateInactive) {
    // The application was just brought from the background to the foreground,
    // so we consider the app as having been "opened by a push notification."
    [PFAnalytics trackAppOpenedWithRemoteNotificationPayload:userInfo];
  }
}

Finally, if using iOS 7 any of its new push features (including the new "content-available" push functionality), be sure to also implement the iOS 7-only handler:

- (void)application:(UIApplication *)application
        didReceiveRemoteNotification:(NSDictionary *)userInfo
        fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
  if (application.applicationState == UIApplicationStateInactive) {
    [PFAnalytics trackAppOpenedWithRemoteNotificationPayload:userInfo];
  }
}

Tracking on OS X

If your OS X application supports receiving push notifications and you'd like to track application opens related to pushes, add hooks to the application:didReceiveRemoteNotification: method (as in iOS) and the following to applicationDidFinishLaunching:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
  // ... other Parse setup logic here
  [PFAnalytics trackAppOpenedWithRemoteNotificationPayload:[aNotification userInfo]];
}

Tracking Local Notifications (iOS only)

To track analytics around local notifications, note that application:didReceiveLocalNotification: is called in addition to application:didFinishLaunchingWithOptions:, if implemented. Please be careful to prevent tracking duplicate events.

Clearing the Badge

A good time to clear your app's badge is usually when your app is opened. Setting the badge property on the current installation will update the application icon badge number and ensure that the latest badge value will be persisted to the server on the next save. All you need to do is:

- (void)applicationDidBecomeActive:(UIApplication *)application {
  PFInstallation *currentInstallation = [PFInstallation currentInstallation];
  if (currentInstallation.badge != 0) {
    currentInstallation.badge = 0;
    [currentInstallation saveEventually];
  }
  // ...
}

The UIApplicationDelegate documentation contains more information on hooks into an app’s life cycle; the ones which are most relevant for resetting the badge count are applicationDidBecomeActive:, application:didFinishLaunchingWithOptions:, and application:didReceiveRemoteNotification:.

Troubleshooting

Setting up Push Notifications is often a source of frustration for developers. The process is complicated and invites problems to happen along the way. If you run into issues, try some of these troubleshooting tips.

  • Make sure you are using the correct Bundle Identifier in the Info.plist file (as described in step 4.1 of the iOS Push Notifications tutorial, titled, "Configuring a Push Enabled iOS Application."
  • Make sure you set the correct provisioning profile in Project > Build Settings (as described in step 4.3 of the iOS Push Notifications tutorial.
  • Clean your project and restart Xcode.
  • Try regenerating the provisioning profile by navigating to Certificates, Identifiers & Profiles, changing the App ID set on the provisioning profile, and changing it back. You will need to reinstall the profile as described in step two of the tutorial (Creating the Provisioning Profile) and set it in your Project's Build Settings as described in step 4 ( Configuring a Push Enabled iOS Application).
  • Open the Xcode Organizer and delete all expired and unused provisioning profiles from both your computer and your iOS device.
  • If everything compiles and runs with no errors, but you are still not receiving pushes, make sure that your app has been given permission to receive notifications. You can verify this in your iOS device's Settings > Notification > YourAppName.
  • If your app has been granted permission to receive push notifications, make sure that you are code signing your app with the correct provisioning profile. If you have uploaded a Development Push Notification Certificate to Parse, you will only receive push notifications if you built your app with a Development Provisioning Profile. If you have uploaded a Production Push Notification Certificate, you should sign your app with a Distribution Provisioning Profile. Ad Hoc and App Store Distribution Provisioning Profiles should both work when your app is configured with a Production Push Notification Certificate.
  • When enabling push notifications for an existing App ID in the Apple iOS Provisioning Portal, make sure to regenerate the provisioning profile, then add the updated profile to the Xcode Organizer.
  • Distribution push notifications need to be enabled prior to submitting an app to the App Store. Make sure you have followed Section 7, Preparing for the App Store, prior to submitting your app. If you skipped any of these steps, you might need to submit a new binary to the App Store.
  • Double check that your app can receive distribution push notifications when signed with an Ad Hoc profile. This configuration is the closest you can get to an App Store provisioned app.
  • Check the number of recipients in your Parse Push Console. Does it match the expected number of recipients? Your push might be targeted incorrectly.

Push Notification Guide

If you haven't installed the SDK yet, please head over to the Push QuickStart to get our SDK up and running.

Introduction

Push notifications are a great way to keep your users engaged and informed about your app. You can reach your entire user base quickly and effectively. This guide will help you through the setup process and the general usage of Parse to send push notifications.

Setting Up Push

Tutorial_link

Follow the Android push tutorial.

If you want to start using push, start by completing the Android Push tutorial to learn how to configure your app. Come back to this guide afterwards to learn more about the push features offered by Parse.

The Parse library provides push notifications using Google Cloud Messaging (GCM) if possible. On devices that do not support GCM (such as Amazon Kindle Fire), Parse will use a background service that maintains a persistent connection to the Parse cloud to deliver pushes. This allows Parse Push to work on all devices running Android 2.2 or higher.





Installations

Every Parse application installed on a device registered for push notifications has an associated Installation object. The Installation object is where you store all the data needed to target push notifications. For example, in a baseball app, you could store the teams a user is interested in to send updates about their performance.

In Android, Installation objects are available through the ParseInstallation class, a subclass of ParseObject. It uses the same API for storing and retrieving data. To access the current Installation object from your Android app, use the ParseInstallation.getCurrentInstallation() method. The first time you save a ParseInstallation, Parse will add it to your Installation class and it will be available for targeting push notifications.

// Save the current Installation to Parse.
ParseInstallation.getCurrentInstallation().saveInBackground();

While it is possible to modify a ParseInstallation just like you would a ParseObject, there are several special fields that help manage and target devices.

  • badge: The current value of the icon badge for iOS apps. Changes to this value on the server will be used for future badge-increment push notifications.
  • channels: An array of the channels to which a device is currently subscribed.
  • timeZone: The current time zone where the target device is located. This value is synchronized every time an Installation object is saved from the device (readonly).
  • deviceType: The type of device, "ios" or "android" (readonly).
  • installationId: Unique Id for the device used by Parse (readonly).
  • deviceToken: The Apple generated token used for iOS devices, or the token used by GCM to keep track of registration ID (readonly).
  • channelUris: The Microsoft-generated push URIs for Windows devices (readonly).
  • appName: The display name of the client application to which this installation belongs (readonly).
  • appVersion: The version string of the client application to which this installation belongs (readonly).
  • parseVersion: The version of the Parse SDK which this installation uses (readonly).
  • appIdentifier: A unique identifier for this installation's client application. This parameter is not supported in Android.(readonly).
  • pushType This field is reserved for directing Parse to the push delivery network to be used. If the device is registered to receive pushes via GCM, this field will be marked "gcm". If this device is not using GCM, and is using Parse's push notification service, it will be blank (readonly).

Sending Pushes

There are two ways to send push notifications using Parse: channels and advanced targeting. Channels offer a simple and easy to use model for sending pushes, while advanced targeting offers a more powerful and flexible model. Both are fully compatible with each other and will be covered in this section.

Sending notifications is often done from the Web Console, the REST API or from Cloud Code. However, push notifications can also be triggered by the existing client SDKs. If you decide to send notifications from the client SDKs, you will need to set Client Push Enabled in the Push Notifications settings of your Parse app.

Client_push_settings

Using Channels

The simplest way to start sending notifications is using channels. This allows you to use a publisher-subscriber model for sending pushes. Devices start by subscribing to one or more channels, and notifications can later be sent to these subscribers. The channels subscribed to by a given Installation are stored in the channels field of the Installation object.

Subscribing to Channels

A channel is identified by a string that starts with a letter and consists of alphanumeric characters, underscores, and dashes. It doesn't need to be explicitly created before it can be used and each Installation can subscribe to any number of channels at a time.

Subscribing to a channel can be done using a single method call. For example, in a baseball score app, we could do:

// When users indicate they are Giants fans, we subscribe them to that channel.
PushService.subscribe(context, "Giants", YourActivity.class);

The provided Activity class specifies which Activity will be run when a user responds to notifications on this channel. This lets you handle push notifications on different channels in different ways.

Once subscribed to the "Giants" channel, your Installation object should have an updated channels field.

Installation_channel

Unsubscribing from a channel is just as easy:

// When users indicate they are no longer Giants fans, we unsubscribe them.
PushService.unsubscribe(context, "Giants");

You can also get the set of channels that the current device is subscribed to using:

Set<String> setOfAllSubscriptions = PushService.getSubscriptions();

Neither the subscribe method nor the unsubscribe method blocks the thread it is called from. The subscription information is cached on the device's disk if the network is inaccessible and transmitted to the Parse Cloud as soon as the network is usable. This means you don't have to worry about threading or callbacks while managing subscriptions.

Sending Pushes to Channels

In the Android SDK, the following code can be used to alert all subscribers of the "Giants" channel that their favorite team just scored. This will display a notification center alert to iOS users and a system tray notification to Android users.

ParsePush push = new ParsePush();
push.setChannel("Giants");
push.setMessage("The Giants just scored! It's now 2-2 against the Mets.");
push.sendInBackground();

If you want to target multiple channels with a single push notification, you can use a LinkedList of channels.

LinkedList<String> channels = new LinkedList<String>();
channels.add("Giants");
channels.add("Mets");

ParsePush push = new ParsePush();
push.setChannels(channels); // Notice we use setChannels not setChannel
push.setMessage("The Giants won against the Mets 2-3.");
push.sendInBackground();

Using Advanced Targeting

While channels are great for many applications, sometimes you need more precision when targeting the recipients of your pushes. Parse allows you to write a query for any subset of your Installation objects using the querying API and to send them a push.

Since ParseInstallation is a subclass of ParseObject, you can save any data you want and even create relationships between Installation objects and your other objects. This allows you to send pushes to a very customized and dynamic segment of your user base.

Saving Installation Data

Storing data on an Installation object is just as easy as storing any other data on Parse. In our Baseball app, we could allow users to get pushes about game results, scores and injury reports.

// Store app language and version
ParseInstallation installation = ParseInstallation.getCurrentInstallation();
installation.put("scores",true);
installation.put("gameResults",true);
installation.put("injuryReports",true);
installation.saveInBackground();

You can even create relationships between your Installation objects and other classes saved on Parse. To associate an Installation with a particular user, for example, you can simply store the current user on the ParseInstallation.

// Associate the device with a user
ParseInstallation installation = ParseInstallation.getCurrentInstallation();
installation.put("user",ParseUser.getCurrentUser());
installation.saveInBackground();

Sending Pushes to Queries

Once you have your data stored on your Installation objects, you can use a PFQuery to target a subset of these devices. Installation queries work just like any other Parse query, but we use the special static method ParseInstallation.getQuery() to create it. We set this query on our PFPush object, before sending the notification.

// Create our Installation query
ParseQuery pushQuery = ParseInstallation.getQuery();
pushQuery.whereEqualTo("injuryReports", true);

// Send push notification to query
ParsePush push = new ParsePush();
push.setQuery(pushQuery); // Set our Installation query
push.setMessage("Willie Hayes injured by own pop fly.");
push.sendInBackground();

We can even use channels with our query. To send a push to all subscribers of the "Giants" channel but filtered by those who want score update, we can do the following:

// Create our Installation query
ParseQuery pushQuery = ParseInstallation.getQuery();
pushQuery.whereEqualTo("channels", "Giants"); // Set the channel
pushQuery.whereEqualTo("scores", true);

// Send push notification to query
ParsePush push = new ParsePush();
push.setQuery(pushQuery);
push.setMessage("Giants scored against the A's! It's now 2-2.");
push.sendInBackground();

If we store relationships to other objects in our Installation class, we can also use those in our query. For example, we could send a push notification to all users near a given location like this.

// Find users near a given location
ParseQuery userQuery = ParseInstallation.getQuery();
userQuery.whereWithinMiles("location", stadiumLocation, 1.0)

// Find devices associated with these users
ParseQuery pushQuery = ParseInstallation.getQuery();
pushQuery.whereMatchesQuery("user", userQuery);

// Send push notification to query
ParsePush push = new ParsePush();
push.setQuery(pushQuery); // Set our Installation query
push.setMessage("Free hotdogs at the Parse concession stand!");
push.sendInBackground();

Sending Options

Push notifications can do more than just send a message. In Android, pushes can also include custom data you wish to send and an Intent to fire upon reciept. An expiration date can also be set for the notification in case it is time sensitive.

Customizing your Notifications

If you want to send more than just a message, you will need to use a JSONObject to package all of the data. There are some reserved fields that have a special meaning in Android.

  • alert: the notification's message.
  • badge: (iOS only) the value indicated in the top right corner of the app icon. This can be set to a value or to Increment in order to increment the current value by 1.
  • sound: (iOS only) the name of a sound file in the application bundle.
  • content-available: (iOS only) If you are a writing a Newsstand app, or an app using the Remote Notification Background Mode introduced in iOS7 (a.k.a. "Background Push"), set this value to 1 to trigger a background download.
  • action: (Android only) the Intent should be fired when the push is received. If no title or alert values are specified, the Intent will be fired but no notification will appear to the user.
  • title: (Android, Windows 8, & Windows Phone 8 only) the value displayed in the Android system tray or Windows 8 toast notification.

For example, to send a notification that would increases the badge number by 1 and plays a custom sound, you can do the following. Note that you can set these properties from your Android client, but they would only take effect in the iOS version of your app. The badge and sound fields would have no effects for Android recipients.

JSONObject data = new JSONObject("{\"alert\": \"The Mets scored!\",
                                   \"badge\": \"Increment\",
                                   \"sound\": \"cheering.caf);

ParsePush *push = new ParsePush();
push.setChannel("Mets");
push.setData(data);
push.sendPushInBackground();

It is also possible to specify your own data in this dictionary. As we'll see in the Receiving Notifications section, you can use Intents to do custom processing upon receiving a notitication. You will also have access to any data set on the notification.

JSONObject data = new JSONObject("{\"action\": \"com.example.UPDATE_STATUS\",
                                   \"name\": \"Vaughn\",
                                   \"newsItem\": \"Man bites dog\""}));

ParsePush *push = new ParsePush();
push.setQuery(injuryReportsQuery);
push.setChannel("Indians");
push.setData(data);
push.sendPushInBackground();

Setting an Expiration Date

When a user's device is turned off or not connected to the internet, push notifications cannot be delivered. If you have a time sensitive notification that is not worth delivering late, you can set an expiration date. This avoids needlessly alerting users of information that may no longer be relevant.

There are two methods provided by the ParsePush class to allow setting an expiration date for your notification. The first is setExpirationTime which simply takes an time (in UNIX epoch time) specifying when Parse should stop trying to send the notification.

// Send push notification with expiration date
ParsePush push = new ParsePush();
push.setExpirationTime(1397602025);
push.setQuery(everyoneQuery);
push.setMessage("Season tickets on sale until April 15th");
push.sendPushInBackground();

There is however a caveat with this method. Since device clocks are not guaranteed to be accurate, you may end up with inaccurate results. For this reason, the ParsePush class also provides the setExpirationTimeInterval method which accepts a timeInterval (in seconds). The notification will expire after the specified interval has elapsed.

// Create time interval
long weekInterval = 60*60*24*7; // 1 week

// Send push notification with expiration interval
ParsePush push = new ParsePush();
push.setExpirationTimeInterval(weekInterval);
push.setQuery(everyoneQuery);
push.setMessage("Season tickets on sale until April 21st");
push.sendPushInBackground();

Targeting by Platform

If you build a cross platform app, it is possible you may only want to target devices of a particular operating system. Advanced Targeting allow you to filter which of these devices are targeted.

The following example would send a different notification to Android, iOS, and Windows 8 users.

ParseQuery query = ParseInstallation.getQuery();
query.whereEqualTo("channels", "suitcaseOwners");

// Notification for Android users
query.whereEqualTo("deviceType", "android");
ParsePush androidPush = new ParsePush();
androidPush.setMessage("Your suitcase has been filled with tiny robots!");
androidPush.setQuery(query);
androidPush.sendPushInBackground();

// Notification for iOS users
query.whereEqualTo("deviceType", "android");
ParsePush iOSPush = new ParsePush();
iOSPush.setMessage("Your suitcase has been filled with tiny apples!");
iOSPush.setQuery(query);
iOSPush.sendPushInBackground();

// Notification for Windows 8 users
query.whereEqualTo("deviceType", "winrt");
ParsePush winPush = new ParsePush();
winPush.setMessage("Your suitcase has been filled with tiny glass!");
winPush.setQuery(query);
winPush.sendPushInBackground();

// Notification for Windows 8 users
query.whereEqualTo("deviceType", "winrt");
ParsePush winPush = new ParsePush();
winPush.setMessage("Your suitcase has been filled with tiny glass!");
winPush.setQuery(query);
winPush.sendPushInBackground();

// Notification for Windows Phone 8 users
query.whereEqualTo("deviceType", "winphone");
ParsePush wpPush = new ParsePush();
wpPush.setMessage("Your suitcase is very hip; very metro.");
wpPush.setQuery(query);
wpPush.sendPushInBackground();

Scheduling Pushes

Sending scheduled push notifications is not currently supported by the Android SDK. Take a look at the REST API, JavaScript SDK or the Web Console.

Receiving Pushes

When a push notification is received, the "title" is displayed in the system tray and the "message" is displayed as the content of that push. Android allows you to go beyond this by specifying an Activity that will handle an opened push notification, and an Intent which will be fired in the background upon receipt of the notification.

Make sure you've gone through the Android Push QuickStart to set up your app to receive pushes. The quickstart shows you how to set up push for all Android devices, including ones that do not support GCM. If you are only pushing to GCM-enabled devices, you can remove these elements from your AndroidManifest.xml:

  • The receiver element for com.parse.ParseBroadcastReceiver (including the intent filter for BOOT_COMPLETED and USER_PRESENT)
  • The permission element for android.permission.RECEIVE_BOOT_COMPLETED

You will still need all the other elements (including the one for com.parse.PushService) as described in the quickstart.

Note that some Android emulators (the ones missing Google API support) don't support GCM, so if you test your app in an emulator with this type of configuration, make sure to select an emulator image that has Google APIs installed.

Responding With an Activity

You can specify an Activity to be launched when a push notification is opened by the user. When using channels, you add this Activity in the subscribe method call.

PushService.subscribe(context, "Giants", YourActivity.class);

If you are using advanced targeting, you can specify a default Activity to be used.

PushService.setDefaultPushCallback(context, YourActivity.class);

Responding With an Intent

You can also specify an Intent to be fired in the background when the push notification is received. This will allow your app to perform custom handling for the notification, and can be used whether or not you have chosen to display a system tray message. To implement custom notification handling, set the Action entry in your push notification data dictionary to the Intent action which you want to fire. Android guidelines suggest that you prefix the action with your package name to avoid namespace collisions with other running apps.

Here is the example we saw earlier:

JSONObject data = new JSONObject("{\"action\": \"com.example.UPDATE_STATUS\",
                                   \"name\": \"Vaughn\",
                                   \"newsItem\": \"Man bites dog\""}));

ParsePush *push = new ParsePush();
push.setQuery(injuryReportsQuery);
push.setChannel("Angels");
push.setData(data);
push.sendPushInBackground();

If your code lives in the com.example package and you want to register a receiver for the com.example.UPDATE_STATUS action, you can add the following XML to your AndroidManifest.xml file, immediately after the end of the ParseBroadcastReceiver block that you created earlier:

<receiver android:name="com.example.MyCustomReceiver" android:exported="false">
  <intent-filter>
    <action android:name="com.example.UPDATE_STATUS" />
  </intent-filter>
</receiver>

Your custom receiver will be called whenever a push notification is received with an action parameter of com.example.UPDATE_STATUS. For security purposes, the Parse SDK ensures that this intent can only be handled by receivers within your app. You should additionally make sure to set the android:exported attribute on your <receiver> element to prevent other apps from sending pushes to your receiver.

The Intent object which is passed to the receiver contains an extras Bundle with two useful mappings. The "com.parse.Channel" key points to a string representing the channel that the message was sent on. The "com.parse.Data" key points to a string representing the JSON-encoded value of the "data" dictionary that was set in the push notification. As an example, the following code will parse a JSON push notification and log it to the Android emulator console:

public class MyCustomReceiver extends BroadcastReceiver {
private static final String TAG = "MyCustomReceiver";

  @Override
  public void onReceive(Context context, Intent intent) {
    try {
      String action = intent.getAction();
      String channel = intent.getExtras().getString("com.parse.Channel");
      JSONObject json = new JSONObject(intent.getExtras().getString("com.parse.Data"));

      Log.d(TAG, "got action " + action + " on channel " + channel + " with:");
      Iterator itr = json.keys();
      while (itr.hasNext()) {
        String key = (String) itr.next();
        Log.d(TAG, "..." + key + " => " + json.getString(key));
      }
    } catch (JSONException e) {
      Log.d(TAG, "JSONException: " + e.getMessage());
    }
  }
}

Tracking Pushes and App Opens

To track your users' engagement over time and the effect of push notifications, we provide some hooks in the ParseAnalytics class.

If you respond to push notifications with an Activity, add the following to the onCreate method of your push-handling Activity and you'll be able to collect information about when your application was opened and what triggered it. If you respond to pushes by implementing a custom BroadcastReceiver, adjust the code to use the Intent passed into onReceive instead.

ParseAnalytics.trackAppOpened(getIntent());

A null parameter to trackAppOpened will track only a standard app-opened event (e.g. if the Parse payload on the Intent was empty, or if you ignore pushes by explicitly passing in null).

Application opens and push-related open rates will be available in your application's dashboard.

Troubleshooting

Setting up Push Notifications is often a source of frustration for developers. The process is complicated and invites problems to happen along the way. If you run into issues, try some of these troubleshooting tips.

  • Upgrade to the latest SDK. Several common issues with push notifications in Android have been fixed in recent releases of Parse.
  • Make sure you have the correct permissions listed in your AndroidManifest.xml file, as outlined in steps 4 and 6 of the Android Push Quickstart. If you are using a a custom receiver, be sure you have registered it in the Manifest file with the correct android:name property and the proper intent filters.
  • Make sure you've used the correct App ID and client key, and that Parse.initialize() is being called. Parse.initialize() lets the service know which application it is listening for; we suggest putting this code in the Application.onCreate rather than the onCreate method for a particular Activity, so that any activation technique will know how to use Parse.
  • Check that the device is set to accept push notifications from your app.
  • Check the number of recipients in your Parse Push Console. Does it match the expected number of recipients? Your push might be targeted incorrectly.
  • If testing in the emulator, try cleaning and rebuilding your project and restarting your AVD.
  • Turn on verbose logging with Parse.setLogLevel(Parse.LOG_LEVEL_VERBOSE). The error messages will be a helpful guide to what may be going on.
  • If you see the message "Finished (with error)" in your Dashboard, check your verbose logs. If you are performing pushes from a device, check that client-side push is enabled in your dashboard.
  • In your logs, you may see an error message, "Could not construct writer" or other issues related to a broken pipe. When this occurs, the framework will continue to try reconnecting. It should not crash your app.

Push Notification Guide

If you haven't installed the SDK yet, please head over to the Push QuickStart to get our SDK up and running.

Introduction

Push Notifications are a great way to keep your users engaged and informed about your app. You can reach your entire user base quickly and effectively. This guide will help you through the setup process and the general usage of Parse to send push notifications.

The Windows SDK can send push notifications from all runtimes, but only WinRT and Windows Phone apps can receive pushes from Microsoft push servers.

Setting Up Push

Tutorial_link

Follow the Windows 8 push tutorial.

If you want to start using push, start by completing the Windows 8 Push tutorial or Windows Phone 8 Push Tutorial to learn how to configure your app. Come back to this guide afterwards to learn more about the push features offered by Parse.





Installations

Every Parse application installed on a device registered for push notifications has an associated Installation object. The Installation object is where you store all the data needed to target push notifications. For example, in a baseball app, you could store the teams a user is interested in to send updates about their performance.

On Windows, Installation objects are available through the ParseInstallation class, a subclass of ParseObject. It uses the same API for storing and retrieving data. To access the current Installation object from your .NET app, use the ParseInstallation.CurrentInstallation property. The first time you save a ParseInstallation, Parse will add it to your Installation class, and it will be available for targeting push notifications as long as its deviceUris field is set.

protected override async void OnLaunched(LaunchActivatedEventArgs args) {
  await ParseInstallation.CurrentInstallation.SaveAsync();
}

While it is possible to modify a ParseInstallation just like you would a ParseObject, there are several special fields that help manage and target devices.

  • channels: An IEnumerable<string> of the channels to which a device is currently subscribed. In .NET, this field is accessible through the Channels property.
  • timeZone: The current time zone where the target device is located. This field is readonly and can be accessed via the TimeZone property. This value is synchronized every time an Installation object is saved from the device.
  • deviceType: The type of device, "ios", "android", "winrt", "winphone", or "dotnet". This field is readonly and can be accessed via the DeviceType property.
  • installationId: Unique Id for the device used by Parse. This field is readonly and can be accessed via the InstallationId property.
  • deviceToken: The Apple generated token used for iOS devices (readonly).
  • channelUris: The Microsoft-generated push URIs for Windows devices. This field is readonly and can be accessed via the DeviceUris property.
  • appName: The display name of the client application to which this installation belongs. This field is readonly and can be accessed via the AppName property.
  • appVersion: The version string of the client application to which this installation belongs. This field is readonly and can be accessed via the AppVersion property.
  • parseVersion: The version of the Parse SDK which this installation uses. This field is readonly and can be accessed via the ParseVersion property.
  • appIdentifier: A unique identifier for this installation's client application. This field is readonly and can be accessed via the AppIdentifier property. On Windows 8, this is the Windows.ApplicationModel.Package id; on Windows Phone 8 this is the ProductId; in other .NET applications, this is the ApplicationIdentity of the current AppDomain

Sending Pushes

There are two ways to send push notifications using Parse: channels and advanced targeting. Channels offer a simple and easy to use model for sending pushes, while advanced targeting offers a more powerful and flexible model. Both are fully compatible with each other and will be covered in this section.

Sending notifications is often done from the Web Console, the REST API or from Cloud Code. However, push notifications can also be triggered by the existing client SDKs. If you decide to send notifications from the client SDKs, you will need to set Client Push Enabled in the Push Notifications settings of your Parse app.

Client_push_settings

Using Channels

The simplest way to start sending notifications is using channels. This allows you to use a publisher-subscriber model for sending pushes. Devices start by subscribing to one or more channels, and notifications can later be sent to these subscribers. The channels subscribed to by a given Installation are stored in the channels field of the Installation object.

Subscribing to Channels

A channel is identified by a string that starts with a letter and consists of alphanumeric characters, underscores, and dashes. It doesn't need to be explicitly created before it can be used and each Installation can subscribe to any number of channels at a time.

An installation's channels can be set using the Channels property of ParseInstallation. For example, in a baseball socre app, we could do:

// When users indicate they are Giants fans, we subscribe them to that channel.
var installation = ParseInstallation.CurrentInstallation;
installation.Channels = new List<string> { "Giants" };
await installation.SaveAsync();

Alternatively, you can insert a channel into Channels without affecting the existing channels using the AddUniqueToList method of ParseObject using the following:

var installation = ParseInstallation.CurrentInstallation;
installation.AddUniqueToList("channels", "Giants");
await installation.SaveAsync();

Finally, ParsePush provides a shorthand for inserting a channel into Channels and saving:

await ParsePush.SubscribeAsync("Giants");

Once subscribed to the "Giants" channel, your Installation object should have an updated channels field.

Installation_channel

Unsubscribing from a channel is just as easy:

var installation = ParseInstallation.CurrentInstallation;
installation.RemoveAllFromList("channels" new List<string> { "Giants" });
await installation.SaveAsync();

Or, using ParsePush:

ParsePush.UnsubscribeAsync("Giants");

The set of subscribed channels is cached in the CurrentInstallation object:

var installation = ParseInstallation.CurrentInstallation
IEnumerable<string> subscribedChannels = installation.Channels;

If you plan on changing your channels from Cloud Code or the data browser, note that you'll need to call FetchAsync prior to this line in order to get the most recent channels.

Sending Pushes to Channels

In the .NET SDK, the following code can be used to alert all subscribers of the "Giants" channel that their favorite team just scored. This will display a toast notification to Windows users. iOS users will receive a notification in the notification center and Android users will receive a notification in the system tray.

// Send a notification to all devices subscribed to the "Giants" channel.
var push = new ParsePush();
push.Channels = new List<string> {"Giants"};
push.Alert = "The Giants just scored!";
await push.SendAsync();

If you want to target multiple channels with a single push notification, you can use any IEnumerable<string> of channels.

Using Advanced Targeting

While channels are great for many applications, sometimes you need more precision when targeting the recipients of your pushes. Parse allows you to write a query for any subset of your Installation objects using the querying API and to send them a push.

Since ParseInstallation is a subclass of ParseObject, you can save any data you want and even create relationships between Installation objects and your other objects. This allows you to send pushes to a very customized and dynamic segment of your user base.

Saving Installation Data

Storing data on an Installation object is just as easy as storing any other data on Parse. In our Baseball app, we could allow users to get pushes about game results, scores and injury reports.

// Store the category of push notifications the user would like to receive.
var installation = ParseInstallation.CurrentInstallation;
installation["scores"] = true;
installation["gameResults"] = true;
installation["injuryReports"] = true;
await installation.SaveAsync();

You can even create relationships between your Installation objects and other classes saved on Parse. To associate an Installation with a particular user, for example, you can simply store the current user on the ParseInstallation.

// Associate the device with a user
var installation = ParseInstallation.CurrentInstallation;
installation["user"] = ParseUser.CurrentUser;
await installation.SaveAsync();

Sending Pushes to Queries

Once you have your data stored on your Installation objects, you can use a ParseQuery to target a subset of these devices. Installation queries work just like any other Parse query, but we use the special static property ParseInstallation.Query to create it. We set this query on our ParsePush object, before sending the notification.

var push = new ParsePush();
push.Query = from installation in ParseInstallation.Query
             where installation.Get<bool>("injuryReports") == true
             select installation;
push.Alert = "Willie Hayes injured by own pop fly.";
await push.SendAsync();

We can even use channels with our query. To send a push to all subscribers of the "Giants" channel but filtered by those who want score update, we can do the following:

var push = new Parse.Push();
push.Query = from installation in ParseInstallation.Query
             where installation.Get<bool>("scores") == true
             select installation;
push.Channels = new List<string> { "Giants" };
push.Alert = "Giants scored against the A's! It's now 2-2.";
await push.SendAsync();

Alternatively, we can use a query that constrains "channels" directly:

var push = new Parse.Push();
push.Query = from installation in ParseInstallation.Query
             where installation.Get<bool>("scores") == true
             where installation.Channels.Contains("Giants")
             select installation;
push.Alert = "Giants scored against the A's! It's now 2-2.";
await push.SendAsync();

If we store relationships to other objects in our Installation class, we can also use those in our query. For example, we could send a push notification to all users near a given location like this.

// Find users in the Seattle metro area
var userQuery = ParseUser.Query.WhereWithinDistance(
    "location",
    marinersStadium,
    ParseGeoDistance.FromMiles(1));
var push= new ParsePush();
push.Query = from installation in ParseInstallation.Query
             join user in userQuery on installation["user"] equals user
             select installation;
push.Alert = "Mariners lost? Free conciliatory hotdogs at the Parse concession stand!";
await push.SendAsync();

Sending Options

Push notifications can do more than just send a message. On Windows and Windows Phone 8, pushes can also include a title, as well as any custom data you wish to send. An expiration date can also be set for the notification in case it is time sensitive.

Customizing your Notifications

If you want to send more than just a message, you will need to use an IDictionary<string, object> to package all of the data. There are some reserved fields that have a special meaning.

  • alert: the notification's message.
  • badge: (iOS only) the value indicated in the top right corner of the app icon. This can be set to a value or to Increment in order to increment the current value by 1.
  • sound: (iOS only) the name of a sound file in the application bundle.
  • content-available: (iOS only) If you are a writing a Newsstand app, or an app using the Remote Notification Background Mode introduced in iOS7 (a.k.a. "Background Push"), set this value to 1 to trigger a background download.
  • action: (Android only) the Intent should be fired when the push is received. If no title or alert values are specified, the Intent will be fired but no notification will appear to the user.
  • title: (Android, Windows 8, and Windows Phone 8 only) the value displayed in the Android system tray or Windows toast notification.

For example, to send a notification that contains a title, you can do the following:

var push = new ParsePush();
push.Channels = new List<string> {"Mets"};
push.Data = new Dictionary<string, object> {
  {"title", "Score Alert"}
  {"alert", "The Mets scored! The game is now tied 1-1!"},
};
await push.SendAsync();

Setting an Expiration Date

When a user's device is turned off or not connected to the internet, push notifications cannot be delivered. If you have a time sensitive notification that is not worth delivering late, you can set an expiration date. This avoids needlessly alerting users of information that may no longer be relevant.

There are two properties provided by the ParsePush class to allow setting an expiration date for your notification. The first is Expiration which simply takes a DateTime? specifying when Parse should stop trying to send the notification.

var push = new ParsePush();
push.Expiration = new DateTime(2014, 4, 15);
push.Alert = "Season tickets on sale until April 15th";
await push.SendAsync();

There is however a caveat with this method. Since device clocks are not guaranteed to be accurate, you may end up with inaccurate results. For this reason, the ParsePush class also provides the ExpirationInterval property which accepts a TimeSpan. The notification will expire after the specified interval has elapsed.

var push = new ParsePush();
push.ExpirationInterval = TimeSpan.FromDays(7);
push.Alert = "Season tickets on sale until April 21st";
await push.SendAsync();

Targeting by Platform

If you build a cross platform app, it is possible you may only want to target one operating system. There are two methods provided to filter which of these devices are targeted. Note that all platforms are targeted by default.

The following example would send a different notification to Android, iOS, and Windows users.

// Notification for Android users
var androidPush = new ParsePush();
androidPush.Alert = "Your suitcase has been filled with tiny robots!";
androidPush.Query = from installation in ParseInstallation.Query
                    where installation.Channels.Contains("suitcaseOwners")
                    where installation.DeviceType == "android"
                    select installation;
await androidPush.SendAsync();

// Notification for iOS users
var iOSPush = new ParsePush();
iosPush.Alert = "Your suitcase has been filled with tiny apples!";
iosPush.Query = from installation in ParseInstallation.Query
                where installation.Channels.Contains("suitcaseOwners")
                where installation.DeviceType == "ios"
                select installation;
await iosPush.SendAsync();

// Notification for Windows 8 users
var winPush = new ParsePush();
winPush.Alert = "Your suitcase has been filled with tiny glass!";
winPush.Query = from installation in ParseInstallation.Query
                where installation.Channels.Contains("suitcaseOwners")
                where installation.DeviceType == "winrt"
                select installation;
await winPush.SendAsync();

// Notification for Windows Phone 8 users
var wpPush = new ParsePush();
wpPush.Alert = "Your suitcase is very hip; very metro."
wpPush.Query = from installation in ParseInstallation.Query
               where installation.Channels.Contains("suitcaseOwners")
               where installation.DeviceType == "winphone"
               select installation;
await winPhonePush.SendAsync();

Scheduling Pushes

Sending scheduled push notifications is not currently supported by the .NET SDK. Take a look at the REST API, JavaScript SDK or the Web Console.

Receiving Pushes

Responding to the Payload

If your app is running while a push notification is received, the ParsePush.PushNotificationReceived event is fired. You can register for this event. This event provides the standard PushNotificationEventArgs. When Parse sends a toast notification, it embeds the JSON payload in the notification. You can extract this JSON payload with ParsePush.PushJson.

ParsePush.ToastNotificationReceived += (sender, args) => {
  var json = ParsePush.PushJson(args);
  object objectId;
  if (json.TryGetValue("objectId", out objectId)) {
    DisplayRichMessageWithObjectId(objectId as string);
  }
};

In Windows 8, you may also receive the JSON payload from the LaunchActivatedEventArgs passed to your application's OnLaunched event.

protected override void OnLaunched(LaunchActivatedEventArgs args) {
  var json = ParsePush.PushJson(args);
  object objectId;
  if (json.TryGetValue("objectId", out objectId)) {
    DisplayRichMessageWithObjectId(objectId as string);
  }
};

In Windows Phone 8, this code would instead be in your page's OnNavigatedTo event:

public override void OnNavigatedTo(NavigationEventArgs args) {
  var json = ParsePush.PushJson(args);
  object objectId;
  if (json.TryGetValue("objectId", out objectId)) {
    DisplayRichMessageWithObjectId(objectId as string);
  }
}

Tracking Pushes and App Opens

To track your users' engagement over time and the effect of push notifications, we provide some hooks in the ParseAnalytics class. In the example above, add the following to your Launching event handler to collect information about when your application was opened, and what triggered it.

ParseAnalytics.TrackAppOpenedAsync(launchArgs);

A null or empty parameter to TrackAppOpenedAsync will track only a standard app-opened event (e.g. if the open wasn't triggered by a toast notification). Application opens and push-related open rates will be available in your application's dashboard.

Tracking on WinRT Applications

On Windows 8, a toast notification can pass a small payload to the launch handler. We take advantage of this to pass a small Parse payload to the app, in order to correlate an app launch with a particular push.

// Override Application.OnLaunched
virtual void OnLaunched(LaunchActivatedEventArgs args) {
    // 'args' contains arguments that are passed to the app
    // during its launch activation from a Toast.
    // More on Toasts: http://msdn.microsoft.com/en-us/library/windows/apps/hh779727.aspx
    ParseAnalytics.TrackAppOpenedAsync(args);
}

Tracking on Windows Phone Applications

You can also track application launches from toast notifications in Windows Phone 8. To track application launches from toasts and tiles, add the following to your App constructor:

this.Startup += (sender, args) => {
  ParseAnalytics.TrackAppOpens(RootFrame);
};

This method will set up event handlers necessary to track all app launches; you should not use TrackAppOpenedAsync if you register event handlers with TrackAppOpens.

Troubleshooting

Setting up Push Notifications is often a source of frustration for developers. The process is complicated and invites problems to happen along the way. If you run into issues, try some of these troubleshooting tips.

  • Make sure you are using the correct Package SID and client secret, as shown in Step 3 of the Windows 8 Push Quickstart.
  • Clean and build your project.
  • Check the number of recipients in your Parse Push Console. Does it match the expected number of recipients? Your push might be targeted incorrectly.
  • Open your project's package.appxmanifest file and make sure "Toast Capable" is set to "yes."

Push Notification Guide

If you haven't installed the SDK yet, please head over to the Push QuickStart to get our SDK up and running.

Introduction

Push Notifications are a great way to keep your users engaged and informed about your app. You can reach your entire user base quickly and effectively. This guide will help you through the setup process and the general usage of Parse to send push notifications.

The JavaScript SDK does not currently support receiving pushes. It can only be used to send notifications to iOS and Android applications. A common use case is to send pushes from Cloud Code.

Setting Up Push

There is no setup required to use the JavaScript SDK for sending push notifications. If you haven't configured your iOS or Android clients to use Push, take a look at their respective setup instruction using the platform toggle at the top.

Installations

Every Parse application installed on a device registered for push notifications has an associated Installation object. The Installation object is where you store all the data needed to target push notifications. For example, in a baseball app, you could store the teams a user is interested in to send updates about their performance.

Note that Installation data can only be modified by the client SDKs, the data browser, or the REST API.

This class has several special fields that help you manage and target devices.

  • badge: The current value of the icon badge for iOS apps. Changes to this value on the server will be used for future badge-increment push notifications.
  • channels: An array of the channels to which a device is currently subscribed.
  • timeZone: The current time zone where the target device is located. This value is synchronized every time an Installation object is saved from the device (readonly).
  • deviceType: The type of device, "ios" or "android" (readonly).
  • installationId: Unique Id for the device used by Parse (readonly).
  • deviceToken: The Apple generated token used for iOS devices (readonly).

Sending Pushes

There are two ways to send push notifications using Parse: channels and advanced targeting. Channels offer a simple and easy to use model for sending pushes, while advanced targeting offers a more powerful and flexible model. Both are fully compatible with each other and will be covered in this section.

Sending notifications is often done from the Web Console, the REST API or from Cloud Code. Since the JavaScript SDK is used in Cloud Code, this is the place to start if you want to send pushes from your Cloud Functions. However, if you decide to send notifications from the JavaScript SDK outside of Cloud Codeor any of the other client SDKs, you will need to set Client Push Enabled in the Push Notifications settings of your Parse app.

Client_push_settings

Using Channels

The simplest way to start sending notifications is using channels. This allows you to use a publisher-subscriber model for sending pushes. Devices start by subscribing to one or more channels, and notifications can later be sent to these subscribers. The channels subscribed to by a given Installation are stored in the channels field of the Installation object.

Subscribing to Channels

The JavaScript SDK does not currently support subscribing iOS and Android devices for pushes. Take a look at the iOS, Android or REST Push guide using the platform toggle at the top.

Sending Pushes to Channels

With the JavaScript SDK, the following code can be used to alert all subscribers of the "Giants" and "Mets" channels about the results of the game. This will display a notification center alert to iOS users and a system tray notification to Android users.

Parse.Push.send({
  channels: [ "Giants", "Mets" ],
  data: {
    alert: "The Giants won against the Mets 2-3."
  }
}, {
  success: function() {
    // Push was successful
  },
  error: function(error) {
    // Handle error
  }
});

Using Advanced Targeting

While channels are great for many applications, sometimes you need more precision when targeting the recipients of your pushes. Parse allows you to write a query for any subset of your Installation objects using the querying API and to send them a push.

Since Installation objects are just like any other object stored in Parse, you can save any data you want and even create relationships between Installation objects and your other objects. This allows you to send pushes to a very customized and dynamic segment of your user base.

Saving Installation Data

The JavaScript SDK does not currently support modifying Installation objects. Take a look at the iOS, Android or REST Push guide using the platform toggle at the top.

Sending Pushes to Queries

Once you have your data stored on your Installation objects, you can use a query to target a subset of these devices. Parse.Installation queries work just like any other Parse query.

var query = new Parse.Query(Parse.Installation);
query.equalTo('injuryReports', true);

Parse.Push.send({
  where: query, // Set our Installation query
  data: {
    alert: "Willie Hayes injured by own pop fly." 
  }
}, {
  success: function() {
    // Push was successful
  },
  error: function(error) {
    // Handle error
  }
});

We can even use channels with our query. To send a push to all subscribers of the "Giants" channel but filtered by those who want score update, we can do the following:

var query = new Parse.Query(Parse.Installation);
query.equalTo('channels', 'Giants'); // Set our channel
query.equalTo('scores', true);

Parse.Push.send({
  where: query,
  data: {
    alert: "Giants scored against the A's! It's now 2-2." 
  }
}, {
  success: function() {
    // Push was successful
  },
  error: function(error) {
    // Handle error
  }
});

If we store relationships to other objects in our Installation class, we can also use those in our query. For example, we could send a push notification to all users near a given location like this.

// Find users near a given location
var userQuery = new Parse.Query(Parse.User);
userQuery.withinMiles("location", stadiumLocation, 1.0);

// Find devices associated with these users
var pushQuery = new Parse.Query(Parse.Installation);
pushQuery.matchesQuery('user', userQuery);

// Send push notification to query
Parse.Push.send({
  where: pushQuery,
  data: {
    alert: "Free hotdogs at the Parse concession stand!" 
  }
}, {
  success: function() {
    // Push was successful
  },
  error: function(error) {
    // Handle error
  }
});

Sending Options

Push notifications can do more than just send a message. In iOS, pushes can also include the sound to be played, the badge number to display as well as any custom data you wish to send. In Android, it is even possible to specify an Intent to be fired upon receipt of a notification. An expiration date can also be set for the notification in case it is time sensitive.

Customizing your Notifications

If you want to send more than just a message, you can set other fields in the data dictionary. There are some reserved fields that have a special meaning.

  • alert: the notification's message.
  • badge: (iOS only) the value indicated in the top right corner of the app icon. This can be set to a value or to Increment in order to increment the current value by 1.
  • sound: (iOS only) the name of a sound file in the application bundle.
  • content-available: (iOS only) If you are a writing a Newsstand app, or an app using the Remote Notification Background Mode introduced in iOS7 (a.k.a. "Background Push"), set this value to 1 to trigger a background download.
  • action: (Android only) the Intent should be fired when the push is received. If not title or alert values are specified, the Intent will be fired but no notification will appear to the user.
  • title: (Android only) the value displayed in the Android system tray notification.

For example, to send a notification that increases the current badge number by 1 and plays a custom sound for iOS devices, and displays a particular title for Android users, you can do the following:

Parse.Push.send({
  channels: [ "Mets" ],
  data: {
    alert: "The Mets scored! The game is now tied 1-1.",
    badge: "Increment",
    sound: "cheering.caf",
    title: "Mets Score!"
  }
}, {
  success: function() {
    // Push was successful
  },
  error: function(error) {
    // Handle error
  }
});

It is also possible to specify your own data in this dictionary. As explained in the Receiving Notifications section for iOS and Android, iOS will give you access to this data only when the user opens your app via the notification and Android will provide you this data in the Intent if one is specified.

var query = new Parse.Query(Parse.Installation);
query.equalTo('channels', 'Indians');
query.equalTo('injuryReports', true);

Parse.Push.send({
  where: query,
  data: {
    action: "com.example.UPDATE_STATUS"
    alert: "Ricky Vaughn was injured in last night's game!",
    name: "Vaughn",
    newsItem: "Man bites dog"
  }
}, {
  success: function() {
    // Push was successful
  },
  error: function(error) {
    // Handle error
  }
});

Setting an Expiration Date

When a user's device is turned off or not connected to the internet, push notifications cannot be delivered. If you have a time sensitive notification that is not worth delivering late, you can set an expiration date. This avoids needlessly alerting users of information that may no longer be relevant.

There are two parameters provided by Parse to allow setting an expiration date for your notification. The first is expiration_time which takes a Date specifying when Parse should stop trying to send the notification. To expire the notification exactly 1 week from now, you can use the following:

Parse.Push.send({
  where: everyoneQuery,
  expiration_time: new Date(2014, 4, 21)
  data: {
    alert: "Season tickets on sale until April 21, 2014"
  }
}, {
  success: function() {
    // Push was successful
  },
  error: function(error) {
    // Handle error
  }
});

Alternatively, you can use the expiration_interval parameter to specify a duration of time before your notification expires. This value is relative to the push_time parameter used to schedule notifications. This means that a push notification scheduled to be sent out in 1 day and an expiration interval of 6 days can be received up to a week from now.

Parse.Push.send({
  push_time: new Date(2014, 4, 15),
  expiration_interval: 518400,
  data: {
    alert: "Season tickets on sale until April 21, 2014"
  
}, {
  success: function() {
    // Push was successful
  },
  error: function(error) {
    // Handle error
  }
});

Targeting by Platform

If you build a cross platform app, it is possible you may only want to target iOS or Android devices. There are two methods provided to filter which of these devices are targeted. Note that both platforms are targeted by default.

The following examples would send a different notification to Android and iOS users.

// Notification for Android users
var query = new Parse.Query(Parse.Installation);
query.equalTo('deviceType', 'android');

Parse.Push.send({
  where: query,
  data: {
    alert: "Your suitcase has been filled with tiny robots!" 
  }
}, {
  success: function() {
    // Push was successful
  },
  error: function(error) {
    // Handle error
  }
});

// Notification for iOS users
var query = new Parse.Query(Parse.Installation);
query.equalTo('deviceType', 'ios');

Parse.Push.send({
  where: query,
  data: {
    alert: "Your suitcase has been filled with tiny apples!" 
  }
}, {
  success: function() {
    // Push was successful
  },
  error: function(error) {
    // Handle error
  }
});

Scheduling Pushes

You can schedule a push in advance by specifying a push_time. For example, if a user schedules a game reminder for a game on April 21, 2014 at noon UTC, you can schedule the push notification by sending:

var query = new Parse.Query(Parse.Installation);
query.equalTo('user_id', 'user_123');

Parse.Push.send({
  where: query,
  data: {
    alert: "You previously created a reminder for the game today" 
  },
  push_time: new Date(2014, 4, 21)
}, {
  success: function() {
    // Push was successful
  },
  error: function(error) {
    // Handle error
  }
});

If you also specify an expiration_interval, it will be calculated from the scheduled push time, not from the time the push is submitted. This means a push scheduled to be sent in a week with an expiration interval of a day will expire 8 days after the request is sent.

The scheduled time cannot be in the past, and can be up to two weeks in the future. It can be an ISO 8601 date with a date, time, and timezone, as in the example above, or it can be a numeric value representing a UNIX epoch time in seconds (UTC). To schedule an alert for April 21, 2014 at noon UTC time, you can set the push_time to either 2014-04-21T12:00:00Z or 1398081600.

Receiving Pushes

The JavaScript SDK does not currently support receiving pushes. To learn more about handling received notifications in iOS or Android, use the platform toggle at the top.

Troubleshooting

For tips on troubleshooting push notifications, check the troubleshooting sections for iOS, Android, and .NET using the platform toggle at the top.

Push Notification Guide

If you haven't installed the SDK yet, please head over to the Push QuickStart to get our SDK up and running.

Introduction

Push Notifications are a great way to keep your users engaged and informed about your app. You can reach your entire user base quickly and effectively. This guide will help you through the setup process and the general usage of Parse to send push notifications.

Setting Up Push

There is no setup required to use the REST API for sending push notifications. If you haven't configured your iOS or Android client to use Push, take a look at their respective setup instructions using the platform toggle at the top.

Installations

Every Parse application installed on a device registered for push notifications has an associated Installation object. The Installation object is where you store all the data needed to target push notifications. For example, in a baseball app, you could store the teams a user is interested in to send updates about their performance.

Using the REST API, Installation objects are available through the Installation end point. This end point behaves a lot like the Object end point and uses the same API for storing and retrieving data.

Note that Installation data is typically modified by the client SDKs. The REST API can be useful for importing or exporting large amounts of subscription data.

The Installation class has several special fields that help you manage and target devices.

  • badge: The current value of the icon badge for iOS apps. Changes to this value on the server will be used for future badge-increment push notifications.
  • channels: An array of the channels to which a device is currently subscribed.
  • timeZone: The current time zone where the target device is located. This value is synchronized every time an Installation object is saved from the device (readonly).
  • deviceType: The type of device, "ios" or "android" (readonly).
  • installationId: Unique Id for the device used by Parse (readonly).
  • deviceToken: The Apple generated token used for iOS devices (readonly).

Sending Pushes

There are two ways to send push notifications using Parse: channels and advanced targeting. Channels offer a simple and easy to use model for sending pushes, while advanced targeting offers a more powerful and flexible model. Both are fully compatible with each other and will be covered in this section.

Sending notifications is often done from the Web Console, the REST API or from Cloud Code. However, push notifications can also be triggered by the existing client SDKs. If you decide to send notifications from the client SDKs, you will need to set Client Push Enabled in the Push Notifications settings of your Parse app.

Client_push_settings

Using Channels

The simplest way to start sending notifications is using channels. This allows you to use a publisher-subscriber model for sending pushes. Devices start by subscribing to one or more channels, and notifications can later be sent to these subscribers. The channels subscribed to by a given Installation are stored in the channels field of the Installation object.

Subscribing to Channels

A channel is identified by a string that starts with a letter and consists of alphanumeric characters, underscores, and dashes. It doesn't need to be explicitly created before it can be used and each Installation can subscribe to any number of channels at a time.

Subscribing to a channel via the REST API can be done by updating the Installation object. We send a PUT request to the Installation URL and update the channels field. For example, in a baseball score app, we could do:

import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/installations/mrmBZvsErB', json.dumps({
       "channels": [
         "Giants"
       ]
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result
curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "channels": [
          "Giants"
        ]
      }' \
  https://api.parse.com/1/installations/mrmBZvsErB

Once subscribed to the "Giants" channel, your Installation object should have an updated channels field.

Installation_channel

To unsubscribe from a channel you would need to update the channels array and remove the unsubscribed channel.

Sending Pushes to Channels

With the REST API, the following code can be used to alert all subscribers of the "Giants" and "Mets" channels about the results of the game. This will display a notification center alert to iOS users and a system tray notification to Android users.

import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "channels": [
         "Giants",
         "Mets"
       ],
       "data": {
         "alert": "The Giants won against the Mets 2-3."
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result
curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "channels": [
          "Giants",
          "Mets"
        ],
        "data": {
          "alert": "The Giants won against the Mets 2-3."
        }
      }' \
  https://api.parse.com/1/push

Using Advanced Targeting

While channels are great for many applications, sometimes you need more precision when targeting the recipients of your pushes. Parse allows you to write a query for any subset of your Installation objects using the querying API and to send them a push.

Since Installation objects are just like any other object stored in Parse, you can save any data you want and even create relationships between Installation objects and your other objects. This allows you to send pushes to a very customized and dynamic segment of your user base.

Saving Installation Data

Storing arbitrary data on an Installation object is done in the same way we store data on any other object on Parse. In our Baseball app, we could allow users to get pushes about game results, scores and injury reports.

import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/installations/mrmBZvsErB', json.dumps({
       "scores": True,
       "gameResults": True,
       "injuryReports": True
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result
curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "scores": true,
        "gameResults": true,
        "injuryReports": true
      }' \
  https://api.parse.com/1/installations/mrmBZvsErB

You can even create relationships between your Installation objects and other classes saved on Parse. To associate an Installation with a particular user, for example, you can use a pointer to the _User class on the Installation.

import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/installations/mrmBZvsErB', json.dumps({
       "user": {
         "__type": "Pointer",
         "className": "_User",
         "objectId": "vmRZXZ1Dvo"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result
curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "user": {
          "__type": "Pointer",
          "className": "_User",
          "objectId": "vmRZXZ1Dvo"
        }
      }' \
  https://api.parse.com/1/installations/mrmBZvsErB

Sending Pushes to Queries

Once you have your data stored on your Installation objects, you can use a query to target a subset of these devices. Installation queries work just like any other Parse query.

import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "where": {
         "injuryReports": True
       },
       "data": {
         "alert": "Willie Hayes injured by own pop fly."
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result
curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "where": {
          "injuryReports": true
        },
        "data": {
          "alert": "Willie Hayes injured by own pop fly."
        }
      }' \
  https://api.parse.com/1/push

We can even use channels with our query. To send a push to all subscribers of the "Giants" channel but filtered by those who want score update, we can do the following:

import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "where": {
         "channels": "Giants",
         "scores": True
       },
       "data": {
         "alert": "Giants scored against the A's! It's now 2-2."
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result
curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "where": {
          "channels": "Giants",
          "scores": true
        },
        "data": {
          "alert": "Giants scored against the A's! It's now 2-2."
        }
      }' \
  https://api.parse.com/1/push

If we store relationships to other objects in our Installation class, we can also use those in our query. For example, we could send a push notification to all users near a given location like this.

import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "where": {
         "user": {
           "$inQuery": {
             "location": {
               "$nearSphere": {
                 "__type": "GeoPoint",
                 "latitude": 30.0,
                 "longitude": -20.0
               },
               "$maxDistanceInMiles": 1.0
             }
           }
         }
       },
       "data": {
         "alert": "Free hotdogs at the Parse concession stand!"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result
curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "where": {
          "user": {
            "$inQuery": {
              "location": {
                "$nearSphere": {
                  "__type": "GeoPoint",
                  "latitude": 30.0,
                  "longitude": -20.0
                },
                "$maxDistanceInMiles": 1.0
              }
            }
          }
        },
        "data": {
          "alert": "Free hotdogs at the Parse concession stand!"
        }
      }' \
  https://api.parse.com/1/push

An in depth look at the Installation end point can be found in the REST guide.

Sending Options

Push notifications can do more than just send a message. In iOS, pushes can also include the sound to be played, the badge number to display as well as any custom data you wish to send. In Android, it is even possible to specify an Intent to be fired upon receipt of a notification. An expiration date can also be set for the notification in case it is time sensitive.

Customizing your Notifications

If you want to send more than just a message, you can set other fields in the data dictionary. There are some reserved fields that have a special meaning.

  • alert: the notification's message.
  • badge: (iOS only) the value indicated in the top right corner of the app icon. This can be set to a value or to Increment in order to increment the current value by 1.
  • sound: (iOS only) the name of a sound file in the application bundle.
  • content-available: (iOS only) If you are a writing a Newsstand app, or an app using the Remote Notification Background Mode introduced in iOS7 (a.k.a. "Background Push"), set this value to 1 to trigger a background download.
  • action: (Android only) the Intent should be fired when the push is received. If no title or alert values are specified, the Intent will be fired but no notification will appear to the user.
  • title: (Android only) the value displayed in the Android system tray notification.
For example, to send a notification that increases the current badge number by 1 and plays a custom sound for iOS devices, and displays a particular title for Android users, you can do the following:

import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "channels": [
         "Mets"
       ],
       "data": {
         "alert": "The Mets scored! The game is now tied 1-1.",
         "badge": "Increment",
         "sound": "cheering.caf",
         "title": "Mets Score!"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result
curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "channels": [
          "Mets"
        ],
        "data": {
          "alert": "The Mets scored! The game is now tied 1-1.",
          "badge": "Increment",
          "sound": "cheering.caf",
          "title": "Mets Score!"
        }
      }' \
  https://api.parse.com/1/push

It is also possible to specify your own data in this dictionary. As explained in the Receiving Notifications section for iOS and Android, iOS will give you access to this data only when the user opens your app via the notification and Android will provide you this data in the Intent if one is specified.

import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "channels": [
         "Indians"
       ],
       "data": {
         "action": "com.example.UPDATE_STATUS",
         "alert": "Ricky Vaughn was injured in last night's game!",
         "name": "Vaughn",
         "newsItem": "Man bites dog"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result
curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "channels": [
          "Indians"
        ],
        "data": {
          "action": "com.example.UPDATE_STATUS",
          "alert": "Ricky Vaughn was injured in last night's game!",
          "name": "Vaughn",
          "newsItem": "Man bites dog"
        }
      }' \
  https://api.parse.com/1/push

Setting an Expiration Date

When a user's device is turned off or not connected to the internet, push notifications cannot be delivered. If you have a time sensitive notification that is not worth delivering late, you can set an expiration date. This avoids needlessly alerting users of information that may no longer be relevant.

There are two parameters provided by Parse to allow setting an expiration date for your notification. The first is expiration_time which takes a date (in ISO 8601 format or Unix epoch time) specifying when Parse should stop trying to send the notification. To expire the notification exactly 1 week from now, you can use the following command.

import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "expiration_time": "2014-04-21T22:47:05Z",
       "data": {
         "alert": "Season tickets on sale until April 21, 2014"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result
curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "expiration_time": "2014-04-21T22:47:05Z",
        "data": {
          "alert": "Season tickets on sale until April 21, 2014"
        }
      }' \
  https://api.parse.com/1/push

Alternatively, you can use the expiration_interval parameter to specify a duration of time before your notification expired. This value is relative to the push_time parameter used to schedule notifications. This means that a push notification scheduled to be sent out in 1 day and an expiration interval of 6 days can be received up to a week from now.

import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "push_time": "2014-04-15T22:47:05Z",
       "expiration_interval": 518400,
       "data": {
         "alert": "Season tickets on sale until April 21, 2014"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result
curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "push_time": "2014-04-15T22:47:05Z",
        "expiration_interval": 518400,
        "data": {
          "alert": "Season tickets on sale until April 21, 2014"
        }
      }' \
  https://api.parse.com/1/push

Targeting by Platform

If you build a cross platform app, it is possible you may only want to target iOS or Android devices. There are two methods provided to filter which of these devices are targeted. Note that both platforms are targeted by default.

The following examples would send a different notification to Android and iOS users.

import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "where": {
         "deviceType": "android"
       },
       "data": {
         "alert": "Your suitcase has been filled with tiny robots!"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result
curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "where": {
          "deviceType": "android"
        },
        "data": {
          "alert": "Your suitcase has been filled with tiny robots!"
        }
      }' \
  https://api.parse.com/1/push
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "where": {
         "deviceType": "ios"
       },
       "data": {
         "alert": "Your suitcase has been filled with tiny apples!"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result
curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "where": {
          "deviceType": "ios"
        },
        "data": {
          "alert": "Your suitcase has been filled with tiny apples!"
        }
      }' \
  https://api.parse.com/1/push

Scheduling Pushes

You can schedule a push in advance by specifying a push_time. For example, if a user schedules a game reminder for a game on April 21, 2014 at noon UTC, you can schedule the push notification by sending:

import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "where": {
         "user_id": "user_123"
       },
       "push_time": "2014-04-21T12:00:00Z",
       "data": {
         "alert": "You previously created a reminder for the game today"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result
curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "where": {
          "user_id": "user_123"
        },
        "push_time": "2014-04-21T12:00:00Z",
        "data": {
          "alert": "You previously created a reminder for the game today"
        }
      }' \
  https://api.parse.com/1/push

If you also specify an expiration_interval, it will be calculated from the scheduled push time, not from the time the push is submitted. This means a push scheduled to be sent in a week with an expiration interval of a day will expire 8 days after the request is sent.

The scheduled time cannot be in the past, and can be up to two weeks in the future. It can be an ISO 8601 date with a date, time, and timezone, as in the example above, or it can be a numeric value representing a UNIX epoch time in seconds (UTC). To schedule an alert for April 21, 2014 at noon UTC time, you can set the push_time to either 2014-04-21T12:00:00Z or 1398081600.

Local Push Scheduling

The push_time parameter can schedule a push to be delivered to each device according to its time zone. This technique delivers a push to all Installation objects with a timeZone member when that time zone would match the push time. For example, if an app had a device in timezone America/New_York and another in America/Los_Angeles, the first would receive the push three hours before the latter.

To schedule a push according to each device's local time, the timeZone parameter should be an ISO 8601 date without a time zone, i.e. 2014-04-21T12:00:00 . Note that Installations without a timeZone will be excluded from this localized push.

Receiving Pushes

Since push notifications are sent to clients, there is no REST API end point for receiving notifications. To learn more about handling received notifications in iOS or Android, use the platform toggle at the top.

Troubleshooting

For tips on troubleshooting push notifications, check the troubleshooting sections for iOS, Android, and .NET using the platform toggle at the top.