OneSignal
The OneSignal integration is available to all users signed up after September '23, the legacy Grow and Pro plans, and Enterprise plans. If you're on a legacy Free or Starter plan and want to access this integration, migrate to our new pricing via your billing settings.
OneSignal can be a useful integration tool for understanding what stage a customer is in to react accordingly. RevenueCat can automatically update user tags in OneSignal with their latest subscription status.
With our OneSignal integration, you can:
- Send an onboarding campaign to a user in a free trial
- Send a push notification to churned users and offer them a discount
With accurate and up-to-date subscription data in OneSignal, you'll be set to turbocharge your campaigns ⚡️
For every auto-renewing subscription event in RevenueCat, the following tags get added or updated on the user in OneSignal. By leaving the tag blank in the RevenueCat dashboard, you can choose to not send any value for specific tag(s).
Tag | Description |
---|---|
app_user_id | The RevenueCat App User Id that triggered the event |
period_type | The latest period type for the purchase or renewal. Either: TRIAL (for free trials), INTRO (or introductory pricing), NORMAL (standard subscription) |
purchased_at | Epoch time in seconds of the latest subscription purchase or renewal |
expiration_at | Epoch time in seconds of the latest subscription expiration date |
store | Either APP_STORE , PLAY_STORE , or STRIPE |
environment | Either SANDBOX or PRODUCTION |
last_event_type | The latest event type from the user. Either: INITIAL_PURCHASE , TRIAL_STARTED , TRIAL_CONVERTED , TRIAL_CANCELLED , RENEWAL , CANCELLATION |
product_id | The latest subscription product identifier that the user has purchased or renewed |
entitlement_ids | Comma separated string of RevenueCat Entitlement identifiers that the user unlocked |
active_subscription | The value will be set to true on any purchase/renewal event, and false on EXPIRATION |
subscription_status | See Subscription Status Attribute below |
grace_period_expiration_at | If a billing issue occurs, we will send the date of the grace period expiration. |
RevenueCat only updates data tags in OneSignal in response to auto-renewing subscription events.
Integration at a Glance
Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
---|---|---|---|---|---|
❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
Events
The OneSignal integration tracks the following events:
Event | Default Event Name | Description | App Store | Play Store | Amazon | Stripe | Promo |
---|---|---|---|---|---|---|---|
Initial Purchase | initial_purchase | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
Trial Started | trial_started | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
Trial Converted | trial_converted | When an auto-renewing subscription product converts from a free trial to normal paid period. | ✅ | ✅ | ✅ | ✅ | ❌ |
Trial Cancelled | trial_cancelled | When a user turns off renewals for an auto-renewing subscription product during a free trial period. | ✅ | ✅ | ✅ | ✅ | ❌ |
Renewal | renewal | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
Cancellation | cancellation | A subscription or non-renewing purchase has been cancelled. See cancellation reasons for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
Uncancellation | uncancellation | A non-expired cancelled subscription has been re-enabled. | ✅ | ✅ | ✅ | ❌ | ❌ |
Non Subscription Purchase | non_subscription_purchase | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
Subscription paused | subscription_paused | A subscription has been paused. | ❌ | ✅ | ❌ | ❌ | ❌ |
Expiration | expiration | A subscription has expired and access should be removed. If you have Platform Server Notifications configured, this event will occur as soon as we are notified (within seconds to minutes) of the expiration. If you do not have notifications configured, delays may be approximately 1 hour. | ✅ | ✅ | ✅ | ✅ | ✅ |
Billing Issue | billing_issue | There has been a problem trying to charge the subscriber. This does not mean the subscription has expired. Can be safely ignored if listening to CANCELLATION event + cancel_reason=BILLING_ERROR. | ✅ | ✅ | ✅ | ✅ | ❌ |
Product Change | product_change | A subscriber has changed the product of their subscription. This does not mean the new subscription is in effect immediately. See Managing Subscriptions for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
1. Send device data to RevenueCat
1.1 User-centric API versions of OneSignal (11.0 and above)
The OneSignal integration requires some user-specific data. RevenueCat will only update users in OneSignal if the below data has been added as Subscriber Attributes for the user.
Key | Description | Required |
---|---|---|
$onesignalUserId | The OneSignal ID used to represent the user. | ✅ |
This property can be set manually, like any other Subscriber Attributes, or through the helper method setOnesignalUserID()
.
You can listen for changes to the OneSignal Id through their SDK, and send the value to RevenueCat. If you already have OneSignal set up, you should make sure that you're also sending the OneSignal Id for users that are updating to the latest version of your app.
- UIKit
- SwiftUI
class AppDelegate: UIResponder, UIApplicationDelegate, OSUserStateObserver {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
Purchases.configure(withAPIKey: "<revenuecat_api_key>")
// Add your AppDelegate as an observer
OneSignal.User.addObserver(self)
OneSignal.initialize("<onesignal_app_id>", withLaunchOptions: launchOptions)
// If you've already set up OneSignal, then users should already have
// a OneSignal Id. We can check if it's available and send it to RevenueCat
if let onesignalId = OneSignal.User.onesignalId {
// It is recommended to confirm the associated `externalId` to ensure
// you are capturing the correct data for the user you expect
if OneSignal.User.externalId == "<expected_user_external_id>" {
Purchases.shared.attribution.setOnesignalUserID(onesignalId)
} else {
// handle unexpected externalId
}
}
return true
}
}
public extension AppDelegate: OSUserStateObserver {
// Add this method to update the $onesignalUserId in RevenueCat whenever it changes
// This code should be sufficient to capture all new users if you're setting
// up OneSignal for the first time.
func onUserStateDidChange(state: OSUserChangedState) {
let onesignalId = state.current.onesignalId
let externalId = state.current.externalId
// Confirm the `onesignalId` is for the expected user by also checking the associated `externalId`
// For example, if the device is offline, there may be cached user-related requests
if let onesignalId,
externalId == "<expected_user_external_id>" {
Purchases.shared.attribution.setOnesignalUserID(onesignalId)
}
}
}
@main
struct MyApp: App {
init() {
Purchases.configure(withAPIKey: "<revenuecat_api_key>")
// Add your AppDelegate as an observer
OneSignal.User.addObserver(self)
OneSignal.initialize("<onesignal_app_id>", withLaunchOptions: launchOptions)
// If you've already set up OneSignal, then users should already have
// a OneSignal Id. We can check if it's available and send it to RevenueCat
if let onesignalId = OneSignal.User.onesignalId {
// It is recommended to confirm the associated `externalId` to ensure
// you are capturing the correct data for the user you expect
if OneSignal.User.externalId == "<expected_user_external_id>" {
Purchases.shared.attribution.setOnesignalUserID(onesignalId)
} else {
// handle unexpected externalId
}
}
return true
}
}
public extension MyApp: OSUserStateObserver {
// Add this method to update the $onesignalUserId in RevenueCat whenever it changes
// This code should be sufficient to capture all new users if you're setting
// up OneSignal for the first time.
func onUserStateDidChange(state: OSUserChangedState) {
let onesignalId = state.current.onesignalId
let externalId = state.current.externalId
// Confirm the `onesignalId` is for the expected user by also checking the associated `externalId`
// For example, if the device is offline, there may be cached user-related requests
if let onesignalId,
externalId == "<expected_user_external_id>"
{ Purchases.shared.attribution.setOnesignalUserID(onesignalId) }
}
}
1.2 Device-centric API versions of OneSignal (9.0 and below)
The OneSignal integration requires some device-specific data. RevenueCat will only update users in OneSignal if the below data has been added as Attributes for the Customer.
Key | Description | Required |
---|---|---|
$onesignalId | The OneSignal Player Id for the user. | ✅ |
This property can be set manually, like any other Attribute, or through the helper method setOnesignalID()
.
You can listen for changes to the OneSignal Id through their SDK, and send the value to RevenueCat. If you already have OneSignal set up, you should make sure that you're also sending the OneSignal Id for users that are updating to the latest version of your app.
- Swift
class AppDelegate: UIResponder, UIApplicationDelegate, OSSubscriptionObserver {
var window: UIWindow?
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
Purchases.configure(withAPIKey: "<revenuecat_api_key>", appUserID: nil)
OneSignal.initWithLaunchOptions(launchOptions, appId: "<onesignal_app_id>")
OneSignal.add(self as OSSubscriptionObserver)
// If you've already set up OneSignal, then users should already have
// a OneSignal Id. We can check if it's available and send it to RevenueCat
if let onesignalId = OneSignal.getUserDevice()?.getUserId() {
Purchases.shared.attribution.setOnesignalID(onesignalId)
}
return true
}
// Add this method to update the $onesignalId in RevenueCat whenever it changes
// This code should be sufficient to capture all new users if you're setting
// up OneSignal for the first time.
func onOSSubscriptionChanged(_ stateChanges: OSSubscriptionStateChanges!) {
if !stateChanges.from.subscribed && stateChanges.to.subscribed {
// The user is subscribed
// Either the user subscribed for the first time
Purchases.shared.attribution.setOnesignalID(stateChanges.to.userId)
}
}
}
2. Send RevenueCat events into OneSignal
After you've set up the Purchases SDK to send device data to RevenueCat, you can "turn on" the integration and configure the tag names from the RevenueCat dashboard.
- Navigate to your project in the RevenueCat dashboard and find the Integrations card in the left menu. Select + New
- Choose OneSignal from the Integrations menu.
- Add your OneSignal App Id and OneSignal API key.
- Enter the tag names that RevenueCat should use, or choose the default tag names.
3. Testing the OneSignal integration
You can test the OneSignal integration end-to-end before going live. It's recommended that you test the integration is working properly for new users, and any existing users that may update their app to a new version.
Make a sandbox purchase with a new user
Simulate a new user installing your app, and go through your app flow to complete a sandbox purchase.
Check that the required device data is collected
Navigate the the Customer View for the test user that just made a purchase. Make sure that all of the required data from step 1 above is listed as attributes for the user.
Check that the OneSignal event delivered successfully
While still on the Customer View, click into the test purchase event in the Customer History and make sure that the OneSignal integration event exists and was delivered successfully.
Sample Events
Below are sample JSONs that are delivered to OneSignal for events.
- Initial Purchase
- Trial Started
- Trial Converted
- Trial Cancelled
- Renewal
- Cancellation
- Uncancellation
- Non Subscription Purchase
- Subscription Paused
- Expiration
- Billing Issue
- Product Change
{
"app_id": "12345678-1234-1234-1234-123456789012",
"tags": {
"user_id": "$RCAnonymousID:87c6049c58069238dce29853916d624c",
"period_type": "NORMAL",
"purchased_at": 1600016247,
"expiration_at": 1602608247,
"store": "APP_STORE",
"environment": "PRODUCTION",
"last_event_type": "initial_purchase",
"last_event_at": 1600016250,
"product_id": "monthly_sub",
"entitlement_ids": "Pro"
}
}
{
"app_id": "12345678-1234-1234-1234-123456789012",
"tags": {
"user_id": "$RCAnonymousID:87c6049c58069238dce29853916d624c",
"period_type": "TRIAL",
"purchased_at": 1600031584,
"expiration_at": 1600290784,
"store": "APP_STORE",
"environment": "PRODUCTION",
"last_event_type": "trial_started",
"last_event_at": 1600031586,
"product_id": "three_month_sub_trial",
"entitlement_ids": "Pro"
}
}
{
"app_id": "12345678-1234-1234-1234-123456789012",
"tags": {
"app_user_id": "$RCAnonymousID:87c6049c58069238dce29853916d624c",
"period_type": "NORMAL",
"purchased_at": 1602136340,
"expiration_at": 1602741140,
"store": "APP_STORE",
"environment": "PRODUCTION",
"last_event_type": "trial_converted",
"last_event_at": 1602114850,
"product_id": "weekly_sub_trial",
"entitlement_ids": null
}
}
{
"app_id": "12345678-1234-1234-1234-123456789012",
"tags": {
"app_user_id": "$RCAnonymousID:87c6049c58069238dce29853916d624c",
"period_type": "TRIAL",
"purchased_at": 1602051920,
"expiration_at": 1602311120,
"store": "APP_STORE",
"environment": "PRODUCTION",
"last_event_type": "trial_cancelled",
"last_event_at": 1602129368,
"product_id": "weekly_sub_trial",
"entitlement_ids": null
}
}
{
"app_id": "12345678-1234-1234-1234-123456789012",
"tags": {
"app_user_id": "$RCAnonymousID:87c6049c58069238dce29853916d624c",
"period_type": "NORMAL",
"purchased_at": 1602125078,
"expiration_at": 1604807078,
"store": "APP_STORE",
"environment": "PRODUCTION",
"last_event_type": "renewal",
"last_event_at": 1602122793,
"product_id": "monthly_sub",
"entitlement_ids": "Pro"
}
}
{
"app_id": "12345678-1234-1234-1234-123456789012",
"tags": {
"app_user_id": "$RCAnonymousID:87c6049c58069238dce29853916d624c",
"period_type": "NORMAL",
"purchased_at": 1602086660,
"expiration_at": 1602691460,
"store": "APP_STORE",
"environment": "PRODUCTION",
"last_event_type": "cancellation",
"last_event_at": 1602118600,
"product_id": "weekly_sub",
"entitlement_ids": null
}
}
{
"app_id": "12345678-1234-1234-1234-123456789012",
"tags": {
"app_user_id": "$RCAnonymousID:87c6049c58069238dce29853916d624c",
"period_type": "TRIAL",
"purchased_at": 1663445025,
"expiration_at": 1664049825,
"store": "APP_STORE",
"environment": "PRODUCTION",
"last_event_type": "uncancellation",
"last_event_at": 1663969096,
"product_id": "annual_sub",
"entitlement_ids": "Premium"
}
}
{
"app_id": "12345678-1234-1234-1234-123456789012",
"tags": {
"app_user_id": "$RCAnonymousID:87c6049c58069238dce29853916d624c",
"purchased_at": 1602086660,
"store": "APP_STORE",
"environment": "PRODUCTION",
"last_event_type": "non_renewing_purchase",
"last_event_at": 1602118600,
"product_id": "one_time_purchase_product",
"entitlement_ids": null
}
}
{
"app_id": "12345678-1234-1234-1234-123456789012",
"tags": {
"app_user_id": "$RCAnonymousID:87c6049c58069238dce29853916d624c",
"period_type": "NORMAL",
"purchased_at": 1602086660,
"expiration_at": 1602691460,
"store": "PLAY_STORE",
"environment": "PRODUCTION",
"last_event_type": "subscription_paused",
"last_event_at": 1602118600,
"product_id": "weekly_sub",
"auto_resume_at": 1602119600,
"entitlement_ids": null
}
}
{
"app_id": "12345678-1234-1234-1234-123456789012",
"tags": {
"period_type": "NORMAL",
"purchased_at": 1652374230,
"expiration_at": 1652979030,
"last_event_type": "expiration",
"last_event_at": 1652988735
}
}
{
"app_id": "12345678-1234-1234-1234-123456789012",
"tags": {
"app_user_id": "$RCAnonymousID:87c6049c58069238dce29853916d624c",
"period_type": "TRIAL",
"purchased_at": 1652383957,
"expiration_at": 1654371157,
"store": "APP_STORE",
"environment": "PRODUCTION",
"last_event_type": "billing_issue",
"last_event_at": 1652988776,
"product_id": "annual_sub",
"entitlement_ids": "Premium"
}
}
{
"app_id": "12345678-1234-1234-1234-123456789012",
"tags": {
"app_user_id": "$RCAnonymousID:87c6049c58069238dce29853916d624c",
"period_type": "NORMAL",
"purchased_at": 1602086660,
"expiration_at": 1602691460,
"store": "APP_STORE",
"environment": "PRODUCTION",
"last_event_type": "product_change",
"last_event_at": 1602118600,
"product_id": "weekly_sub",
"new_product_id": "monthly_sub",
"entitlement_ids": null
}
}
If your tags aren't working and RevenueCat is sending events successfully with 200 codes, check out OneSignal's troubleshooting guide.
You should start seeing subscription data from RevenueCat appear on users in OneSignal.
Subscription Status Attribute
Whenever RevenueCat sends an event to OneSignal, we'll send a subscription_status
user attribute with any applicable changes, using one of the following values:
Status | Description |
---|---|
active | The customer has an active, paid subscription which is set to renew at their next renewal date. |
intro | The customer has an active, paid subscription through a paid introductory offer. |
cancelled | The customer has a paid subscription which is set to expire at their next renewal date. |
grace_period | The customer has a paid subscription which has entered a grace period after failing to renew successfully. |
trial | The customer is in a trial period which is set to convert to paid at the end of their trial period. |
cancelled_trial | The customer is in a trial period which is set to expire at the end of their trial period. |
grace_period_trial | The customer was in a trial period and has now entered a grace period after failing to renew successfully. |
expired | The customer's subscription has expired. |
promotional | The customer has access to an entitlement through a RevenueCat Granted Entitlement |
expired_promotional | The customer previously had access to an entitlement through a RevenueCat Granted Entitlement that has since expired. |
paused | The customer has a paid subscription which has been paused and is set to resume at some future date. |
For customers with multiple active subscriptions, this attribute will represent the status of only the subscription for which the most recent event occurred.
Please note that since this attribute is set and updated when events are delivered, subscribers with events prior to our release of this attribute (during November 2023) will not have this attribute set until/unless a future event (renewal, cancellation, etc) occurs.