Registering your app users for push

Push notifications can be sent from Dotdigital ,but only to users who have had a push profile linked to them. The way a Dotdigital contact is linked to a push profile is by setting an email address on the push profile. When this is done, if the Dotdigital contact already exists using the email address, the push profile will be linked to it, otherwise we create a contact using the email address and link it to the push profile automatically.

🚧

Ask users to enter their email address

If you don't have an email address for your app user, you should ask users if they'd like to receive push notifications from you and prompt them to enter their email address.

Prerequisite knowledge

The following concepts are useful to understand when working with the SDK:

Your push audience is discovered

Unlike channels such as email or SMS, it's not possible to import data to make contacts in Dotdigital push contactable. Your push audience is discovered as your users or customers open your app with the App Messaging SDK integrated into it, as it passes to Dotdigital the necessary push tokens and email address to send a push message.

When a contact is push contactable the PUSHOPTIN_xxx data field is populated, otherwise this field is blank.

❗️

Do not edit or amend the PUSHOPTIN field

The PUSHOPTIN_xxx data field is automatically managed by the platform and should not be altered or populated manually, as this will cause issues with push messaging.

Push profiles

The SDK has a concept of a profile, used to represent the app user, which is created after the SDK is initialised and a session is started. It is at this point that the SDK asks your app for the JWT (JSON Web Token) that represents the app user, as explained in our Creating a JSON Web Token page. The sub claim from the JWT is used for the push profile id, as explained here


Sessions

You require session in order to send push messages to a device, so you need to start one if this has been done already. Sessions persist between app launches, so they only need starting once, or if no session exists.

When a session is started, the JWT token is used to create the user's profile ID ('profileId' string). This profile ID remains the same until a session is stopped.

When a session is stopped and started again, a new JWT token is requested and used to create a profile. We recommend that your JWT always uses the same profile id for the same user in the JWT's sub claim so that you don't end up with any duplication of profiles.

If the user uninstalls the app or clears the app data we won't know about this. The push token that we store eventually expires. When an expired token is used for sending push message the failure prompts the system to clear it from the device and the contact. Until the expiry is checked as part of a send attempt we have no way to know if it is still valid.
The only way to explicitly remove the token is to call the endSession method in the SDK.

client.service().session().endSession(
   new Callback<ComapiResult<Void>>(){/* implement */});
client.services.session.endSession();
sdk.session.endSession();

If someone uninstalls the app then they won't receive a push message on the device. However, just clearing the app data doesn't have an effect on messages being delivered to the device until the push token expires.

🚧

Does your app support switching users?

To avoid the same push profile being attached to multiple contacts in Dotdigital it's important to ensure you stop the session whenever a user logs out of your app. Then when a new user logs in you can ensure a session with a push profile for the new user is used.

Updating the profile with the email address

  1. After you've initialised the SDK and before you can update the profile with an email address, you need to check whether a session has been started; the code to do this is:
if(client.getSession() != null && client.getSession().isSuccessfullyCreated()) {/*Implement*/}
BOOL isSuccessfullyCreated = [client isSessionSuccessfullyCreated];

If the session hasn't been started, start it by calling the startSession() method then continue to step 2. Otherwise, skip to step 2.

client.service().session().startSession(new Callback<Session>() { /*Implement */ });
[client.services.session startSessionWithCompletion:^{
  // session successfully created
} failure:^(NSError * _Nullable error) {
  // error ocurred
}];
COMAPI.Foundation.initialise(comapiConfig)
    .then(function (sdk) {
        console.log("Foundation interface created", sdk);
    })
    .catch(function (error) {
        $log.error("paragonService: failed to initialise", error);
    });
  1. Use the getProfileId() method on the Session object to retrieve the app users profile id, and then pass the profile id to the getProfile() method to retrieve the full profile.

The getProfile() method returns a ComapiResult<T> object with the following methods:

  • result.isSuccessful(): Indicates that the profile was retrieved or not

  • result.getResult(): The profile data

  • result.getETag(): Version of the data

  • result.getMessage(): HTTP status message

  • result.getErrorBody() Error details

  • result.getCode(): HTTP status code

if(client.getSession() != null && client.getSession().isSuccessfullyCreated()) {
  client.service().profile().getProfile(client.getSession().getProfileId(), new Callback<ComapiResult<Map<String, Object>>>() {
    @Override
    public void success(ComapiResult<Map<String, Object>> result) {	
      @Override
      public void error(Throwable t) {
        //Error
      }
    }
  }
}
[client.services.profile getProfileForProfileID:@"<PROFILE-ID>" completion:^(CMPResult<CMPProfile *> * result) {
    if (result.error) {
        // error occurred
    } else {
        // success
    }
}];
sdk.services.profile.getMyProfile()
    .then(function (profile) {
			// Use the profile
    })
    .catch(function (error) {
        console.error("getMyProfile() failed", error);
    });
  1. When you have the user's profile data, add an email address to it and patch the profile.

📘

eTags

An eTag string contains data about the version of a resource and is returned from every service response.

When updating a profile, the eTag string is used to check that the profile hasn't already been updated before you update it.

When you use the patchMyProfile() method, you need to pass it the eTag, which is returned from the result of the getProfile() method.

public void success(ComapiResult<Map<String, Object>> result) {
  Map <String, Object> additionalMap = new HashMap<>();
  //Add the user's email address to the profile
  additionalMap.put("email", "[email protected]");
  client.service().profile().patchMyProfile(additionalMap, result.getETag(), new Callback<ComapiResult<Map<String, Object>>>() { }
[client.services.profile patchProfileForProfileID:@"<PROFILE-ID>" attributes:@{@"email" : @"[email protected]"} eTag:result.eTag completion:^(CMPResult<CMPProfile *> * result) {
    if (result.error) {
        // error occurred
    } else {
        // success
    }
}];
sdk.services.profile.getMyProfile()
    .then(function (profile) {
  			profile.email = "[email protected]";
        sdk.services.profile.updateMyProfile(profile);
    })
    .catch(function (error) {
        console.error("getMyProfile() failed", error);
    });

🚧

A push profile needs at least 1 valid device to be used for push

The push profile must have at least 1 device registered against it with an FCM or APNS token to be associated with an Dotdigital contact. If not the contacts PUSHOPTIN field remains empty and they cannot use the push channel.

👍

All done!

Now, when a user launches your app, the user's profile data is sent to Dotdigital and (if that profile contains an email address that belongs to one of your contacts) that contact can now receive push notifications from Dotdigital 🎉

Checking a contacts device data

To verify that you have integrated the SDK correctly, and passed your user registration information correctly, you use the Devices tab when viewing a contact within Dotdigital. To do this:

  1. Log in to Dotdigital.
  2. Go to Audience > Contacts.
  3. Search for the contact using the email address you registered for them.
  4. Select the contact.
  5. Select the Devices tab.
The Devices tab when viewing a contact in Dotdigital

The Devices tab when viewing a contact in Dotdigital

A contact can have multiple devices registered to them, and when you push to a contact we send the push to all devices that have a valid push token. The push token can be seen in the device details on the right in the Registration ID field. If this is not present, then either the user has not allowed push permissions or you haven't registered the push token correctly with the SDK, so please check your app code.

Common issues

No device details showing for a contact

Check that you have registered an email address with the SDK as covered here, as it this email address that is used to link an instance of your app on a device to a contact in Dotdigital.

I have devices but I am not receiving pushes

The following two prerequisites are required in order to successfully send a push to a contact:

  1. They have 1 or more devices registered to them; check the contact's devices in the Devices tab as described above.
  2. At least one device has a valid push token. The push token can be seen in the device details on the right in the Registration ID field on the contacts Devices tab. If this is not present then either:
  • the user has not allowed push permissions
  • your app isn't registering the push token correctly with the SDK, so please check your app code. See:
  • the push profile has invalid APNS and/or FCM details configured; please check your settings again if you are not seeing push tokens registered but you believe your app code is correct.

📘

Still having issues?

Please see the Push troubleshooting guide for more help

Unregistering app users

If you want users to be able to opt-out of push notifications you will need to end their push session in the SDK, which will delete any push tokens from the Dotdigital platform and clear the PUSH_OPTIN data field, which indicates they are no longer push contactable.

To end a session:

[client.services.session endSessionWithCompletion:^(CMPResult<NSNumber *> * result) {
    if (result.error) {
      // error occurred
    } else {
      BOOL success = [result.object boolValue];
      if (success) {
        // session successfully ended
      }     
    }
}];
client.services.session.endSession(completion: { [weak self] in
                                                  // Session ended
                                                  completion(nil)
                                                 })
}) { (error) in
    completion(error)
   }
client.service().session().endSession(
   new Callback<ComapiResult<Void>>(){/* implement */});
rxClient.service().session().endSession()
   .subscribe(new Observer<ComapiResult<Void>>(){/* implement */});
await <Your push SDK instance>.endSession();

Checking for push permission changes

You may well also wish to check if a user has revoked the apps push permissions and if so end their session so that this is reflected in Dotdigital. You could do the following to achieve this:

  1. When the app is launched check with the operating system if push permissions have been granted
  2. If they have not been granted you could either call end session (see above) in the SDK to remove the push registration from the user or maybe prompt them to grant the push permission again.
  3. If you do prompt the user and they do grant the push permission you must start a session with the SDK to ensure a push token is acquired and sent to Dotdigital:
[client.services.session startSessionWithCompletion:^{
  // session successfully created
} failure:^(NSError * _Nullable error) {
  // error ocurred
}];
client.services.session.startSession(completion: { [weak self] in
                                                  // Session started
                                                  completion(nil)
                                                 })
}) { (error) in
    completion(error)
   }
client.service().session().startSession(new Callback<Session>(){/* implement */});
rxClient.service().session().startSession()
   .subscribe(new Observer<Session>(){/* implement */});
await <Your push SDK instance>.startSession();