diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index ad928f3ef..48b31b88f 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,4 +1,7 @@
## Motivation / Description
+
## Changes introduced
+
## Linear ticket (if any)
+
## Additional comments
diff --git a/.prettierignore b/.prettierignore
index 19dccfebd..0833adc3e 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -1,6 +1,3 @@
tools
code_blocks
openapi-spec
-# TODO: Reformat. MDX is whitespace sensitive, so it requires making sure all the docs still look good.
-**/*.md
-**/*.mdx
diff --git a/README.md b/README.md
index 285b5f81c..80e448da6 100644
--- a/README.md
+++ b/README.md
@@ -98,19 +98,19 @@ The default sidebar is rendered at the bottom of `sidebars.js`.
- Install dependencies
- ```sh
- $ yarn install
- ```
+ ```sh
+ $ yarn install
+ ```
- Optionally install [typos-cli](https://github.com/crate-ci/typos)
- ```sh
- brew install typos-cli
- ```
+ ```sh
+ brew install typos-cli
+ ```
- See the link for other options.
-
- This is optional, but will enable running it via the pre-commit hook. You can also use the recommended [vscode extension](https://marketplace.visualstudio.com/items?itemName=tekumara.typos-vscode) or let it run via GitHub Actions when you create a PR.
+ See the link for other options.
+
+ This is optional, but will enable running it via the pre-commit hook. You can also use the recommended [vscode extension](https://marketplace.visualstudio.com/items?itemName=tekumara.typos-vscode) or let it run via GitHub Actions when you create a PR.
### Local Development
diff --git a/docs/customers/customer-attributes.mdx b/docs/customers/customer-attributes.mdx
index 135e0efb3..58fedd1e0 100644
--- a/docs/customers/customer-attributes.mdx
+++ b/docs/customers/customer-attributes.mdx
@@ -96,40 +96,40 @@ Attribute keys beginning with `$` are reserved for RevenueCat. The current list
#### General
-| Key | Description |
-| :----------------------- | :----------------------------------------------------------- |
-| `$displayName` | Name that should be used to reference the user |
-| `$apnsTokens` | Apple push notification tokens for the user. |
-| `$fcmTokens` | Google push notification tokens for the user. |
-| `$attConsentStatus` | Apple App Tracking Transparency consent status for the user. |
-| `$clevertapId ` | Clever Tap ID for the user. |
-| `$idfa` | iOS advertising identifier UUID. |
-| `$idfv` | iOS vender identifier UUID. |
-| `$gpsAdId` | The advertising ID that is provided by Google Play services. |
-| `$amazonAdId` | Amazon Advertising ID. |
-| `$adjustId` | The unique Adjust identifier for the user. |
-| `$amplitudeDeviceId` | The Amplitude Device ID. |
-| `$amplitudeUserId` | The Amplitude User ID. |
-| `$appsflyerId` | Appsflyer Id. The unique Appsflyer identifier for the user. |
-| `$brazeAliasName` | The Braze 'alias_name' in User Alias Object. |
-| `$brazeAliasLabel` | The Braze 'alias_label' in User Alias Object. |
-| `$clevertapId` | The CleverTap ID for the user. |
-| `$fbAnonId` | The Facebook Anonymous ID for the user. |
-| `$attConsentStatus` | Apple App Tracking Transparency consent status for the user. |
-| `$mparticleId` | The unique mParticle user identifier (mpid). |
-| `$onesignalId` | The OneSignal Player Id for the user. |
-| `$airshipChannelId` | The Airship channel ID for the user. |
-| `$iterableUserId` | The Iterable ID for the user. |
-| `$iterableCampaignId` | The Iterable campaign ID. |
-| `$iterableTemplateId` | The Iterable template ID. |
-| `$firebaseAppInstanceId` | The Firebase instance identifier. |
-| `$mixpanelDistinctId` | The Mixpanel user identifier. |
-| `$kochavaDeviceId` | The unique Kochava device identifier. |
-| `$ip` | The IP address of the device. |
-| `$email` | Email address for the user. |
-| `$phoneNumber` | Phone number for the user. |
-| `$posthogUserId` | The PostHog User ID |
-| `$deviceVersion` | Device, platform and version information. |
+| Key | Description |
+| :------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `$displayName` | Name that should be used to reference the user |
+| `$apnsTokens` | Apple push notification tokens for the user. |
+| `$fcmTokens` | Google push notification tokens for the user. |
+| `$attConsentStatus` | Apple App Tracking Transparency consent status for the user. |
+| `$clevertapId ` | Clever Tap ID for the user. |
+| `$idfa` | iOS advertising identifier UUID. |
+| `$idfv` | iOS vender identifier UUID. |
+| `$gpsAdId` | The advertising ID that is provided by Google Play services. |
+| `$amazonAdId` | Amazon Advertising ID. |
+| `$adjustId` | The unique Adjust identifier for the user. |
+| `$amplitudeDeviceId` | The Amplitude Device ID. |
+| `$amplitudeUserId` | The Amplitude User ID. |
+| `$appsflyerId` | Appsflyer Id. The unique Appsflyer identifier for the user. |
+| `$brazeAliasName` | The Braze 'alias_name' in User Alias Object. |
+| `$brazeAliasLabel` | The Braze 'alias_label' in User Alias Object. |
+| `$clevertapId` | The CleverTap ID for the user. |
+| `$fbAnonId` | The Facebook Anonymous ID for the user. |
+| `$attConsentStatus` | Apple App Tracking Transparency consent status for the user. |
+| `$mparticleId` | The unique mParticle user identifier (mpid). |
+| `$onesignalId` | The OneSignal Player Id for the user. |
+| `$airshipChannelId` | The Airship channel ID for the user. |
+| `$iterableUserId` | The Iterable ID for the user. |
+| `$iterableCampaignId` | The Iterable campaign ID. |
+| `$iterableTemplateId` | The Iterable template ID. |
+| `$firebaseAppInstanceId` | The Firebase instance identifier. |
+| `$mixpanelDistinctId` | The Mixpanel user identifier. |
+| `$kochavaDeviceId` | The unique Kochava device identifier. |
+| `$ip` | The IP address of the device. |
+| `$email` | Email address for the user. |
+| `$phoneNumber` | Phone number for the user. |
+| `$posthogUserId` | The PostHog User ID |
+| `$deviceVersion` | Device, platform and version information. |
| `$appleRefundHandlingPreference` | The [App Store refund preference](/platform-resources/apple-platform-resources/handling-refund-requests#overriding-refund-preference) to override for the user. |
:::warning attConsentStatus is populated regardless of requesting any permission
diff --git a/docs/customers/customer-info.mdx b/docs/customers/customer-info.mdx
index 9925d487e..11ad27817 100644
--- a/docs/customers/customer-info.mdx
+++ b/docs/customers/customer-info.mdx
@@ -9,7 +9,7 @@ RevenueCat makes it easy to determine subscription status and more with the Reve
## Getting subscription status via the SDK
-The CustomerInfo object contains all of the purchase and subscription data available about a customer.
+The CustomerInfo object contains all of the purchase and subscription data available about a customer.
This object is updated whenever a purchase or restore occurs and periodically throughout the lifecycle of your app. The latest information can always be retrieved by calling `getCustomerInfo()`:
@@ -24,8 +24,6 @@ import contentCapacitor from "!!raw-loader!@site/code_blocks/customers/customer-
import content8 from "!!raw-loader!@site/code_blocks/customers/customer-info_8.cs";
import rcBillingContent from "!!raw-loader!@site/code_blocks/_projects/rc-billing/rc-billing-doc-snippets.ts";
-
-
-
It's safe to call `getCustomerInfo()` frequently throughout your app. Since the SDK updates and caches the latest CustomerInfo when the app becomes active, the completion block won't need to make a network request in most cases.
### Checking If A User Is Subscribed
@@ -85,41 +82,48 @@ import content14 from "!!raw-loader!@site/code_blocks/customers/customer-info_14
import content15 from "!!raw-loader!@site/code_blocks/customers/customer-info_15.js";
import content16 from "!!raw-loader!@site/code_blocks/customers/customer-info_16.cs";
-
+ {
+ type: "ts",
+ content: rcBillingContent,
+ name: "Web (JS/TS)",
+ region: "Check for specific entitlement",
+ },
+ ]}
+/>
If your app has multiple entitlements, you might also want to check if the customer has any active entitlements:
@@ -132,42 +136,48 @@ import content22 from "!!raw-loader!@site/code_blocks/customers/customer-info_22
import content23 from "!!raw-loader!@site/code_blocks/customers/customer-info_23.js";
import content24 from "!!raw-loader!@site/code_blocks/customers/customer-info_24.cs";
-
-
+ {
+ type: "ts",
+ content: rcBillingContent,
+ name: "Web (JS/TS)",
+ region: "Check for any entitlement",
+ },
+ ]}
+/>
It's important to note that CustomerInfo will be empty if no purchases have been made and no transactions have been synced. This means that entitlements may not exist in CustomerInfo even if they have been set up in the RevenueCat dashboard.
@@ -181,7 +191,7 @@ See our [Restoring Purchases](/getting-started/restoring-purchases) guide for mo
### Cache
-The SDK caches the user's subscription information to reduce your app's reliance on the network.
+The SDK caches the user's subscription information to reduce your app's reliance on the network.
Users who unlock entitlements will be able to access them even without an internet connection. The SDK will update the cache if it's older than 5 minutes, but only if you call `getCustomerInfo()`, make a purchase, or restore purchases, so it's a good idea to call `getCustomerInfo()` any time a user accesses premium content.
@@ -204,49 +214,51 @@ import contentCapacitor2 from "!!raw-loader!@site/code_blocks/customers/customer
import content32 from "!!raw-loader!@site/code_blocks/customers/customer-info_32.cs";
import contentKmp from "!!raw-loader!@site/code_blocks/customers/customer-info_kmp_1.kts";
-
+ ]}
+/>
### Reference
@@ -266,14 +278,13 @@ The `CustomerInfo` object gives you access to the following information about a
| All Purchased Product Identifiers | An array of product identifiers purchased by the user regardless of expiration. |
| All Expiration Dates By Product | A map of product identifiers to expiration dates. |
| All Purchase Dates By Product | A map of product identifiers to purchase dates. |
-| Non Subscription Transactions | A list of all the non-subscription transactions purchased by the user. |
+| Non Subscription Transactions | A list of all the non-subscription transactions purchased by the user. |
| Latest Expiration Date | The latest expiration date of all purchased products. |
| Active Subscriptions | An array of subscription product identifiers that are active. You should be using [entitlement](/getting-started/entitlements) though. |
| Entitlements | `EntitlementInfo` objects that contain information about the user's entitlements, such as subscription state. [See more below](/customers/customer-info#get-entitlement-information). |
-
EntitlementInfo Reference
@@ -298,19 +309,20 @@ The `EntitlementInfo` object gives you access to all of the information about th
-
## Getting subscription status via the REST API
-If you need to get a user's subscription status from outside of the _Purchases SDK_, for example, from your own backend, you should use the REST API. You can read the full API reference [here](https://docs.revenuecat.com/reference).
+If you need to get a user's subscription status from outside of the _Purchases SDK_, for example, from your own backend, you should use the REST API. You can read the full API reference [here](https://docs.revenuecat.com/reference).
import content33 from "!!raw-loader!@site/code_blocks/customers/customer-info_33.curl";
-
+ ]}
+/>
## Handling Refunds
@@ -320,11 +332,12 @@ RevenueCat can handle refunds across all platforms for both subscription and non
In the very uncommon case that RevenueCat servers don't respond as expected, the SDK is prepared to verify Apple/Google/Amazon's purchases on the device itself and grant entitlements temporarily. This allows your customers to have an almost seamless experience in this unlikely scenario, improving even more on our reliability. This happens automatically, so you don't need to do anything, the entitlements will appear in the `CustomerInfo`.
-Offline Entitlements is automatically enabled when our SDK attempts to reach our servers and they can't respond. It automatically is disabled when our servers respond successful http responses again.
+Offline Entitlements is automatically enabled when our SDK attempts to reach our servers and they can't respond. It automatically is disabled when our servers respond successful http responses again.
-In order to do this, the SDK caches the relationships between products and entitlements you have setup in your RevenueCat dashboard. Then, when it tries to post a purchase to RevenueCat's servers, and these respond with an error, we will use the purchases from the stores and these relationships to grant entitlements.
+In order to do this, the SDK caches the relationships between products and entitlements you have setup in your RevenueCat dashboard. Then, when it tries to post a purchase to RevenueCat's servers, and these respond with an error, we will use the purchases from the stores and these relationships to grant entitlements.
### Some things to note:
+
- No information is lost when Offline Entitlements are active. All purchases are recorded and will be processed by our servers automatically once they are back online, with no action needed from you or your users.
- The data for these purchases won't appear in our RevenueCat graphs and webhooks until it's successfully pushed.
- Purchases won't be recognized cross-platform while using Offline Entitlements.
diff --git a/docs/customers/trusted-entitlements.mdx b/docs/customers/trusted-entitlements.mdx
index 7943f1303..0167a15f1 100644
--- a/docs/customers/trusted-entitlements.mdx
+++ b/docs/customers/trusted-entitlements.mdx
@@ -31,38 +31,38 @@ import content5 from "!!raw-loader!@site/code_blocks/customers/trusted-entitleme
import content6 from "!!raw-loader!@site/code_blocks/customers/trusted-entitlements-capacitor.ts";
import content7 from "!!raw-loader!@site/code_blocks/customers/trusted-entitlements.cs";
-
-
+ ]}
+/>
### Verification
@@ -76,38 +76,38 @@ import content12 from "!!raw-loader!@site/code_blocks/customers/verification-res
import content13 from "!!raw-loader!@site/code_blocks/customers/verification-result-capacitor.ts";
import content14 from "!!raw-loader!@site/code_blocks/customers/verification-result.cs";
-
-
+ ]}
+/>
Additionally, verification errors are always forwarded to `Purchases.errorHandler`.
diff --git a/docs/customers/user-ids.mdx b/docs/customers/user-ids.mdx
index 390c7287d..5ff18ae95 100644
--- a/docs/customers/user-ids.mdx
+++ b/docs/customers/user-ids.mdx
@@ -11,7 +11,7 @@ For an overview of what a customer is in RevenueCat, see [What is a Customer?](/
## Anonymous App User IDs
-By default, if you don't provide an App User ID when configuring the Purchases SDK, RevenueCat will generate a new random App User ID (prefixed with `$RCAnonymousID:`) for you, and will cache it on the device.
+By default, if you don't provide an App User ID when configuring the Purchases SDK, RevenueCat will generate a new random App User ID (prefixed with `$RCAnonymousID:`) for you, and will cache it on the device.
In the event that the user deletes and reinstalls the app, the cache will be cleared and a new random anonymous App User ID will be generated.
@@ -28,50 +28,51 @@ import contentCapacitor1 from "!!raw-loader!@site/code_blocks/customers/user-ids
import content8 from "!!raw-loader!@site/code_blocks/customers/user-ids_unity.cs";
import contentKmpAnon from "!!raw-loader!@site/code_blocks/customers/user-ids_kmp_anon.kts";
-
+ ]}
+/>
## Custom App User IDs
@@ -104,51 +105,51 @@ import contentCapacitor2 from "!!raw-loader!@site/code_blocks/customers/user-ids
import content16 from "!!raw-loader!@site/code_blocks/customers/user-ids_16.cs";
import contentKmp from "!!raw-loader!@site/code_blocks/customers/user-ids_kmp.kts";
-
-
+ ]}
+/>
Often times, you may not have your own App User IDs until later in the application lifecycle. In these cases, you can pass the App User ID later through the `.logIn()` method.
@@ -156,7 +157,7 @@ Often times, you may not have your own App User IDs until later in the applicati
If your app doesn't receive its own App User ID until later in its lifecycle, you can set (or change) the App User ID at any time by calling `.logIn()`. If the logged in identity does not already exist in RevenueCat, it will be created automatically.
-This flow will generate an anonymous App User ID for the user first, then may (*see below*) alias the anonymous App User ID to the provided custom App User ID. In this case if you integrated webhooks, `original_app_user_id` will be the anonymous id and `app_user_id` will be the provided id.
+This flow will generate an anonymous App User ID for the user first, then may (_see below_) alias the anonymous App User ID to the provided custom App User ID. In this case if you integrated webhooks, `original_app_user_id` will be the anonymous id and `app_user_id` will be the provided id.
import content17 from "!!raw-loader!@site/code_blocks/customers/user-ids_17.swift";
import content18 from "!!raw-loader!@site/code_blocks/customers/user-ids_18.m";
@@ -169,50 +170,51 @@ import contentCapacitor3 from "!!raw-loader!@site/code_blocks/customers/user-ids
import content24 from "!!raw-loader!@site/code_blocks/customers/user-ids_24.cs";
import contentKmpLogin from "!!raw-loader!@site/code_blocks/customers/user-ids_kmp_login.kts";
-
+ ]}
+/>
`logIn()` method alias behavior
@@ -220,11 +222,11 @@ import contentKmpLogin from "!!raw-loader!@site/code_blocks/customers/user-ids_k
When logging in from an Anonymous ID to a provided custom App User ID, RevenueCat will decide whether the identities should be merged (aliased) into the same CustomerInfo object or not. This is decided depending on whether the provided custom App User ID already exists, and if it does exist whether it has an anonymous alias already.
| Current App User ID | Provided Custom App User ID already exists? | Provided Custom App User ID already has an anonymous alias? | Result |
-| :------------------ | :------------------------------------------ | :----------------------------------------------- | :--------------------------------------------------------- |
-| Anonymous | No | N/A | Anonymous ID and Provided ID have CustomerInfo merged. |
-| Anonymous | Yes | No | Anonymous ID and Provided ID have CustomerInfo merged. |
-| Anonymous | Yes | Yes | CustomerInfo transfers to Provided ID, no aliases created. |
-| Non-anonymous | Any | Any | CustomerInfo transfers to Provided ID, no aliases created. |
+| :------------------ | :------------------------------------------ | :---------------------------------------------------------- | :--------------------------------------------------------- |
+| Anonymous | No | N/A | Anonymous ID and Provided ID have CustomerInfo merged. |
+| Anonymous | Yes | No | Anonymous ID and Provided ID have CustomerInfo merged. |
+| Anonymous | Yes | Yes | CustomerInfo transfers to Provided ID, no aliases created. |
+| Non-anonymous | Any | Any | CustomerInfo transfers to Provided ID, no aliases created. |
@@ -250,15 +252,15 @@ You can retrieve the currently identified App User ID via the `Purchases.shared.
## Aliases
-If you use a combination of anonymous and custom App User IDs, it’s expected that Customers may be merged over time due to various actions they perform within the app, like [logins](/customers/user-ids#login-method-alias-behavior) or [restores](/getting-started/restoring-purchases). Scenarios explaining when merges occur are covered in more detail below, and will depend on the [restore behavior](/getting-started/restoring-purchases#restore-behavior) you select for your project.
+If you use a combination of anonymous and custom App User IDs, it’s expected that Customers may be merged over time due to various actions they perform within the app, like [logins](/customers/user-ids#login-method-alias-behavior) or [restores](/getting-started/restoring-purchases). Scenarios explaining when merges occur are covered in more detail below, and will depend on the [restore behavior](/getting-started/restoring-purchases#restore-behavior) you select for your project.
-When a merge of customers occurs, there will be only one App User ID within the `original_app_user_id` field. If you’re listening to [Webhooks](/integrations/webhooks), the other App User IDs associated with the customer will be within an array in the `aliases` field.
+When a merge of customers occurs, there will be only one App User ID within the `original_app_user_id` field. If you’re listening to [Webhooks](/integrations/webhooks), the other App User IDs associated with the customer will be within an array in the `aliases` field.
When referenced via the [SDK](/getting-started/configuring-sdk) or [API](https://www.revenuecat.com/reference/basic), any merged App User IDs will all be treated as the same “customer”. Looking up any of the merged App User IDs in RevenueCat will return the same `CustomerInfo`, customer history, customer attributes, subscription status, etc.
## Tips for Setting Custom App User IDs
-**ℹ️ Every app user ID must be unique per user.**
+**ℹ️ Every app user ID must be unique per user.**
If you don't have your own user IDs for some of your users, you should not pass any value for the App User ID on configuration, which will then rely on the anonymous IDs created by RevenueCat.
@@ -284,7 +286,7 @@ You should never hardcode a string as an App User ID, since every install will b
## Blocked App User IDs
-Certain App User IDs are blocked in RevenueCat. This is by design to help developers that may be unintentionally passing non-unique strings as user identifiers.
+Certain App User IDs are blocked in RevenueCat. This is by design to help developers that may be unintentionally passing non-unique strings as user identifiers.
The current block-list is: `'no_user'`, `'null'`, `'none'`, `'nil'`, `'(null)'`, `'NaN`, `'\\x00'`(`NULL` character), `''`(empty string), `'unidentified'`, `'undefined'`, `'unknown'`, `'anonymous'`, `'guest'`, `'-1'`, `'0'`, `'[]'`, `'{}'`, `'[object Object]'` and any App User IDs containing the character `/`.
@@ -293,9 +295,9 @@ The current block-list is: `'no_user'`, `'null'`, `'none'`, `'nil'`, `'(null)'`,
How to force only using Custom App User IDs
-To only use custom App User IDs, you must take care not to generate any anonymous App User IDs in the SDK.
+To only use custom App User IDs, you must take care not to generate any anonymous App User IDs in the SDK.
-Anonymous App User IDs are generated when the SDK is configured without a provided custom App User ID, and are also created on `logOut()` as mentioned above. Many apps use a combination of anonymous App User IDs and their own custom App User IDs via an authentication system to provide flexibility in their user purchase flows. However, some applications are intended only to be used while using a known App User ID, without anonymous users at all.
+Anonymous App User IDs are generated when the SDK is configured without a provided custom App User ID, and are also created on `logOut()` as mentioned above. Many apps use a combination of anonymous App User IDs and their own custom App User IDs via an authentication system to provide flexibility in their user purchase flows. However, some applications are intended only to be used while using a known App User ID, without anonymous users at all.
Some limits of anonymous IDs include added difficulty in personalization of user experiences, optimization of monetization strategies, and not being able to share subscriptions across platforms. Depending on the application's [transfer behavior](/getting-started/restoring-purchases), a provided user's subscription may be transferred to an anonymous ID - which can only be brought back through a [restore](/getting-started/restoring-purchases) on the original purchase platform.
diff --git a/docs/dashboard-and-metrics/anomaly-detection-notifications.md b/docs/dashboard-and-metrics/anomaly-detection-notifications.md
index 35abbb95b..12fb03302 100644
--- a/docs/dashboard-and-metrics/anomaly-detection-notifications.md
+++ b/docs/dashboard-and-metrics/anomaly-detection-notifications.md
@@ -34,13 +34,13 @@ Currently, you can only set one alert (Custom Threshold or Auto Detection) per p
## FAQs
-| Question | Answer |
-| --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| Can I configure multiple alerts (Custom Threshold and Auto Detection) for the same project? | Not at this time. Currently, you can only choose one type of alert per project. However, this is a feature we are planning to enhance in the future. |
-| When are the alerts sent? | Alerts are sent twice daily after anomaly detection checks are performed, and notifications are delivered to your registered email address. |
-| How does the machine learning algorithm in Auto Detection work? | The algorithm uses time series forecasting to account for weekly and yearly seasonalities, identifying unexpected deviations or outliers in revenue data. |
-| Can I receive notifications for multiple projects? | Yes, you can select multiple projects to monitor for anomalies from the **Notifications** section of your account settings. |
-| How do I know if an alert was triggered by a false positive? | You can review your revenue trends on the RevenueCat Dashboard to validate alerts. If you encounter consistent false positives, reach out through [Support](https://app.revenuecat.com/settings/support). |
+| Question | Answer |
+| ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Can I configure multiple alerts (Custom Threshold and Auto Detection) for the same project? | Not at this time. Currently, you can only choose one type of alert per project. However, this is a feature we are planning to enhance in the future. |
+| When are the alerts sent? | Alerts are sent twice daily after anomaly detection checks are performed, and notifications are delivered to your registered email address. |
+| How does the machine learning algorithm in Auto Detection work? | The algorithm uses time series forecasting to account for weekly and yearly seasonalities, identifying unexpected deviations or outliers in revenue data. |
+| Can I receive notifications for multiple projects? | Yes, you can select multiple projects to monitor for anomalies from the **Notifications** section of your account settings. |
+| How do I know if an alert was triggered by a false positive? | You can review your revenue trends on the RevenueCat Dashboard to validate alerts. If you encounter consistent false positives, reach out through [Support](https://app.revenuecat.com/settings/support). |
---
@@ -49,11 +49,11 @@ Currently, you can only set one alert (Custom Threshold or Auto Detection) per p
Anomaly Detection is currently in beta, and there are a few limitations to be aware of:
- Fixed check frequency: Anomalies are evaluated twice daily, meaning sudden changes between checks may not trigger an immediate alert.
-- False positives and false negatives:
- - A false positive means you might receive an alert for a revenue change that isn't actually an anomaly (e.g., expected fluctuations due to promotions or seasonality).
- - A false negative means a real anomaly might not be detected, especially if it's subtle or follows an unusual but valid pattern.
- - We are currently tweaking the alert thresholds to improve accuracy and reduce unnecessary alerts.
+- False positives and false negatives:
+ - A false positive means you might receive an alert for a revenue change that isn't actually an anomaly (e.g., expected fluctuations due to promotions or seasonality).
+ - A false negative means a real anomaly might not be detected, especially if it's subtle or follows an unusual but valid pattern.
+ - We are currently tweaking the alert thresholds to improve accuracy and reduce unnecessary alerts.
We are continuously improving the model to reduce these cases, but it’s always a good idea to cross-check alerts with your own revenue trends.
-If you notice any issues or have feedback, please reach out to [RevenueCat Support](https://app.revenuecat.com/settings/support).
\ No newline at end of file
+If you notice any issues or have feedback, please reach out to [RevenueCat Support](https://app.revenuecat.com/settings/support).
diff --git a/docs/dashboard-and-metrics/customer-history/active-entitlements.md b/docs/dashboard-and-metrics/customer-history/active-entitlements.md
index 8057048dd..965d7de46 100644
--- a/docs/dashboard-and-metrics/customer-history/active-entitlements.md
+++ b/docs/dashboard-and-metrics/customer-history/active-entitlements.md
@@ -54,7 +54,7 @@ Transferring entitlements works with the block-restore behavior
## Refunding and Cancelling Purchases
-Google Play and RevenueCat Billing purchases can be refunded directly through the RevenueCat dashboard. Granting a refund will immediately expire the subscription and remove any entitlement access. By refunding directly through RevenueCat you can ensure that refunds are accounted for immediately in all charts and integrations.
+Google Play and RevenueCat Billing purchases can be refunded directly through the RevenueCat dashboard. Granting a refund will immediately expire the subscription and remove any entitlement access. By refunding directly through RevenueCat you can ensure that refunds are accounted for immediately in all charts and integrations.
RevenueCat Billing subscriptions and Google Play subscriptions in the trial period can also be cancelled, which means that they will not renew at the next expiration date.
diff --git a/docs/dashboard-and-metrics/customer-history/manage-users.md b/docs/dashboard-and-metrics/customer-history/manage-users.md
index 8bfe42b31..bf5c09257 100644
--- a/docs/dashboard-and-metrics/customer-history/manage-users.md
+++ b/docs/dashboard-and-metrics/customer-history/manage-users.md
@@ -15,8 +15,10 @@ Deleting a user with live purchases may have downstream effects on charts and re
:::
:::info Deleting a user from RevenueCat won't cancel mobile or Stripe Web Payments subscriptions
+
- You can cancel a user's Google Play subscription before deleting them via our [API](https://docs.revenuecat.com/reference#revoke-a-google-subscription).
- It's not possible for you to cancel a user's Apple subscription; this is a limitation of the App Store.
- Stripe Web Payments subscriptions are not canceled automatically, and should be canceled directly in the [Stripe Dashboard](https://support.stripe.com/questions/how-to-pause-payment-collection-or-cancel-subscriptions).
- RevenueCat Billing (web) subscriptions are always canceled immediately when the user is deleted.
+
:::
diff --git a/docs/dashboard-and-metrics/supporting-your-customers.md b/docs/dashboard-and-metrics/supporting-your-customers.md
index a31728964..7366fef1e 100644
--- a/docs/dashboard-and-metrics/supporting-your-customers.md
+++ b/docs/dashboard-and-metrics/supporting-your-customers.md
@@ -10,14 +10,15 @@ As the central location for all your subscription data, RevenueCat is a power to
## Inviting your customer support team to RevenueCat
+
In order for your customer support team to take advantage of RevenueCat’s features, they first need access to RevenueCat!
The “Support” role was developed specifically with this use case in mind. Collaborators with this permission can manage individual customers, including Customer Timelines, grant Promotional Entitlements, issue refunds, and delete customers. However, they’re not able to view any financial data or access most app settings.
Of course, you can also give your support team one of the other RevenueCat roles if you wish them to have access to more data and functionality. See how to invite a collaborator and learn about other permission options here.
-
## Looking up customers in RevenueCat
+
How you look up customers will depend partially on your implementation and what data you’re passing into RevenueCat.
All customers can be found by searching for an App User ID, Transaction ID, or Order ID (iOS only). In order to find a customer via their email, you must be passing email as a custom attribute to RevenueCat.
@@ -26,24 +27,25 @@ To find a customer, visit the Customer tab in the RevenueCat dashboard and look
To learn more about finding individual customers visit [Find an Individual Customer](/dashboard-and-metrics/customer-lists#find-an-individual-customer).
-
## Reviewing a customer’s subscription history
+
RevenueCat knows a lot about your customers from when they were first seen using the app, to when they made their first purchase, and even to when their subscription most recently renewed.
All of these events can be found in the Customer History on the Customer’s profile. Learn more about the specific event types and the additional details they contain from our [Customer History](/dashboard-and-metrics/customer-history) documentation.
-
## Managing customer subscriptions
+
Not only can you see information about your customer’s subscriptions in the RevenueCat dashboard, but you can also perform certain actions (without ever needing to log into the stores).
Here are some of the ways you can make changes to a customer’s subscription from RevenueCat:
-* _Issue a refund_ - Google Play purchases and purchases made through RevenueCat Billing can be refunded directly through the RevenueCat dashboard. To refund a purchase, find the transaction event in the customer history and click “Refund” in the upper right corner. To learn more about how refunds work for Apple, Amazon, and Stripe, visit [Handling Refunds](/subscription-guidance/refunds).
-* _Cancel a subscription_ - If a subscription was purchased through RevenueCat Billing, you can also cancel that purchase from the RevenueCat dashboard. To cancel a subscription, click on the "..." menu on the subscription in the "Entitlements" card of the customer profile and then select "Cancel subscription". Learn more about managing subscriptions with RevenueCat Billing [here](/web/revenuecat-billing/managing-customer-subscriptions).
-* _Transfer a subscription_ - In some cases you may want to manually transfer a subscription to a different user. The “Transfer” functionality can be found in the upper right corner of the customer profile page in the Entitlements section (details [here](/dashboard-and-metrics/customer-history/active-entitlements#transferring-entitlements) ). Please note that when you transfer a subscription you are not changing the underlying App Store account (for instance, the Apple Account) that owns the subscription. Because of this, the subscription may automatically be transferred again when the user restores purchases. The exact behavior will depend on your RevenueCat Project’s settings for [restoring purchases](/getting-started/restoring-purchases#transferring-purchases-seen-on-multiple-app-user-ids).
-* _Grant a promotional entitlement_ - With promotional entitlements you can also use RevenueCat to give users access to your products without involving any third party platform. For example, if you want to give a VIP user or a fellow employee free access to your app, you could grant them a promotional entitlement. Keep in mind this is purely a RevenueCat concept and therefore doesn’t change anything about a subscription they may have through the store. Learn more at our [Granted Entitlements](/dashboard-and-metrics/customer-history/promotionals) documentation.
+- _Issue a refund_ - Google Play purchases and purchases made through RevenueCat Billing can be refunded directly through the RevenueCat dashboard. To refund a purchase, find the transaction event in the customer history and click “Refund” in the upper right corner. To learn more about how refunds work for Apple, Amazon, and Stripe, visit [Handling Refunds](/subscription-guidance/refunds).
+- _Cancel a subscription_ - If a subscription was purchased through RevenueCat Billing, you can also cancel that purchase from the RevenueCat dashboard. To cancel a subscription, click on the "..." menu on the subscription in the "Entitlements" card of the customer profile and then select "Cancel subscription". Learn more about managing subscriptions with RevenueCat Billing [here](/web/revenuecat-billing/managing-customer-subscriptions).
+- _Transfer a subscription_ - In some cases you may want to manually transfer a subscription to a different user. The “Transfer” functionality can be found in the upper right corner of the customer profile page in the Entitlements section (details [here](/dashboard-and-metrics/customer-history/active-entitlements#transferring-entitlements) ). Please note that when you transfer a subscription you are not changing the underlying App Store account (for instance, the Apple Account) that owns the subscription. Because of this, the subscription may automatically be transferred again when the user restores purchases. The exact behavior will depend on your RevenueCat Project’s settings for [restoring purchases](/getting-started/restoring-purchases#transferring-purchases-seen-on-multiple-app-user-ids).
+- _Grant a promotional entitlement_ - With promotional entitlements you can also use RevenueCat to give users access to your products without involving any third party platform. For example, if you want to give a VIP user or a fellow employee free access to your app, you could grant them a promotional entitlement. Keep in mind this is purely a RevenueCat concept and therefore doesn’t change anything about a subscription they may have through the store. Learn more at our [Granted Entitlements](/dashboard-and-metrics/customer-history/promotionals) documentation.
### More Popular Features & FAQs
+
1. [Customer History](/dashboard-and-metrics/customer-history)
2. [Promotionals](/dashboard-and-metrics/customer-history/promotionals)
3. [Customer Lists](/dashboard-and-metrics/customer-lists)
diff --git a/docs/dashboard-and-metrics/taxes-and-commissions.md b/docs/dashboard-and-metrics/taxes-and-commissions.md
index 145f19eb8..d0e3ad0f5 100644
--- a/docs/dashboard-and-metrics/taxes-and-commissions.md
+++ b/docs/dashboard-and-metrics/taxes-and-commissions.md
@@ -46,10 +46,12 @@ We do not take your location as a developer into account when estimating taxes t
### Calculating taxes for the mobile stores
The App Store, Google Play Store, and Amazon Appstore stores appear to charge both [Value-Added Tax]() (VAT) and the [digital services taxes](https://taxfoundation.org/digital-tax-europe-2020/) (DST) that have been put in place by several countries. However, they do not apply identical tax rates for each country, so we:
+
1. Find the proceeds quoted by the store for a given price in a given country
2. Use that to determine the tax rate being charged to yield proceeds
To then calculate the portion of a given transaction that was deducted for taxes, we:
+
1. Use the found tax rate to determine what was deducted from the customer price due to taxes: `price / (1 + [tax rate]) = [amount deducted for taxes]`
2. Divide the amount deducted due to taxes from the customer price to get the `tax_percentage` that's provided in events, used to calculate Charts, etc: `[amount deducted for taxes] / price = tax_percentage`
diff --git a/docs/getting-started/configuring-sdk.mdx b/docs/getting-started/configuring-sdk.mdx
index 2f4d744cf..682e44387 100644
--- a/docs/getting-started/configuring-sdk.mdx
+++ b/docs/getting-started/configuring-sdk.mdx
@@ -3,6 +3,7 @@ title: Configuring the SDK
slug: configuring-sdk
hidden: false
---
+
If this is your first time integrating RevenueCat into your app, we recommend following our [Quickstart](/getting-started/quickstart) guide.
:::info Using an older SDK (v3.x)
@@ -42,20 +43,27 @@ import cordovaChinaWorkaround from "!!raw-loader!@site/code_blocks/getting-start
import capacitorChinaWorkaround from "!!raw-loader!@site/code_blocks/getting-started/configuring-sdk_8_capacitor_china_url.ts";
import unityChinaWorkaround from "!!raw-loader!@site/code_blocks/getting-started/configuring-sdk_9_china_url.cs";
-
+
## Enabling Debug Logs
@@ -76,7 +84,7 @@ The SDK allows additional configuration on first setup:
### Proxies & configuration for users in Mainland China
-We’ve received reports of our API being blocked in mainland China.
+We’ve received reports of our API being blocked in mainland China.
While we work on a long-term solution, if your app has a significant user base in this region, set the `proxyURL` property to `https://api.rc-backup.com/` before initializing the RevenueCat SDK. Ensure this configuration occurs prior to SDK setup to prevent connection issues for users in mainland China.
@@ -84,19 +92,20 @@ While we work on a long-term solution, if your app has a significant user base i
If you have your own proxy server and already use the `proxyURL` API, you don't need any further configuration.
:::
-
-
+
### iOS
@@ -117,13 +126,14 @@ Called whenever _Purchases_ receives an updated `CustomerInfo` object. This may
#### Handling Promoted Purchases
Implement the following delegate method to handle promoted purchases:
+
```
purchases:readyForPromotedProduct
```
-Called when a user initiates a promoted in-app purchase from the App Store. If your app is able to handle a purchase at the current time, run the `defermentBlock` in this method.
+Called when a user initiates a promoted in-app purchase from the App Store. If your app is able to handle a purchase at the current time, run the `defermentBlock` in this method.
-If the app is not in a state to make a purchase: cache the `defermentBlock`, then call the `defermentBlock` when the app is ready to make the promoted purchase.
+If the app is not in a state to make a purchase: cache the `defermentBlock`, then call the `defermentBlock` when the app is ready to make the promoted purchase.
If the purchase should never be made, you don't need to ever call the `defermentBlock` and _Purchases_ will not proceed with promoted purchases.
diff --git a/docs/getting-started/configuring-sdk/ios-app-extensions.mdx b/docs/getting-started/configuring-sdk/ios-app-extensions.mdx
index 063d3d07d..0425b1466 100644
--- a/docs/getting-started/configuring-sdk/ios-app-extensions.mdx
+++ b/docs/getting-started/configuring-sdk/ios-app-extensions.mdx
@@ -3,6 +3,7 @@ title: iOS App Extensions
slug: ios-app-extensions
hidden: false
---
+
[App Extensions](https://developer.apple.com/app-extensions/) in iOS are an important component of the iOS ecosystem that are supported by RevenueCat. The most popular use of App Extensions for subscription apps are Today Widgets and iMessage apps.
:::warning Purchases aren't allowed on extensions
@@ -17,8 +18,10 @@ After you enable app groups, you will be able to access a user's active subscrip
import iosAppExtensionsSwiftContent from "!!raw-loader!@site/code_blocks/getting-started/configuring-sdk/ios-app-extensions_1.swift";
-
+
Now the app extension and parent app can both use the a shared UserDefaults suite.
diff --git a/docs/getting-started/entitlements.mdx b/docs/getting-started/entitlements.mdx
index 86ce6d8e1..d7093777f 100644
--- a/docs/getting-started/entitlements.mdx
+++ b/docs/getting-started/entitlements.mdx
@@ -1,6 +1,7 @@
---
title: Entitlements
---
+
{/* I'm including this, because this doc historically had a lot of information on product configuration, and not just entitlements. this is to keep some kind of continuity for legacy links to this page */}
:::info Looking for details on product configuration?
diff --git a/docs/getting-started/entitlements/roku-products.md b/docs/getting-started/entitlements/roku-products.md
index 407ba545a..964d08f58 100644
--- a/docs/getting-started/entitlements/roku-products.md
+++ b/docs/getting-started/entitlements/roku-products.md
@@ -4,15 +4,17 @@ slug: roku-products
excerpt: Setting up your in-app purchases in Roku
hidden: false
---
+
:::warning Beta Feature
RevenueCat's Roku support is currently in beta.
:::
-To set up in-channel products for Roku, start by logging into the [Roku dashboard](https://developer.roku.com/dev/landing).
+To set up in-channel products for Roku, start by logging into the [Roku dashboard](https://developer.roku.com/dev/landing).
**This guide assumes basic knowledge of Roku and the Roku dashboard, as well as having a Roku channel set up and ready for products.** For more information, visit Roku's [documentation](https://developer.roku.com/docs/developer-program/getting-started/roku-dev-prog.md).
## Create a new Product
+
This process is going to configure a subscription product, but the steps are similar for creating other products. To configure other types of products, select the appropriate 'Purchase Type'. However, please read our [limitations](/getting-started/installation/roku#beta-limitations) on what we currently support in this beta program.
To create a new in-channel product, click on products in the sidebar of the Roku Developer Dashboard, then click **Add a new product**.
@@ -22,64 +24,69 @@ To create a new in-channel product, click on products in the sidebar of the Roku

### Product basics
+

- **Channels**: From the channels list, select one or more channels where this product will be available for sale. The channels listed in this selection show the channels belonging to the root account.
- **Product category**: Select a product category for the product you are creating.
- - _Video_: Primarily video content, includes music videos.
- - _Audio_: Primarily audio content without accompanying video, such as streaming music services or audio-only podcasts.
- - _Game_: Primarily functions as a game.
- - _App/Utility_: Application or utility. Examples include screensavers, weather apps, etc.
+ - _Video_: Primarily video content, includes music videos.
+ - _Audio_: Primarily audio content without accompanying video, such as streaming music services or audio-only podcasts.
+ - _Game_: Primarily functions as a game.
+ - _App/Utility_: Application or utility. Examples include screensavers, weather apps, etc.
- **Product name**: Enter a 30-character maximum product name in English. The product name will be disaplued to your customers in their purchasing workflow, as well as emails sent by Roku. Roku recommends the following syntax: "channelName - planName".
:::warning
-The product name must clearly identify the service being offered. Product names may not include the name "Roku", text related to a trial or discount offer, or any misleading language.
+The product name must clearly identify the service being offered. Product names may not include the name "Roku", text related to a trial or discount offer, or any misleading language.
:::
- **Localization**: Optionally, you can also provide a localized product name by selecting 'Add product name in another language', selecting a language, and entering the product localized name. Repeat this to create another localized name.
- **Product identifier**: The product identifier is a unique ID that is used for accessing your product in development and syncing with RevenueCat. After you use a Product ID for one product within a Roku Channel Store, it can’t be used again. It helps to be a little organized here from the beginning - we recommend using a consistent naming scheme across all of your product identifiers.
### Product pricing
+

- **Purchase type**: The purchase type list will allow you to select the following types for the product being created:
- - _Monthly subscription_: A product that will auto-renew monthly.
- - _Yearly subscription_: A product that will auto-renew annually.
- - _One-time Purchase_: This product type may only be purchased a single time.
- - _One-time Purchase, Consumable - Quantity_ This is a "packet" of identical items (e.g: number of viewings permitted).
+ - _Monthly subscription_: A product that will auto-renew monthly.
+ - _Yearly subscription_: A product that will auto-renew annually.
+ - _One-time Purchase_: This product type may only be purchased a single time.
+ - _One-time Purchase, Consumable - Quantity_ This is a "packet" of identical items (e.g: number of viewings permitted).
:::warning One-time and consumable product limitations
At the moment, RevenueCat does not support One-time Purchase and One-time Purchase, Consumable - Quantity products
:::
-- **Price tier**: Roku's price tiers enforce a 99 cent or 49 cent pricing tier.
- - One to three-digit tier numbers are used for 99 cent pricing. To calculate, you can subtract 1 cent from the tier to get the corresponding price. For example, Tier 100 is $99.99 (`$100 - $0.01 = $99.99`).
- - Four-digit tier numbers are used for 49 cent pricing. To calculate this, you can add 49 cents to the last two digits in the tier. For example, Tier 1030 is $30.49 (30 is the last 2 digits → `$30 + $0.49 = $30.49`).
+- **Price tier**: Roku's price tiers enforce a 99 cent or 49 cent pricing tier.
+ - One to three-digit tier numbers are used for 99 cent pricing. To calculate, you can subtract 1 cent from the tier to get the corresponding price. For example, Tier 100 is $99.99 (`$100 - $0.01 = $99.99`).
+ - Four-digit tier numbers are used for 49 cent pricing. To calculate this, you can add 49 cents to the last two digits in the tier. For example, Tier 1030 is $30.49 (30 is the last 2 digits → `$30 + $0.49 = $30.49`).
Once you select a price tier, a chart will appear that displays the purchase price, net price, and proceeds for each country the product is available for.
+
- **Purchase price**: Reflects the amount your customer will pay.
- **Net price**: This is the pre-tax price.
- **Your proceeds**: This is the amount you will receive from Roku for the sale of the product.
### Trials and offers
+
Roku subscription products support free trials and discounted offers. Note that the root account must be creating free trials, discounted offers, or limited-time offers for subscriptions.
Under **Base offer**, select one of the following:

-- **Discounted price**: This will provide new customers a discounted introductory price.
- - _Discounted price range_: This is the discounted price you'd like to offer. The discounted price range must be lower than the base price.
- - _Discount duration_: Enter the number of months the discount will be until the customer renews at full price.
+- **Discounted price**: This will provide new customers a discounted introductory price.
+ - _Discounted price range_: This is the discounted price you'd like to offer. The discounted price range must be lower than the base price.
+ - _Discount duration_: Enter the number of months the discount will be until the customer renews at full price.

- **Free trial**: This will provide new customers with a free trial of your product.
- - _Free trial duration_: Enter the number of days or months for the trial
- - Select the unit of time (**Days** or **Months**)
+ - _Free trial duration_: Enter the number of days or months for the trial
+ - Select the unit of time (**Days** or **Months**)
### Ready for sale
-Once the product is ready to be made available to customers for purchase, select the _"Cleared for sale"_ checkbox. After selecting this checkbox, you will be able to [schedule limited-time free trials and discount offers](/getting-started/entitlements/roku-products#scheduling-offers) for the product.
+
+Once the product is ready to be made available to customers for purchase, select the _"Cleared for sale"_ checkbox. After selecting this checkbox, you will be able to [schedule limited-time free trials and discount offers](/getting-started/entitlements/roku-products#scheduling-offers) for the product.

@@ -87,36 +94,42 @@ Once the product is ready to be made available to customers for purchase, select
### Scheduling offers
+
Once your product is cleared for sale, you can schedule limited-time free trials and discount offers on your subscription products.
-Within your product details, you can select 'Schedule offer' > 'Create new offer'.
+Within your product details, you can select 'Schedule offer' > 'Create new offer'.

Please refer to the [Trials and offers](/getting-started/entitlements/roku-products#trials-and-offers) section of this documentation for additional instructions on creating an offer. When scheduling an offer, you must input a **Start date** and **End date**.
Note that a customer can only receive one free trial or discount offer, regardless if it is a scheduled offer or part of your base product. For example, if you have a monthly subscription product with the following offers:
+
- Time-limited offer: Two-month free trial
- Base offer: Three-month 50% discount
When your customer accepts a two-month free trial, once that trial is over the customer will be billed at full price. If your subscription product does not contain a time-limited offer, the customer would be billed for the first three months at 50% then convert to paying full price.
## Editing / deleting products
+
### Edit products
-You can edit a product by selecting the **Product name** in your **Manage In-Channel Products** index page. You may want to edit a product if you no longer wish to list a product for sale.
+
+You can edit a product by selecting the **Product name** in your **Manage In-Channel Products** index page. You may want to edit a product if you no longer wish to list a product for sale.
:::warning Editing cleared for sale
Note that changing the **Cleared for Sale** to "No" will cancel all existing subscriptions of the product and will not renew at the end of the billing period.
:::
### Deleting products
-Deleted products cannot be recovered.
+
+Deleted products cannot be recovered.
:::warning Deleting products that are cleared for sale
Note that deleting a product without first changing its **Cleared for Sale** status to "No" will keep the current subscriptions of the product active and will prevent additional purchases of the subscription product.
:::
## Product groups
+
Product groups are used for upgrade/downgrade functionality and to prevent double billing your customers. For more information regarding upgrades/downgrades, please visit our documentation on [_Upgrades, Downgrades, & Management_](/subscription-guidance/managing-subscriptions#roku).
To set up a product group, navigate to your _'Manage In-Channel Products' > 'All product groups' > 'Add a new group'_
diff --git a/docs/getting-started/installation/android.mdx b/docs/getting-started/installation/android.mdx
index aad74ed6a..eb9f99fb5 100644
--- a/docs/getting-started/installation/android.mdx
+++ b/docs/getting-started/installation/android.mdx
@@ -4,6 +4,7 @@ slug: android
excerpt: Instructions for installing Purchases SDK for Android
hidden: false
---
+
## What is RevenueCat?
RevenueCat provides a backend and a wrapper around StoreKit and Google Play Billing to make implementing in-app purchases and subscriptions easy. With our SDK, you can build and manage your app business on any platform without having to maintain IAP infrastructure. You can read more about [how RevenueCat fits into your app](https://www.revenuecat.com/blog/growth/where-does-revenuecat-fit-in-your-app/) or you can [sign up free](https://app.revenuecat.com/signup) to start building.
@@ -18,10 +19,7 @@ Purchases for Android (Google Play and Amazon Appstore) is available on Maven an
import content from "!!raw-loader!@site/code_blocks/getting-started/installation/android_1.groovy";
-
-
+
### Import Purchases
@@ -29,9 +27,7 @@ You should now be able to import `Purchases`.
import javaContent from "!!raw-loader!@site/code_blocks/getting-started/installation/android_2.java";
-
+
### Configure Proguard (Optional)
@@ -42,9 +38,9 @@ Purchases uses AndroidX App Startup under the hood. Make sure you have not remov
import xmlContent from "!!raw-loader!@site/code_blocks/getting-started/installation/android_workmanager_manifest.xml";
-
+
:::
### Set the correct launchMode
@@ -53,9 +49,11 @@ Depending on your user's payment method, they may be asked by Google Play to ver
import launchModeContent from "!!raw-loader!@site/code_blocks/getting-started/installation/android_launchmode.xml";
-
+
You can find Android's documentation on the various `launchMode` options [here](https://developer.android.com/guide/topics/manifest/activity-element#lmode).
@@ -67,9 +65,9 @@ Add a new dependency to the build.gradle apart from the regular `purchases` depe
import unityContent from "!!raw-loader!@site/code_blocks/getting-started/installation/android_3.groovy";
-
+
### Add Amazon public key
@@ -79,4 +77,4 @@ Due to some limitations, RevenueCat will only validate purchases made in product
## Next Steps
-- Now that you've installed the Purchases SDK in your Android app, get started by [configuring an instance of Purchases ](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
\ No newline at end of file
+- Now that you've installed the Purchases SDK in your Android app, get started by [configuring an instance of Purchases ](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
diff --git a/docs/getting-started/installation/capacitor.mdx b/docs/getting-started/installation/capacitor.mdx
index 5953c2af7..a2406e6a6 100644
--- a/docs/getting-started/installation/capacitor.mdx
+++ b/docs/getting-started/installation/capacitor.mdx
@@ -4,6 +4,7 @@ slug: capacitor
excerpt: Instructions for installing Purchases SDK for Cordova
hidden: false
---
+
## What is RevenueCat?
RevenueCat provides a backend and a wrapper around StoreKit and Google Play Billing to make implementing in-app purchases and subscriptions easy. With our SDK, you can build and manage your app business on any platform without having to maintain IAP infrastructure. You can read more about [how RevenueCat fits into your app](https://www.revenuecat.com/blog/growth/where-does-revenuecat-fit-in-your-app/) or you can [sign up free](https://app.revenuecat.com/signup) to start building.
@@ -14,9 +15,9 @@ RevenueCat provides a backend and a wrapper around StoreKit and Google Play Bill
import content from "!!raw-loader!@site/code_blocks/getting-started/installation/capacitor_add_plugin.shell";
-
+
## Additional Android Setup
@@ -26,16 +27,20 @@ Depending on your user's payment method, they may be asked by Google Play to ver
import launchModeContent from "!!raw-loader!@site/code_blocks/getting-started/installation/android_launchmode.xml";
-
+
You can find Android's documentation on the various `launchMode` options [here](https://developer.android.com/guide/topics/manifest/activity-element#lmode).
## Additional iOS Setup
### Add In-app Purchase Capability to Project
+
The In-app Purchase capability isn't required to install the SDK, but it is required to make purchases.
+
1. In Xcode, in project manager, select your app target.
2. Open the `Signing and Capabilities` tab.
3. Click the `+ Capability` button and double-click on In-App Purchase.
@@ -47,6 +52,7 @@ The In-app Purchase capability isn't required to install the SDK, but it is requ
You have to make sure that the `SWIFT_LANGUAGE_VERSION` is set if it's not already. `purchases-capacitor` needs Swift >= 5.0.
You can either set it in the project yourself, or use an external plugin. In order to set it yourself:
+
1. In Xcode, in project manager, select your app target.
2. Open the `Build Settings` tab
3. Look for the `Swift Language Version` setting.
@@ -60,9 +66,9 @@ The types are shipped inside the npm package. You can import them like this:
import capacitorTypesContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ionic_typescript_capacitor.ts";
-
+
### Angular
@@ -70,9 +76,11 @@ Wait for the Platform to be ready, then configure the plugin in your `src/app/ap
import capacitorAngularContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ionic_angular_capacitor.ts";
-
+
### React
@@ -80,9 +88,9 @@ Import the plugin object then use its static methods:
import capacitorReactContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ionic_react_capacitor.ts";
-
+
### Vue.js
@@ -94,10 +102,10 @@ Import the plugin object then use its static methods:
import capacitorVuejsContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ionic_vuejs_capacitor.ts";
-
+
## Next Steps
-* Now that you've installed the Purchases SDK in your Capacitor app, get started by [configuring an instance of Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
\ No newline at end of file
+- Now that you've installed the Purchases SDK in your Capacitor app, get started by [configuring an instance of Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
diff --git a/docs/getting-started/installation/cordova.mdx b/docs/getting-started/installation/cordova.mdx
index 376af34c6..ec6a5c79f 100644
--- a/docs/getting-started/installation/cordova.mdx
+++ b/docs/getting-started/installation/cordova.mdx
@@ -4,12 +4,13 @@ slug: cordova
excerpt: Instructions for installing Purchases SDK for Cordova
hidden: false
---
+
## What is RevenueCat?
RevenueCat provides a backend and a wrapper around StoreKit and Google Play Billing to make implementing in-app purchases and subscriptions easy. With our SDK, you can build and manage your app business on any platform without having to maintain IAP infrastructure. You can read more about [how RevenueCat fits into your app](https://www.revenuecat.com/blog/growth/where-does-revenuecat-fit-in-your-app/) or you can [sign up free](https://app.revenuecat.com/signup) to start building.
:::danger The Cordova SDK is deprecated
-The Cordova SDK is now deprecated. We suggest using our [Capacitor SDK](/getting-started/installation/capacitor) instead.
+The Cordova SDK is now deprecated. We suggest using our [Capacitor SDK](/getting-started/installation/capacitor) instead.
The Cordova SDK will receive maintenance updates, but new RevenueCat features and new major versions will not be made available. Billing Client v7 will be the latest version this SDK will ever support (it won't be updated to v8), which means that Google will not allow updates to your app after August 31st, 2026 [Read more about Google's Billing Client deprecation schedule](https://developer.android.com/google/play/billing/deprecation-faq)
:::
@@ -18,9 +19,9 @@ The Cordova SDK will receive maintenance updates, but new RevenueCat features an
import content from "!!raw-loader!@site/code_blocks/getting-started/installation/cordova_1.shell";
-
+
## Additional Android Setup
@@ -30,24 +31,29 @@ Depending on your user's payment method, they may be asked by Google Play to ver
import launchModeContent from "!!raw-loader!@site/code_blocks/getting-started/installation/android_launchmode.xml";
-
+
You can find Android's documentation on the various `launchMode` options [here](https://developer.android.com/guide/topics/manifest/activity-element#lmode).
## Additional iOS Setup
### Add In-app Purchase Capability to Project
+
The In-app Purchase capability isn't required to install the SDK, but it is required to make purchases.
+
1. In Xcode, in project manager, select your app target.
2. Open the `Signing and Capabilities` tab.
3. Click the `+ Capability` button and double-click on In-App Purchase.
-
+ 
### Add Strip Frameworks Phase if using cordova-plugin-purchases 1.1.0 or lower
The App Store, in its infinite wisdom, still rejects fat frameworks, so we need to strip our framework before it is deployed. To do this, add the following script phase to your build.
+
1. In Xcode, in project manager, select your app target.
2. Open the `Build Phases` tab
3. Add a new `Run Script`, name it `Strip Frameworks`
@@ -61,6 +67,7 @@ You have to make sure that the `SWIFT_LANGUAGE_VERSION` is set if it's not alrea
You can either set it in the project yourself, or use an external plugin like https://www.npmjs.com/package/cordova-plugin-add-swift-support.
In order to set it yourself:
+
1. In Xcode, in project manager, select your app target.
2. Open the `Build Settings` tab
3. Look for the `Swift Language Version` setting.
@@ -74,9 +81,15 @@ The types are shipped inside the npm package. You can import them like this:
import cordovaTypesContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ionic_typescript_cordova.ts";
-
+
## Angular
@@ -84,9 +97,9 @@ Wait for the Platform to be ready, then configure the plugin in your `src/app/ap
import cordovaAngularContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ionic_angular_cordova.ts";
-
+
## React
@@ -94,10 +107,10 @@ Import the plugin object then use its static methods:
import cordovaReactContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ionic_react_cordova.ts";
-
+
## Next Steps
-* Now that you've installed the Purchases SDK in your Cordova app, get started by [initializing an instance of Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
+- Now that you've installed the Purchases SDK in your Cordova app, get started by [initializing an instance of Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
diff --git a/docs/getting-started/installation/flutter.mdx b/docs/getting-started/installation/flutter.mdx
index 2afaf806e..34ad75967 100644
--- a/docs/getting-started/installation/flutter.mdx
+++ b/docs/getting-started/installation/flutter.mdx
@@ -4,6 +4,7 @@ slug: flutter
excerpt: Instructions for installing Purchases SDK for Flutter
hidden: false
---
+
## What is RevenueCat?
RevenueCat provides a backend and a wrapper around StoreKit and Google Play Billing to make implementing in-app purchases and subscriptions easy. With our SDK, you can build and manage your app business on any platform without having to maintain IAP infrastructure. You can read more about [how RevenueCat fits into your app](https://www.revenuecat.com/blog/growth/where-does-revenuecat-fit-in-your-app/) or you can [sign up free](https://app.revenuecat.com/signup) to start building.
@@ -17,13 +18,11 @@ Minimum target: iOS 11.0+
[](https://github.com/RevenueCat/purchases-flutter/releases)
-To use this plugin, add `purchases_flutter` as a [dependency in your pubspec.yaml file](https://flutter.io/platform-plugins/) (and run an implicit dart pub get):
+To use this plugin, add `purchases_flutter` as a [dependency in your pubspec.yaml file](https://flutter.io/platform-plugins/) (and run an implicit dart pub get):
import content from "!!raw-loader!@site/code_blocks/getting-started/installation/flutter_1.yaml";
-
+
Alternatively run this command:
@@ -32,14 +31,17 @@ Alternatively run this command:
```
### iOS Deployment Target
+
RevenueCat is compatible with iOS 11.0 or higher. Flutter does not automatically set the iOS deployment target for your project. You need to make sure that the deployment target is set to 11.0 or higher. To do that, simply edit `ios/Podfile` and add the following line if it's not already there:
```
platform :ios, '11.0'
```
+
Set it to 11.0 or a higher version for RevenueCat to work.
### iOS Swift Version
+
RevenueCat requires Swift >= 5.0 to work. If the `Podfile` in your project's `ios` folder specifies a Swift version, make sure that it's at least 5.0, otherwise you may run into build issues.
### Set the correct launchMode for Android
@@ -48,9 +50,11 @@ Depending on your user's payment method, they may be asked by Google Play to ver
import launchModeContent from "!!raw-loader!@site/code_blocks/getting-started/installation/android_launchmode.xml";
-
+
You can find Android's documentation on the various `launchMode` options [here](https://developer.android.com/guide/topics/manifest/activity-element#lmode).
@@ -60,9 +64,7 @@ You should now be able to import `purchases_flutter`.
import content2 from "!!raw-loader!@site/code_blocks/getting-started/installation/flutter_2.kt";
-
+
:::info Enable In-App Purchase capability for iOS projects in Xcode
Don't forget to enable the In-App Purchase capability for your iOS project under `Project Target -> Capabilities -> In-App Purchase`
@@ -75,12 +77,14 @@ Don't forget to enable the In-App Purchase capability for your iOS project under
:::warning
If you're using other plugins like [mobx](https://pub.dev/packages/flutter_mobx), you may run into conflicts with types from other plugins having the same name as those defined in `purchases_flutter`.
If this happens, you can resolve the ambiguity in the types by adding an import alias, for example:
+
```dart
import 'package:purchases_flutter/purchases_flutter.dart' as purchases;
```
+
After that, you can reference the types from `purchases_flutter` as `purchases.Foo`, like `purchases.PurchaserInfo`.
:::
## Next Steps
-* Now that you've installed the Purchases SDK in Flutter, get started by [configuring an instance of Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
\ No newline at end of file
+- Now that you've installed the Purchases SDK in Flutter, get started by [configuring an instance of Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
diff --git a/docs/getting-started/installation/ios.mdx b/docs/getting-started/installation/ios.mdx
index 9351c05a4..e9290f28e 100644
--- a/docs/getting-started/installation/ios.mdx
+++ b/docs/getting-started/installation/ios.mdx
@@ -4,6 +4,7 @@ slug: ios
excerpt: Instructions for installing RevenueCat SDK for iOS
hidden: false
---
+
## What is RevenueCat?
RevenueCat provides a backend and a wrapper around StoreKit and Google Play Billing to make implementing in-app purchases and subscriptions easy. With our SDK, you can build and manage your app business on any platform without having to maintain IAP infrastructure. You can read more about [how RevenueCat fits into your app](https://www.revenuecat.com/blog/growth/where-does-revenuecat-fit-in-your-app/) or you can [sign up free](https://app.revenuecat.com/signup) to start building.
@@ -12,26 +13,29 @@ RevenueCat provides a backend and a wrapper around StoreKit and Google Play Bill
[](https://github.com/RevenueCat/purchases-ios/releases)
-RevenueCat for iOS can be installed either via [CocoaPods](/getting-started/installation/ios#section-install-via-cocoapods), [Carthage](ios#section-install-via-carthage), or [Swift Package Manager](/getting-started/installation/ios#section-install-via-swift-package-manager).
+RevenueCat for iOS can be installed either via [CocoaPods](/getting-started/installation/ios#section-install-via-cocoapods), [Carthage](ios#section-install-via-carthage), or [Swift Package Manager](/getting-started/installation/ios#section-install-via-swift-package-manager).
:::info
Already have 4.x installed? View our [migration guide to 5.x →](/sdk-guides/ios-native-4x-to-5x-migration)
:::
-
+
### Install via Swift Package Manager
-You can use Swift Package Manager to add RevenueCat to your Xcode project.
+You can use Swift Package Manager to add RevenueCat to your Xcode project.
:::tip Speed up the Swift Package Manager installation
-Use a mirror of the main repository by selecting `File » Add Packages Dependencies...` and entering the repository URL (`https://github.com/RevenueCat/purchases-ios-spm.git`) into the search bar (top right).
+Use a mirror of the main repository by selecting `File » Add Packages Dependencies...` and entering the repository URL (`https://github.com/RevenueCat/purchases-ios-spm.git`) into the search bar (top right).
This will integrate far more quickly than using the main repository directly.
:::
-Set the Dependency Rule to `Up to next major`, and the version number to `5.0.0 < 6.0.0`.
+Set the Dependency Rule to `Up to next major`, and the version number to `5.0.0 < 6.0.0`.
When "Choose Package Products for purchases-ios" appears, only select `RevenueCat` and `RevenueCatUI` and click "Add Package".
@@ -45,25 +49,23 @@ To always use the latest release, add the following to your Podfile:
import iosPodfileContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ios_1.ruby";
-
+
Alternatively, pin to a specific minor version:
import iosRubyContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ios_2.ruby";
-
+
And then run:
import iosTerminalContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ios_3.ruby";
-
+
This will add `RevenueCat.framework` to your workspace.
@@ -73,28 +75,26 @@ To always use the latest release, add the following to your Cartfile:
import iosCartfileContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ios_4.txt";
-
+
Alternatively, pin to a specific minor version:
import iosTextContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ios_5.txt";
-
+
#### Carthage with XCFrameworks
-If you're using Carthage version >= 0.37, you can use RevenueCat as an XCFramework instead of a Universal Framework. This makes setup easier, since you don't have to set up build phases at all.
+If you're using Carthage version >= 0.37, you can use RevenueCat as an XCFramework instead of a Universal Framework. This makes setup easier, since you don't have to set up build phases at all.
To use XCFrameworks with Carthage, you need to pass in `--use-xcframeworks`.
import iosShellContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ios_6.shell";
-
+
More information on using XCFrameworks with Carthage is available at https://github.com/carthage/Carthage/#building-platform-independent-xcframeworks-xcode-12-and-above
@@ -108,9 +108,9 @@ Run:
import iosTextContent2 from "!!raw-loader!@site/code_blocks/getting-started/installation/ios_7.txt";
-
+
## Import the SDK
@@ -123,10 +123,12 @@ You should now be able to `import RevenueCat`.
import iosSwiftContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ios_8.swift";
import iosObjectiveCContent from "!!raw-loader!@site/code_blocks/getting-started/installation/ios_9.m";
-
+
:::info Enable In-App Purchase capability for your project
Don't forget to enable the In-App Purchase capability for your project under `Project Target -> Capabilities -> In-App Purchase`
@@ -136,4 +138,4 @@ Don't forget to enable the In-App Purchase capability for your project under `Pr
## Next Steps
-* Now that you've installed the SDK in your iOS app, get started by [configuring an instance of Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
+- Now that you've installed the SDK in your iOS app, get started by [configuring an instance of Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
diff --git a/docs/getting-started/installation/kotlin-multiplatform.mdx b/docs/getting-started/installation/kotlin-multiplatform.mdx
index 2be8271e0..014602e4f 100644
--- a/docs/getting-started/installation/kotlin-multiplatform.mdx
+++ b/docs/getting-started/installation/kotlin-multiplatform.mdx
@@ -4,6 +4,7 @@ slug: kotlin-multiplatform
excerpt: Instructions for installing Purchases SDK for Kotlin Multiplatform
hidden: false
---
+
## What is RevenueCat?
RevenueCat provides a backend and a wrapper around StoreKit and Google Play Billing to make implementing in-app purchases and subscriptions easy. With our SDK, you can build and manage your app business on any platform without having to maintain IAP infrastructure. You can read more about [how RevenueCat fits into your app](https://www.revenuecat.com/blog/growth/where-does-revenuecat-fit-in-your-app/) or you can [sign up free](https://app.revenuecat.com/signup) to start building.
@@ -25,80 +26,86 @@ Add the following coordinates to your `libs.versions.toml`.
import versionsContent from "!!raw-loader!@site/code_blocks/getting-started/installation/kmp_1.toml";
-
+
-You can now add the dependency to your `commonMain` source set in your module's `build.gradle.kts`.
+You can now add the dependency to your `commonMain` source set in your module's `build.gradle.kts`.
import buildGradle1 from "!!raw-loader!@site/code_blocks/getting-started/installation/kmp_2.kts";
-
+
### Opt in to ExperimentalForeignApi
-Since the SDK uses generated Kotlin bindings for native code on iOS, you will need to opt in to `ExperimentalForeignApi` in your iOS source sets. To do so, add the following to your module's `build.gradle.kts`.
+
+Since the SDK uses generated Kotlin bindings for native code on iOS, you will need to opt in to `ExperimentalForeignApi` in your iOS source sets. To do so, add the following to your module's `build.gradle.kts`.
import efaContent from "!!raw-loader!@site/code_blocks/getting-started/installation/kmp_3.kts";
-
+
### Link the native iOS SDK
-Since the SDK depends on a native RevenueCat iOS framework, `PurchasesHybridCommon`, this will need to be linked to your existing iOS project. You have 2 options do to so: using Swift Package Manager and using CocoaPods. It's easiest to pick the dependency manager you're already using in your iOS project.
+
+Since the SDK depends on a native RevenueCat iOS framework, `PurchasesHybridCommon`, this will need to be linked to your existing iOS project. You have 2 options do to so: using Swift Package Manager and using CocoaPods. It's easiest to pick the dependency manager you're already using in your iOS project.
+
#### Using Swift Package Manager
-To add `PurchasesHybridCommon` to your iOS project using Swift Package Manager, do the following:
+To add `PurchasesHybridCommon` to your iOS project using Swift Package Manager, do the following:
-1. Select `File » Add Packages Dependencies...` and enter the repository URL `https://github.com/RevenueCat/purchases-hybrid-common` into the search bar (top right).
-2. Then set the Dependency Rule to `Exact`, and specify the version number to be equal to everything after the '+' in the purchases-kmp version.
-3. When "Choose Package Products for purchases-hybrid-common" appears, select `PurchasesHybridCommon`. If you plan to use Paywalls, select `PurchasesHybridCommonUI` too.
+1. Select `File » Add Packages Dependencies...` and enter the repository URL `https://github.com/RevenueCat/purchases-hybrid-common` into the search bar (top right).
+2. Then set the Dependency Rule to `Exact`, and specify the version number to be equal to everything after the '+' in the purchases-kmp version.
+3. When "Choose Package Products for purchases-hybrid-common" appears, select `PurchasesHybridCommon`. If you plan to use Paywalls, select `PurchasesHybridCommonUI` too.
4. Lastly, click "Add Package".
The library should now have been added to the Package Dependencies section.
#### Using CocoaPods
-There are 2 approaches to add `PurchasesHybridCommon` to your iOS project using CocoaPods. The approach depends on how you currently integrate your existing Kotlin Multiplatform code with your iOS project.
+
+There are 2 approaches to add `PurchasesHybridCommon` to your iOS project using CocoaPods. The approach depends on how you currently integrate your existing Kotlin Multiplatform code with your iOS project.
##### 1. Directly as a local iOS framework
-Follow these instructions if your Kotlin Multiplatform module is integrated directly with your iOS project as a local iOS framework. That is, Xcode is calling the `embedAndSignAppleFrameworkForXcode` Gradle task (or the old `packForXcode` task) as part of the build. At the time of writing, if you generated your Kotlin Multiplatform project using the [online wizard](https://kmp.jetbrains.com/), this is how it's set up.
+
+Follow these instructions if your Kotlin Multiplatform module is integrated directly with your iOS project as a local iOS framework. That is, Xcode is calling the `embedAndSignAppleFrameworkForXcode` Gradle task (or the old `packForXcode` task) as part of the build. At the time of writing, if you generated your Kotlin Multiplatform project using the [online wizard](https://kmp.jetbrains.com/), this is how it's set up.
In this scenario, you need to specify the transitive dependency on `PurchasesHybridCommon` in your `Podfile`. Add the following:
import podfileContent from "!!raw-loader!@site/code_blocks/getting-started/installation/kmp_6.ruby";
-
+
##### 2. Using Cocoapods
+
Follow these instructions if your Kotlin Multiplatform module is integrated with your iOS project using CocoaPods. That is, you've applied the `kotlin("native.cocoapods")` Gradle plugin, and set it up such that the `Podfile` specifies a dependency on your Kotlin Multiplatform module. (See also [the Kotlin docs](https://kotlinlang.org/docs/native-cocoapods-xcode.html).)
-In this scenario, you can specify the transitive dependency on `PurchasesHybridCommon` using Gradle. To do so, add the following to your `libs.versions.toml`:
+In this scenario, you can specify the transitive dependency on `PurchasesHybridCommon` using Gradle. To do so, add the following to your `libs.versions.toml`:
import commonVersion from "!!raw-loader!@site/code_blocks/getting-started/installation/kmp_4.toml";
-
+
Now you can add the following to your module's `build.gradle.kts`:
import cocoapodsGradle from "!!raw-loader!@site/code_blocks/getting-started/installation/kmp_5.kts";
-
+
-Finally, add the following `post_install` script to your iOS app target in your `Podfile`. For instance, if your Kotlin Multiplatform module is named `shared`, it should look something like this:
+Finally, add the following `post_install` script to your iOS app target in your `Podfile`. For instance, if your Kotlin Multiplatform module is named `shared`, it should look something like this:
import podfilePostInstallContent from "!!raw-loader!@site/code_blocks/getting-started/installation/kmp_8.ruby";
-
+
This avoids the compiler looking for an app icon in your Kotlin Multiplatform module.
@@ -108,9 +115,11 @@ Depending on your user's payment method, they may be asked by Google Play to ver
import launchModeContent from "!!raw-loader!@site/code_blocks/getting-started/installation/android_launchmode.xml";
-
+
You can find Android's documentation on the various `launchMode` options [here](https://developer.android.com/guide/topics/manifest/activity-element#lmode).
@@ -120,20 +129,20 @@ You should now be able to import `Purchases`.
import importContent from "!!raw-loader!@site/code_blocks/getting-started/installation/kmp_7.kts";
-
+
:::warning
On Android, Purchases uses AndroidX App Startup under the hood. Make sure you have not removed the `androidx.startup.InitializationProvider` completely in your manifest. If you need to remove specific initializers, such as `androidx.work.WorkManagerInitializer`, set `tools:node="merge"` on the provider, and `tools:node="remove"` on the meta-data of the initializer you want to remove.
import xmlContent from "!!raw-loader!@site/code_blocks/getting-started/installation/android_workmanager_manifest.xml";
-
+
:::
## Next Steps
-* Now that you've installed the Purchases SDK in Kotlin Multiplatform, get started by [configuring an instance of Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
\ No newline at end of file
+- Now that you've installed the Purchases SDK in Kotlin Multiplatform, get started by [configuring an instance of Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
diff --git a/docs/getting-started/installation/macos.mdx b/docs/getting-started/installation/macos.mdx
index 112e428e1..5ab8f87bf 100644
--- a/docs/getting-started/installation/macos.mdx
+++ b/docs/getting-started/installation/macos.mdx
@@ -4,11 +4,12 @@ slug: macos
excerpt: Instructions for installing Purchases SDK for macOS / Catalyst
hidden: false
---
+
## What is RevenueCat?
RevenueCat provides a backend and a wrapper around StoreKit and Google Play Billing to make implementing in-app purchases and subscriptions easy. With our SDK, you can build and manage your app business on any platform without having to maintain IAP infrastructure. You can read more about [how RevenueCat fits into your app](https://www.revenuecat.com/blog/growth/where-does-revenuecat-fit-in-your-app/) or you can [sign up free](https://app.revenuecat.com/signup) to start building.
-As of March 2020, RevenueCat only supports [universal purchases](https://developer.apple.com/support/universal-purchase/) for macOS apps. This allows you to seamlessly share purchases between iOS, iPadOS, tvOS, watchOS, and macOS versions of your apps. If you need support for the legacy Mac App Store purchases, contact support.
+As of March 2020, RevenueCat only supports [universal purchases](https://developer.apple.com/support/universal-purchase/) for macOS apps. This allows you to seamlessly share purchases between iOS, iPadOS, tvOS, watchOS, and macOS versions of your apps. If you need support for the legacy Mac App Store purchases, contact support.
## Requirements
@@ -17,7 +18,7 @@ Minimum target: iOS 11.0+
## Installation
-The Purchases iOS SDK is also compatible with macOS, and can be installed either via [CocoaPods](/getting-started/installation/macos#section-install-via-cocoapods) or [Swift Package Manager](macos#section-install-via-swift-package-manager).
+The Purchases iOS SDK is also compatible with macOS, and can be installed either via [CocoaPods](/getting-started/installation/macos#section-install-via-cocoapods) or [Swift Package Manager](macos#section-install-via-swift-package-manager).
:::warning Carthage is currently incompatible with Catalyst
Once Carthage is updated to support Catalyst, installing with Carthage will be restored. The recommended way to install the Purchases iOS SDK for Catalyst projects is to use [Swift Package Manager](macos#section-install-via-swift-package-manager).
@@ -29,25 +30,25 @@ To always use the latest release, add the following to your Podfile:
import macosPodfileContent from "!!raw-loader!@site/code_blocks/getting-started/installation/macos_1.ruby";
-
+
Alternatively, pin to a specific minor version (e.g. 3.10):
import macosRubyContent from "!!raw-loader!@site/code_blocks/getting-started/installation/macos_2.ruby";
-
+
And then run:
import macosTerminalContent from "!!raw-loader!@site/code_blocks/getting-started/installation/macos_3.ruby";
-
+
This will add `RevenueCat.framework` to your workspace.
@@ -62,10 +63,16 @@ You should now be able to `import RevenueCat`.
import macosSwiftContent from "!!raw-loader!@site/code_blocks/getting-started/installation/macos_4.swift";
import macosObjectiveCContent from "!!raw-loader!@site/code_blocks/getting-started/installation/macos_5.m";
-
+
:::info Enable In-App Purchase capability for your project
Don't forget to enable the In-App Purchase capability for your project under `Project Target -> Capabilities -> In-App Purchase`
@@ -75,4 +82,4 @@ Don't forget to enable the In-App Purchase capability for your project under `Pr
## Next Steps
-* Now that you've installed the Purchases SDK in your macOS app, get started by [configuring an instance of Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
\ No newline at end of file
+- Now that you've installed the Purchases SDK in your macOS app, get started by [configuring an instance of Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
diff --git a/docs/getting-started/installation/reactnative.mdx b/docs/getting-started/installation/reactnative.mdx
index eb84aba4b..3a6230065 100644
--- a/docs/getting-started/installation/reactnative.mdx
+++ b/docs/getting-started/installation/reactnative.mdx
@@ -4,6 +4,7 @@ slug: reactnative
excerpt: Instructions for installing Purchases SDK for React Native
hidden: false
---
+
## What is RevenueCat?
RevenueCat provides a backend and a wrapper around StoreKit and Google Play Billing to make implementing in-app purchases and subscriptions easy. With our SDK, you can build and manage your app business on any platform without having to maintain IAP infrastructure. You can read more about [how RevenueCat fits into your app](https://www.revenuecat.com/blog/where-does-revenuecat-fit-in-your-app) or you can [sign up free](https://app.revenuecat.com/signup) to start building.
@@ -12,12 +13,12 @@ RevenueCat provides a backend and a wrapper around StoreKit and Google Play Bill
[](https://github.com/RevenueCat/react-native-purchases/releases)
-Make sure that the deployment target for iOS is at least 13.4 and Android is at least 6.0 (API 23) [as defined here](https://github.com/facebook/react-native#-requirements).
+Make sure that the deployment target for iOS is at least 13.4 and Android is at least 6.0 (API 23) [as defined here](https://github.com/facebook/react-native#-requirements).
### Option 1: React-Native package
Purchases for React-Native can be installed either via npm or yarn.
-We recommend using the latest version of React Native, or making sure that the version is at least greater than 0.64.
+We recommend using the latest version of React Native, or making sure that the version is at least greater than 0.64.
#### Option 1.1: Using auto-linking
@@ -26,25 +27,29 @@ Recent versions of React Native will automatically link the SDK, so all that's n
import reactNativeNpmContent from "!!raw-loader!@site/code_blocks/getting-started/installation/reactnative_1.shell";
import reactNativeYarnContent from "!!raw-loader!@site/code_blocks/getting-started/installation/reactnative_2.shell";
-
+
#### Option 1.2: Manual linking
-
+
After that, you should link the library to the native projects by doing:
import reactNativeShellContent from "!!raw-loader!@site/code_blocks/getting-started/installation/reactnative_5.shell";
-
+
### Option 2: Using Expo
@@ -72,9 +77,11 @@ Depending on your user's payment method, they may be asked by Google Play to ver
import launchModeContent from "!!raw-loader!@site/code_blocks/getting-started/installation/android_launchmode.xml";
-
+
You can find Android's documentation on the various `launchMode` options [here](https://developer.android.com/guide/topics/manifest/activity-element#lmode).
@@ -84,9 +91,7 @@ You should now be able to import `Purchases`.
import reactNativeJsContent from "!!raw-loader!@site/code_blocks/getting-started/installation/reactnative_7.js";
-
+
:::info Include BILLING permission for Android projects
Don't forget to include the `BILLING` permission in your AndroidManifest.xml file
@@ -94,9 +99,15 @@ Don't forget to include the `BILLING` permission in your AndroidManifest.xml fil
import reactNativeXmlContent from "!!raw-loader!@site/code_blocks/getting-started/installation/reactnative_8.xml";
-
+
:::info Enable In-App Purchase capability for your iOS project
Don't forget to enable the In-App Purchase capability for your project under `Project Target -> Capabilities -> In-App Purchase`
@@ -106,4 +117,4 @@ Don't forget to enable the In-App Purchase capability for your project under `Pr
## Next Steps
-* Now that you've installed the Purchases SDK in your React Native app, get started by [initializing an instance of Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
\ No newline at end of file
+- Now that you've installed the Purchases SDK in your React Native app, get started by [initializing an instance of Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
diff --git a/docs/getting-started/installation/roku.mdx b/docs/getting-started/installation/roku.mdx
index d95f23e87..4aa5f426c 100644
--- a/docs/getting-started/installation/roku.mdx
+++ b/docs/getting-started/installation/roku.mdx
@@ -10,11 +10,15 @@ RevenueCat's Roku support is currently in beta.
:::
## General setup
+
### Prerequisites
+
#### Setting up your Roku developer account
+
Follow the [First Steps](https://developer.roku.com/en-gb/docs/developer-program/getting-started/first-steps.md) guide to create a Roku developer account, log in to your Roku device and enable developer mode on your Roku device.
#### Setting up your Roku channel
+
Once you have your developer account created, head to the [dashboard](https://developer.roku.com/dev/dashboard)
1. First, [create a new Channel](https://developer.roku.com/en-gb/docs/developer-program/publishing/channel-publishing-guide.md#create-a-channel).
@@ -23,6 +27,7 @@ Once you have your developer account created, head to the [dashboard](https://de
4. Under "Monetization" -> "Product", follow the process to submit the tax documents, and after you're approved, you can [create in-channel products](/getting-started/entitlements/roku-products).
### App configuration
+
1. Make sure your project has been enabled to create Roku apps. If you're not sure, talk to your RevenueCat contact.
2. Open the RevenueCat dashboard, select your project, and click on "Add app" > "Roku Channel Store".
@@ -41,8 +46,8 @@ Once you have your developer account created, head to the [dashboard](https://de

-
-Remember to select 'SAVE CHANGES'
+ 
+ Remember to select 'SAVE CHANGES'
5. Back to the RevenueCat dashboard, click on "Public API Key" and copy over the value which should start with "roku_XXXXXX". You will need it to configure the SDK later.
@@ -50,6 +55,7 @@ Once you have your developer account created, head to the [dashboard](https://de

### Multi-channel support
+
The Roku channel ID is required for supporting multiple channels on a single Roku account. If your Roku account has more than one Roku Channel, you will need to enter your Channel ID for each Roku app on the RevenueCat dashboard.
1. Navigate to your [Roku Developer Dashboard](https://developer.roku.com/dev/dashboard).
@@ -63,23 +69,23 @@ The Roku channel ID is required for supporting multiple channels on a single Rok

-[](/images/roku/roku-multi-channel.png)
-Remember to select 'SAVE CHANGES'
+ [](/images/roku/roku-multi-channel.png)
+ Remember to select 'SAVE CHANGES'
### Product configuration
+
After you have configured the Roku Store app on RevenueCat, you should [create your in-channel products](/getting-started/entitlements/roku-products) and then follow RevenueCat's regular setup of [entitlements, products, and offerings](/getting-started/entitlements).
## Installing the SDK
[](https://github.com/RevenueCat/purchases-roku/releases)
+
1. Clone the repository:
import rokuClone from "!!raw-loader!@site/code_blocks/getting-started/installation/configuring-roku_1.shell";
-
+
2. Copy the `components/purchases` folder into your app's `components` folder.
3. Copy the `source/Purchases.brs` file into your app's `source` folder.
@@ -87,22 +93,24 @@ import rokuClone from "!!raw-loader!@site/code_blocks/getting-started/installati
import rokuXML from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-import-sdk.xml";
-
+
## Configuring the SDK
+
**Important:** The SDK should be used only from SceneGraph components. Calling it from the main thread or from a Task component is not supported.
Initialize the SDK with your api key. You typically do this inside the `init()` method of your main scene.
import rokuConfigure from "!!raw-loader!@site/code_blocks/getting-started/installation/configuring-roku_2.brs";
-
+
## Callbacks and error handling
+
In methods of the SDK which perform async operations, you can get the result by passing a sub routine or a callback name.
- The first parameter will contain the result.
@@ -112,9 +120,15 @@ In methods of the SDK which perform async operations, you can get the result by
import rokuCallbacksErrorHandling from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-callbacks-error-handling.brs";
-
+
## Models
@@ -125,26 +139,53 @@ import rokuLoginLogout from "!!raw-loader!@site/code_blocks/getting-started/inst
import rokuSubscriberInfo from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-subscriber-info.brs";
import rokuSubscriberAttributes from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-subscriber-attributes.brs";
-
+
### Offerings
+
import rokuGetOfferings from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-get-offerings.brs";
import rokuOffersObject from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-offerings-object.txt";
import rokuPlacements from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-placements.brs";
-
+
### Purchase
+
#### Making a purchase
+
As a parameter to the `purchase()` method, you can pass an associative array containing one of the following keys:
- `code`: A string containing the product id.
@@ -156,43 +197,55 @@ Additionally,you can pass the following optional parameters:
- `action`: To perform a product change. Valid values: `Upgrade` or `Downgrade`
#### Sync purchases
+
This method will post all purchases associated with the current Roku account to RevenueCat and become associated with the current User ID. It should only be used if you're migrating from using your own Roku Pay implementation and want to track previous purchases in RevenueCat.
import rokuPurchaseObject from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-purchase-object.txt";
import rokuMakePurchase from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-make-purchase.brs";
import rokuSyncPurchases from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-sync-purchases.brs";
-
+
### Error
+
The error model contains two fields: `code` and `message`
import rokuError from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-error.txt";
-
+
### Tying everything together
+
For most apps, the usage of the SDK would look like this:
1. Initialise the SDK
2. Log in the user
-4. Check if the entitlement is active
-5. Fetch offerings and show your paywall UI
-6. Make a purchase
+3. Check if the entitlement is active
+4. Fetch offerings and show your paywall UI
+5. Make a purchase
import rokuTyingTogether from "!!raw-loader!@site/code_blocks/getting-started/installation/roku-tying-together.brs";
-
+
## Testing
+
:::warning
Only the "root account user" can test billing on device. If you get added as a collaborator to someone else's developer account, billing testing will not work. You'll need to create your own developer account.
:::
@@ -200,17 +253,18 @@ Only the "root account user" can test billing on device. If you get added as a c
Roku transactions **do not** have an "associated" environment. Both types of transactions arrive via push notifications, however, there are key differences between them.
- **Price differentiation**:
- - _Test purchases_: Always have a price of **0**
- - _Production purchases_: Will have a non-zero price (unless it's a trial)
+ - _Test purchases_: Always have a price of **0**
+ - _Production purchases_: Will have a non-zero price (unless it's a trial)
- **Charges**:
- - _Test purchases_: The end customer will not be charged for a test purchase
- - _Production purchases_: The end customer will be charged according to the product details (e.g: pricing tier, trials, offers, etc)
+ - _Test purchases_: The end customer will not be charged for a test purchase
+ - _Production purchases_: The end customer will be charged according to the product details (e.g: pricing tier, trials, offers, etc)
In order to perform a test purchase, a [test user must be created](https://developer.roku.com/en-gb/docs/developer-program/roku-pay/quickstart/test-users.md) and associated with the channel.
After that, the test user will be able to make test purchases on the channel, regardless of the installation method: Public, Beta or Sideloaded (Billing Testing must be enabled). However, you can only use one Roku channel at a time for testing.
### RevenueCat limitations
+
Since Roku transactions do not have an associated environment, RevenueCat defines a **"sandbox"** purchase as any purchase made in a **Sideloaded** channel. A **"production"** purchase is defined as any purchase made in either a **beta** or **public** channel, regardless of whether the end customer was actually charged or not for it.
This also means for any events RevenueCat dispatches containing an [`environment` field](/integrations/webhooks/event-types-and-fields#events-format), the Roku channel where the purchase was made will determine whether the value is set to `SANDBOX` or `PRODUCTION`.
@@ -222,23 +276,27 @@ To ensure a clear separation between your "testing" and "production" purchases,
Roku's beta channels are a special channel type to assist with testing your channel in a production-like environment before publishing.
#### Beta channel rules
+
- **120 days**: A beta channel can exist for only 120 days after you create it. After 120 days, the channel will be (1) deleted and removed from your Developer Dashboard and (2) disabled for all users who have it installed
- **10 channels**: There is a maximum of 10 beta channels at a time
- **20 test users**: There can only be 20 beta test users per beta channel at any given time
## Beta limitations
+
This feature is currently in beta and has a number of known limitations.
RevenueCat features not yet supported:
+
- [RevenueCat paywalls](/tools/paywalls)
- [Trusted entitlements](/customers/trusted-entitlements)
- [Offline entitlements](/customers/customer-info#offline-entitlements)
- [Customer Center](/tools/customer-center)
Functionality not yet supported:
+
- Detecting price changes
- Chargebacks
- Extending subscriptions
- Identifying customers upon configuration
-If your use case is not supported above, reach out to [RevenueCat Support](https://app.revenuecat.com/settings/support) so we can discuss more on how to support you!
\ No newline at end of file
+If your use case is not supported above, reach out to [RevenueCat Support](https://app.revenuecat.com/settings/support) so we can discuss more on how to support you!
diff --git a/docs/getting-started/installation/unity.mdx b/docs/getting-started/installation/unity.mdx
index d336e924a..844546acc 100644
--- a/docs/getting-started/installation/unity.mdx
+++ b/docs/getting-started/installation/unity.mdx
@@ -4,6 +4,7 @@ slug: unity
excerpt: Instructions for installing Purchases SDK for Unity
hidden: false
---
+
## What is RevenueCat?
RevenueCat provides a backend and a wrapper around StoreKit and Google Play Billing to make implementing in-app purchases and subscriptions easy. With our SDK, you can build and manage your app business on any platform without having to maintain IAP infrastructure. You can read more about [how RevenueCat fits into your app](https://www.revenuecat.com/blog/where-does-revenuecat-fit-in-your-app) or you can [sign up free](https://app.revenuecat.com/signup) to start building.
@@ -15,8 +16,9 @@ RevenueCat provides a backend and a wrapper around StoreKit and Google Play Bill
We provide 2 ways to install our SDK: via Unity Package Manager (UPM) in the OpenUPM registry, or as a `.unitypackage`.
### Option 1 (recommended): Install using OpenUPM
-
+
1. First you need to import the [EDM4U](https://github.com/googlesamples/unity-jar-resolver) plugin into your project if you haven't already. This plugin will add all the Android and iOS dependencies automatically when building your project. To do this, you can:
+
- Download the `external-dependency-manager-latest.unitypackage` file from the root of the [EDM4U](https://github.com/googlesamples/unity-jar-resolver) repo.
- [Import](https://docs.unity3d.com/Manual/AssetPackagesImport.html) the downloaded `unitypackage` to your project.
@@ -58,7 +60,7 @@ The Purchases package will include a MonoBehavior called Purchases. This will be
### Link StoreKit (iOS only)
-`StoreKit` should automatically be linked. If you run into any issues, add *StoreKit.framework* to *Linked Frameworks and Libraries* in Xcode.
+`StoreKit` should automatically be linked. If you run into any issues, add _StoreKit.framework_ to _Linked Frameworks and Libraries_ in Xcode.
### Set the correct launchMode (Android only)
@@ -66,9 +68,11 @@ Depending on your user's payment method, they may be asked by Google Play to ver
import launchModeContent from "!!raw-loader!@site/code_blocks/getting-started/installation/android_launchmode.xml";
-
+
You can find Android's documentation on the various `launchMode` options [here](https://developer.android.com/guide/topics/manifest/activity-element#lmode).
@@ -78,9 +82,9 @@ The Purchases behavior takes one additional parameter, a GameObject with a Purch
import unityCSharpContent from "!!raw-loader!@site/code_blocks/getting-started/installation/unity_1.cs";
-
+
## Unity Editor
@@ -122,15 +126,15 @@ Modify the `mainTemplate.gradle` to include the following at the end of the depe
import unityGroovyContent from "!!raw-loader!@site/code_blocks/getting-started/installation/unity_2.groovy";
-
+
-Perform a clean up of the resolved dependencies using the `Assets/External Dependency Manager/Android Resolver/Delete Resolved Libraries` menu. This will cleanup the previously downloaded .aars in `Assets/Plugins/Android`. Otherwise you could end up with duplicated classes errors.
+Perform a clean up of the resolved dependencies using the `Assets/External Dependency Manager/Android Resolver/Delete Resolved Libraries` menu. This will cleanup the previously downloaded .aars in `Assets/Plugins/Android`. Otherwise you could end up with duplicated classes errors.
Also make sure to perform a resolve, so External Dependency Manager adds the right dependencies to the generated `build.gradle`.
-:::danger
+:::danger
The above instructions will also apply if using other plugin that includes the Android InAppBillingService class, or for some other reason you get an error regarding duplicated classes.
:::
@@ -156,7 +160,7 @@ Download `Purchases-UnityIAP.unityPackage` and install as normal. Skip the rest
**side by side with Unity IAP 3.3.0 < 4.4.0**
-Download `Purchases-UnityIAP.unityPackage` and install as normal. Skip the rest of the instructions in this page.
+Download `Purchases-UnityIAP.unityPackage` and install as normal. Skip the rest of the instructions in this page.
### Completing Transactions with your own IAP Code
@@ -178,4 +182,4 @@ On Android, RevenueCat **will not** consume or acknowledge any purchase if [you
## Next Steps
-* Now that you've installed the Purchases SDK in your Unity app, get started [building with Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
+- Now that you've installed the Purchases SDK in your Unity app, get started [building with Purchases →](/getting-started/quickstart#4-using-revenuecats-purchases-sdk)
diff --git a/docs/getting-started/installation/web-sdk.mdx b/docs/getting-started/installation/web-sdk.mdx
index 5c28d7370..b0e1ff078 100644
--- a/docs/getting-started/installation/web-sdk.mdx
+++ b/docs/getting-started/installation/web-sdk.mdx
@@ -4,6 +4,7 @@ slug: web-sdk
excerpt: Instructions for installing Purchases SDK for the web
hidden: false
---
+
## What is RevenueCat and RevenueCat Billing?
RevenueCat provides a backend and a mobile and web SDKs to to make implementing in-app and web purchases and subscriptions easy. With our SDK, you can build and manage your app business on any platform without having to maintain your own backend infrastructure. You can read more about [how RevenueCat fits into your app](https://www.revenuecat.com/blog/growth/where-does-revenuecat-fit-in-your-app/) or you can [sign up free](https://app.revenuecat.com/signup) to start building.
@@ -23,10 +24,13 @@ To install the RevenueCat Web SDK, add the `@revenuecat/purchases-js` package to
import npmContent from "!!raw-loader!@site/code_blocks/_projects/rc-billing/installation-npm.shell";
import yarnContent from "!!raw-loader!@site/code_blocks/_projects/rc-billing/installation-yarn.shell";
-
+
## Next steps
+
Now that you've installed the RevenueCat Web SDK, get started by [initializing it](/getting-started/configuring-sdk).
diff --git a/docs/getting-started/making-purchases.mdx b/docs/getting-started/making-purchases.mdx
index c1e7137ab..5ce961655 100644
--- a/docs/getting-started/making-purchases.mdx
+++ b/docs/getting-started/making-purchases.mdx
@@ -4,7 +4,8 @@ slug: making-purchases
excerpt: Process a transaction with Apple or Google
hidden: false
---
-The SDK has a simple method, `purchase(package:)`, that takes a package from the fetched Offering and purchases the underlying product with Apple, Google, or Amazon.
+
+The SDK has a simple method, `purchase(package:)`, that takes a package from the fetched Offering and purchases the underlying product with Apple, Google, or Amazon.
import swiftContent1 from "!!raw-loader!@site/code_blocks/getting-started/making-purchases_1.swift";
import objectiveCContent2 from "!!raw-loader!@site/code_blocks/getting-started/making-purchases_2.m";
@@ -18,34 +19,41 @@ import unityContent9 from "!!raw-loader!@site/code_blocks/getting-started/making
import rcBillingContent from "!!raw-loader!@site/code_blocks/_projects/rc-billing/rc-billing-doc-snippets.ts";
import kmpContent from "!!raw-loader!@site/code_blocks/getting-started/making-purchases_kmp_1.kts";
-
+
The `purchase(package:)` completion block will contain an updated [CustomerInfo](/customers/customer-info) object if successful, along with some details about the transaction.
If the `error` object is present, then the purchase failed. See our guide on [Error Handling](/test-and-launch/errors) for the specific error types.
-The `userCancelled` boolean is a helper for handling user cancellation errors. There will still be an error object if the user cancels, but you can optionally check the boolean instead of unwrapping the error completely.
+The `userCancelled` boolean is a helper for handling user cancellation errors. There will still be an error object if the user cancels, but you can optionally check the boolean instead of unwrapping the error completely.
:::info RevenueCat automatically finishes/acknowledges/consumes transactions
-Transactions (new and previous transactions that are synced) will be automatically completed (finished on iOS, acknowledged and consumed in Android), and will be made available through the RevenueCat SDK / Dashboard / ETL Exports.
+Transactions (new and previous transactions that are synced) will be automatically completed (finished on iOS, acknowledged and consumed in Android), and will be made available through the RevenueCat SDK / Dashboard / ETL Exports.
If you are migrating an existing app to RevenueCat and want to continue using your own in-app purchase logic, you can tell the SDK that [your app is completing transactions](/migrating-to-revenuecat/sdk-or-not/finishing-transactions) if you don't wish to have transactions completed automatically, but you will have to make sure that you complete them yourself.
:::
## Next Steps
-* Don't forget to provide some way for customers to [restore their purchases](/getting-started/restoring-purchases)
-* With purchases coming through, make sure they're [linked to the correct app user ID](/customers/user-ids)
-* If you're ready to test, start with our guides on [sandbox testing](/test-and-launch/sandbox)
\ No newline at end of file
+- Don't forget to provide some way for customers to [restore their purchases](/getting-started/restoring-purchases)
+- With purchases coming through, make sure they're [linked to the correct app user ID](/customers/user-ids)
+- If you're ready to test, start with our guides on [sandbox testing](/test-and-launch/sandbox)
diff --git a/docs/getting-started/making-purchases/android-with-jetpack-compose.mdx b/docs/getting-started/making-purchases/android-with-jetpack-compose.mdx
index e8adc4169..73a92a435 100644
--- a/docs/getting-started/making-purchases/android-with-jetpack-compose.mdx
+++ b/docs/getting-started/making-purchases/android-with-jetpack-compose.mdx
@@ -4,20 +4,21 @@ slug: android-with-jetpack-compose
excerpt: Process a transaction with an Android app built with Jetpack Compose
hidden: false
---
-Jetpack Compose is a new modern toolkit for building native UI for Android. One major difference in Jetpack Compose is the absence of `Activity`. The `purchasePackage()` and `purchasePackageWith()` functions accept an `Activity` as the first parameter but an `Activity` is not easily accessible in a `@Composable` function.
+
+Jetpack Compose is a new modern toolkit for building native UI for Android. One major difference in Jetpack Compose is the absence of `Activity`. The `purchasePackage()` and `purchasePackageWith()` functions accept an `Activity` as the first parameter but an `Activity` is not easily accessible in a `@Composable` function.
To get around this, you can create an extension function to recursively find the nearest `Activity` from your Jetpack Compose context.
import kotlinContent from "!!raw-loader!@site/code_blocks/getting-started/making-purchases/android-with-jetpack-compose_1.kt";
-
+
So example below shows how to check the nullable `Activity?` returned by `LocalContext.current.findActivity()` and pass it into `purchase(package:)`.
import kotlinContent2 from "!!raw-loader!@site/code_blocks/getting-started/making-purchases/android-with-jetpack-compose_2.kt";
-
+
diff --git a/docs/getting-started/quickstart.mdx b/docs/getting-started/quickstart.mdx
index 37b971f5c..e1af6fabf 100644
--- a/docs/getting-started/quickstart.mdx
+++ b/docs/getting-started/quickstart.mdx
@@ -29,7 +29,10 @@ Read more about setting up StoreKit Configuration files in our [Sandbox Testing]
### Configure Products and Entitlements in RevenueCat
-
+
Once your in-app products have been configured in [App Store Connect](/getting-started/entitlements/ios-products), [Google Play Console](/getting-started/entitlements/android-products), [Amazon Appstore](/getting-started/entitlements/amazon-product-setup), or [Stripe](/getting-started/entitlements/stripe-products), you'll need to copy that configuration into the RevenueCat dashboard. RevenueCat uses an Entitlements system to control access to premium features, and Offerings to manage the set of products you offer to customers.
@@ -43,16 +46,18 @@ See [Configuring Products](/getting-started/entitlements) to set up your product
-After configuring your offerings, you can jump right into designing a paywall (even before installing the SDK!) by choosing Paywalls in the sidebar of your project dashboard.
+After configuring your offerings, you can jump right into designing a paywall (even before installing the SDK!) by choosing Paywalls in the sidebar of your project dashboard.
RevenueCat provides several pre-built, customizable paywall templates that you can use to rapidly create a paywall.
-If you'd prefer to install the SDK before designing your paywall, you can always come back to this step later.
+If you'd prefer to install the SDK before designing your paywall, you can always come back to this step later.
+
+{}
-
-
+
+
-*Want to build your own custom paywall? See [Displaying Products](/getting-started/displaying-products), [Making Purchases](/getting-started/making-purchases), and [Restoring Purchases](/getting-started/restoring-purchases) for more information on manual implementation.*
+_Want to build your own custom paywall? See [Displaying Products](/getting-started/displaying-products), [Making Purchases](/getting-started/making-purchases), and [Restoring Purchases](/getting-started/restoring-purchases) for more information on manual implementation._
## 3. Using RevenueCat's Purchases SDK
@@ -60,13 +65,13 @@ Our SDK seamlessly implements purchases and subscriptions across platforms while
### SDK Installation
-Install the SDK on your preferred platform.
+Install the SDK on your preferred platform.
**Note: if you are using RevenueCat's Paywalls, the `RevenueCatUI` package is required during the installation process.**
If you run into issues with the SDK, see [Troubleshooting the SDKs](/test-and-launch/debugging/troubleshooting-the-sdks) for guidance.
-
+{}
### Initialize and Configure the SDK
@@ -96,7 +101,7 @@ import kmpContent1 from "!!raw-loader!@site/code_blocks/getting-started/configur
{ type: "swift", content: swiftContent },
{ type: "objc", content: objectiveCContent },
{ type: "kotlin", content: kotlinContent },
- { type: 'kotlin', content: kmpContent1, name: 'Kotlin Multiplatform' },
+ { type: "kotlin", content: kmpContent1, name: "Kotlin Multiplatform" },
{ type: "java", content: javaContent },
{ type: "flutter", content: flutterContent },
{ type: "rn", content: reactNativeContent },
@@ -124,10 +129,12 @@ The SDK will automatically fetch the [configured Offerings](/getting-started/ent
Presenting a paywall varies depending on your platform. See [Displaying Paywalls](/tools/paywalls/displaying-paywalls) to see in-depth examples for each platform.
-
-
+{}
-*Want to display your products manually? See [Displaying Products](/getting-started/displaying-products).*
+
+
+
+_Want to display your products manually? See [Displaying Products](/getting-started/displaying-products)._
#### SDK not fetching products or offerings?
@@ -143,11 +150,11 @@ Each platform requires slightly different configuration steps to test in sandbox
When the purchase is complete, you can find the purchase associated to the customer in the [RevenueCat dashboard](/dashboard-and-metrics/customer-history). You can [search for the customer](/dashboard-and-metrics/customer-lists#find-an-individual-customer) by their App User ID that you configured, or by the automatically assigned `$RCAnonymousID` that you'll find in your logs.
-**Note:** RevenueCat ***always*** validates transactions with the respective store. The dashboard will only reflect purchases that have been successfully validated by the store.
+**Note:** RevenueCat **_always_** validates transactions with the respective store. The dashboard will only reflect purchases that have been successfully validated by the store.
Additionally, the SDK will automatically update the customer's `CustomerInfo` object with the new purchase information. This object contains all the information about the customer's purchases and subscriptions.
-*Want to manually call the `purchase` method? See [Making Purchases](/getting-started/making-purchases).*
+_Want to manually call the `purchase` method? See [Making Purchases](/getting-started/making-purchases)._
### Check Subscription Status
@@ -215,7 +222,7 @@ import kmpContent6 from "!!raw-loader!@site/code_blocks/customers/customer-info_
{ type: "swift", content: swiftContent44 },
{ type: "objc", content: objectiveCContent45 },
{ type: "kotlin", content: kotlinContent46 },
- { type: 'kotlin', content: kmpContent6, name: 'Kotlin Multiplatform' },
+ { type: "kotlin", content: kmpContent6, name: "Kotlin Multiplatform" },
{ type: "java", content: javaContent47 },
{ type: "flutter", content: flutterContent48 },
{ type: "rn", content: reactNativeContent49 },
@@ -247,7 +254,7 @@ import kmpContent5 from "!!raw-loader!@site/code_blocks/getting-started/restorin
{ type: "swift", content: swiftContent36 },
{ type: "objc", content: objectiveCContent37 },
{ type: "kotlin", content: kotlinContent38 },
- { type: 'kotlin', content: kmpContent5, name: 'Kotlin Multiplatform' },
+ { type: "kotlin", content: kmpContent5, name: "Kotlin Multiplatform" },
{ type: "java", content: javaContent39 },
{ type: "flutter", content: flutterContent40 },
{ type: "rn", content: reactNativeContent41 },
@@ -259,7 +266,6 @@ import kmpContent5 from "!!raw-loader!@site/code_blocks/getting-started/restorin
If two different [App User IDs](/customers/user-ids) restore transactions from the same underlying store account (Apple, Google, or Amazon account) RevenueCat may attempt to create an alias between the two App User IDs and count them as the same user going forward. See our guide on [Restoring Purchases](/getting-started/restoring-purchases) for more information on the different configurable restore behaviors.
-
:::success You did it!
You have now implemented a fully-featured subscription purchasing system without spending a month writing server code. Congrats!
:::
diff --git a/docs/getting-started/restoring-purchases.mdx b/docs/getting-started/restoring-purchases.mdx
index 7b8f92216..963b08ac0 100644
--- a/docs/getting-started/restoring-purchases.mdx
+++ b/docs/getting-started/restoring-purchases.mdx
@@ -20,18 +20,20 @@ import capacitorContent from "!!raw-loader!@site/code_blocks/getting-started/res
import unityContent from "!!raw-loader!@site/code_blocks/getting-started/restoring-purchases_8.cs";
import kmpContent from "!!raw-loader!@site/code_blocks/getting-started/restoring-purchases_kmp_1.kts";
-
+
The `restorePurchases` method **should not** be triggered programmatically, since it may cause OS level sign-in prompts to appear, and should only be called from some user interaction (e.g. tapping a "Restore" button.)
diff --git a/docs/guides/common-architecture.mdx b/docs/guides/common-architecture.mdx
index 113d06ee7..b28a95c27 100644
--- a/docs/guides/common-architecture.mdx
+++ b/docs/guides/common-architecture.mdx
@@ -5,27 +5,32 @@ excerpt: Most common architecture Common setup w/ RC
hidden: false
---
-
-## Entitlements On Your Existing Backend
+## Entitlements On Your Existing Backend
Integrating RevenueCat with your backend allows you to seamlessly manage subscription purchases and unlock content for users while keeping your existing setup intact. By using RevenueCat’s SDK and webhooks, you can ensure that your backend stays synchronized with user purchases and entitlements, providing a reliable and up-to-date system for managing access to premium content.

### Process Flow
+
#### 1. App: Paywall Load and Offer Display
+
Paywall Load: When users open the app, the paywall loads and displays the available subscription offerings in the UI.
User Makes Purchase: Users can choose a subscription plan and proceed with the purchase.
+
#### 2. RevenueCat SDK: Handling Purchases
+
Fetch Offerings: The RevenueCat SDK fetches available offerings and displays them to the user.
Process Purchase: The RevenueCat backend validates and processes the purchase details received from the SDK.
Complete Purchase: The SDK finalizes the purchase, and the results are sent to the RevenueCat backend for further processing.
-Restore Purchase: The SDK allows you to regain access to entitlements after a transfer happens from one app user ID to another.
+Restore Purchase: The SDK allows you to regain access to entitlements after a transfer happens from one app user ID to another.
+
#### 3. RevenueCat Backend: Subscription Management
+
Process Purchase: The RevenueCat backend validates and processes the purchase details received from the SDK.
Unlock Entitlements: Once the purchase is confirmed, RevenueCat unlocks the corresponding entitlements.
@@ -33,7 +38,9 @@ Unlock Entitlements: Once the purchase is confirmed, RevenueCat unlocks the corr
Dispatch Webhooks & Events: RevenueCat sends webhooks and events to your backend and any other third-party integrations configured, keeping everything in sync.
Fetch Entitlements: The backend fetches the updated entitlements data.
+
#### 4. App Backend: Entitlement Synchronization
+
Receive Webhooks: Your backend receives an initial purchase webhook from RevenueCat, indicating a change in subscription status or new purchase.
Perform Entitlement Sync: The app backend performs an entitlement synchronization by fetching the latest entitlement details from RevenueCat.
@@ -41,14 +48,7 @@ Perform Entitlement Sync: The app backend performs an entitlement synchronizatio
Persist Entitlements in DB: Once fetched, the backend persists these entitlements in the database, ensuring accurate and up-to-date access controls.
#### 5. App: Content Unlocking
+
Query Database for Subscription Status: The app queries your backend database to check the user’s subscription status.
Unlock Content: If the subscription is active, the app unlocks the relevant premium content for the user.
-
-
-
-
-
-
-
-
diff --git a/docs/guides/environment-strategies.mdx b/docs/guides/environment-strategies.mdx
index 5ef19c49b..51061a325 100644
--- a/docs/guides/environment-strategies.mdx
+++ b/docs/guides/environment-strategies.mdx
@@ -4,11 +4,14 @@ slug: environment-strategies
excerpt: Recommended Environment Strategies for your use cases.
hidden: false
---
-This document contains our recommended best practices for navigating between different environments when building your app. When building and testing an app, using distinct environments like DEV, TEST, and PROD can be very helpful but can also be complicated in picking what is best for your needs.
+
+This document contains our recommended best practices for navigating between different environments when building your app. When building and testing an app, using distinct environments like DEV, TEST, and PROD can be very helpful but can also be complicated in picking what is best for your needs.
Each environment can help serve a specific purpose, from early-stage development to final user-ready deployment. This document provides an overview of the best practices and recommended approaches for using these environments to your advantage. By understanding when and how to use different environments, you can streamline your workflows, catch issues early, and confidently release a polished app to your users. Follow this guide to ensure a smooth and error-free user experience.
-## Single Project Approach ##
-If you would like to keep things short and simple as well as use DEV, TEST, and PROD environments, you can do this by simply setting up one [project](/projects/overview) in RevenueCat. RevenueCat will automatically determine if a purchase is from the [Sandbox](https://www.revenuecat.com/docs/test-and-launch/sandbox) environment or Production.
+
+## Single Project Approach
+
+If you would like to keep things short and simple as well as use DEV, TEST, and PROD environments, you can do this by simply setting up one [project](/projects/overview) in RevenueCat. RevenueCat will automatically determine if a purchase is from the [Sandbox](https://www.revenuecat.com/docs/test-and-launch/sandbox) environment or Production.
With this method, you will have the same RevenueCat API keys for all environments (DEV, TEST, and PROD). You can take advantage of RevenueCats events to identify the difference between purchases made in the Sandbox vs production, as well as use the RevenueCat dashboard to [toggle between sandbox and production transactions](https://www.revenuecat.com/docs/test-and-launch/sandbox#viewing-sandbox-data). Key details for this method include:
@@ -19,22 +22,24 @@ With this method, you will have the same RevenueCat API keys for all environment
**Data Filtering:** You can filter Customer History and the Overview section specifically for sandbox purchases or create custom Customer Lists to view sandbox data separately from production data.
**Advantages:**
+
- Minimal setup and maintenance.
- Works well for smaller projects or teams that prioritize simplicity.
**Considerations:**
+
- Less setup but more of a chance to cause confusion between users and events making purchases in different environments.
- More suited for smaller teams or projects with looser environment requirements.
This approach is best for indie projects or cases where the added complexity of multiple projects is unnecessary.
-## Separate Projects for Each Environment ##
+## Separate Projects for Each Environment
-:::warning
+:::warning
This approach increases the risk of projects becoming out of sync, leading to possible issues between environments. If you choose this route, ensure that any changes or updates are consistently applied across all projects to maintain alignment.
:::
-For teams looking to maintain complete separation of data across all environments, you can create separate [RevenueCat projects](/projects/overview) for each environment that you plan to support. DEV, TEST, and PROD environments are the most common that we see.
+For teams looking to maintain complete separation of data across all environments, you can create separate [RevenueCat projects](/projects/overview) for each environment that you plan to support. DEV, TEST, and PROD environments are the most common that we see.
We recommend this approach when testing and separation of concerns is a priority for your development team. This approach ensures that each environment has different API keys associated with it and are fully separate from one another. Once you set up a separate project for each environment, you will be able to decipher which events are coming from certain environments as well as keep all transactions from different environments isolated. Key details of this approach include:
@@ -47,10 +52,12 @@ We recommend this approach when testing and separation of concerns is a priority
**Reusability of In-App Purchase Keys:** If the projects belong to the same App Store Connect account, you can use the same In-App Purchase Key for all projects, avoiding redundant setup steps.
**Advantages:**
+
- Clear separation of data across environments.
- Better control over environment-specific settings and configurations.
**Considerations:**
+
- Requires additional setup and ongoing maintenance.
- More suited for larger teams or projects with stricter environment requirements.
- Significant duplication is necessary. You will need to manually replicate all aspects for each environment to ensure a consistent experience during testing. This includes paywalls, targeting rules, offerings, and more.
diff --git a/docs/guides/testing-guide.mdx b/docs/guides/testing-guide.mdx
index 472688eb2..7b471959b 100644
--- a/docs/guides/testing-guide.mdx
+++ b/docs/guides/testing-guide.mdx
@@ -1,7 +1,7 @@
---
title: Testing Guide
slug: testing-guide
-excerpt: Is my RevenueCat integration working?
+excerpt: Is my RevenueCat integration working?
hidden: false
---
@@ -15,13 +15,14 @@ RevenueCat makes it easy to unlock access using entitlements. Entitlements defin
This approach allows you to utilize RevenueCat as the single source of truth by checking the CustomerInfo object to see your users' purchases. This recommended approach enables you to unlock access seamlessly while still allowing you to use your backend as a backup if needed.
### Using Own Backend for Entitlements
+
You can still use RevenueCat to unlock access via your own backend. This requires some setup, as shown [here](https://www.revenuecat.com/docs/test-and-launch/testing-guide/common-architecture). This setup allows you to maintain your existing system while utilizing RevenueCat’s webhooks to keep your backend in sync with the purchases your users have made.
We recommend this approach if you have an extensive setup and don't want to switch to using RevenueCat exclusively, or if you want to unlock entitlements with the SDK and have your own backend as a fallback.
-
## Migration
### Client Side Migration
+
A client-side migration is best used when you don't have access to the raw base64 Apple receipts, StoreKit 2 signed transactions or Google purchase tokens needed for a full receipt import. This approach allows you to migrate users as they update to the latest version of your app with the RevenueCat SDK integrated. However, it may take longer to get all your users into RevenueCat, as it depends on when they choose to upgrade.
If you do have the receipts or transaction IDs, we recommend performing a full import, as it will provide more complete and accurate data.
@@ -29,6 +30,7 @@ If you do have the receipts or transaction IDs, we recommend performing a full i
You can find more on the client-side migration [here](https://www.revenuecat.com/docs/migrating-to-revenuecat/migrating-existing-subscriptions#client-side-sdk-data-import).
### Import Migration
+
If you do have access to Apple receipts, StoreKit 2 signed transactions, or Google purchase tokens, our recommend approach is a server-side data migration, as it provides a fuller history of your users. This method allows us to capture the full history of a user’s purchases for iOS and the latest snapshot for Google and Stripe.
You can find out more about server-side migration [here](https://www.revenuecat.com/docs/migrating-to-revenuecat/migrating-existing-subscriptions#server-side-data-import).
@@ -44,22 +46,30 @@ One thing to note is that you'll want to set up the following in this order:
This ensures that no subscriptions are missed during the receipt import process.
-## RevenueCat Tools
+## RevenueCat Tools
### Using RevenueCat Paywalls
+
To ensure that you are making use out of our [Paywalls](https://www.revenuecat.com/docs/tools/paywalls) tool correctly, please follow the instructions [here](https://www.revenuecat.com/docs/tools/paywalls/displaying-paywalls) for how to create a paywall in the RevenueCat dashboard and display it to your users with the RevenueCat SDK. We also have a [testing guide](https://github.com/RevenueCat/docusaurus/pull/testing-guide/use-cases) which details common testing use cases.
-### Placements & Targeting
+
+### Placements & Targeting
+
To ensure that you are making use of our [Placements](https://www.revenuecat.com/docs/tools/targeting/placements) and [Targeting](https://www.revenuecat.com/docs/tools/targeting) tools, you will want to make sure that you have some defined rules set in the monetization section of your project in the RevenueCat dashboard. More information on how to set these up can be found [here](https://www.revenuecat.com/docs/tools/targeting#creating-targeting-rules).
To test your rules, create a new user in your app that matches a targeting rule or placement and [fetch the offering](https://www.revenuecat.com/docs/getting-started/displaying-products#fetching-offerings) in the SDK. This user should be returned the correct offering based on the rule, which you can verify by creating another app user that shouldn't match your rules and comparing their returned offerings.
## Different Identification Setups
-### Anonymous
+### Anonymous
+
If you don't use an authentication system in your app, configuring RevenueCat to use anonymous app user IDs is the simplest option. Simply configure the SDK without providing a custom app user ID, and RevenueCat will assign an anonymous ID that will enable full purchase tracking.
We have a useful guide which goes over this in more detail [here](https://www.revenuecat.com/docs/customers/user-ids#anonymous-app-user-ids). To verify that you have followed that guide correctly, simply make a fresh [sandbox account](https://www.revenuecat.com/docs/test-and-launch/sandbox) and open your app. Once this is done, you should be able to see your new user in the RevenueCat dashboard with an anonymous app user ID.
-### Identified
+
+### Identified
+
To configure RevenueCat to use Identified app user IDs, simply provide your app user ID when configuring the RevenueCat SDK. We have a useful guide which goes over this in more detail [here](https://www.revenuecat.com/docs/customers/user-ids#provide-app-user-id-on-configuration).
+
### Mixed
-To configure RevenueCat to use both Anonymous and Identified App User ID's, this setup will be a little different and dependent on your use case. To do this, you can configure the SDK without identifying an app user ID initially, and then call the `login()` method with the identified App User ID that you would like to have the user login to. More information on this can be found [here](https://www.revenuecat.com/docs/customers/user-ids#provide-app-user-id-after-configuration). Going this route will also allow you to use the `logout()` method with less penalty because calling `logout()` will automatically generate an anonymous App User ID for that user that was previously logged in.
\ No newline at end of file
+
+To configure RevenueCat to use both Anonymous and Identified App User ID's, this setup will be a little different and dependent on your use case. To do this, you can configure the SDK without identifying an app user ID initially, and then call the `login()` method with the identified App User ID that you would like to have the user login to. More information on this can be found [here](https://www.revenuecat.com/docs/customers/user-ids#provide-app-user-id-after-configuration). Going this route will also allow you to use the `logout()` method with less penalty because calling `logout()` will automatically generate an anonymous App User ID for that user that was previously logged in.
diff --git a/docs/guides/testing-guide/use-cases.mdx b/docs/guides/testing-guide/use-cases.mdx
index e01db3917..413a6aa8f 100644
--- a/docs/guides/testing-guide/use-cases.mdx
+++ b/docs/guides/testing-guide/use-cases.mdx
@@ -82,17 +82,17 @@ iOS:
1. When a user tries to issue a refund, verify that you immediately direct them to the Apple support page: https://support.apple.com/en-us/HT204084
2. Once a user gets a refund granted through Apple, verify that the refund has been seen by us by checking the customer history of this user 24 hours later and ensuring that a `CANCELLATION` event has occurred with the reason field set to `CUSTOMER_SUPPORT`.
-:::warning Sandbox testing
+ :::warning Sandbox testing
Since granting refunds is done through the App Store themselves, testing this in the sandbox environment is not currently possible
:::
-**Expected Results:**
+**Expected Results:**
+
1. Users are able to request a refund
2. For Google Play, you are able to grant the refund via the Dashboard or API
3. For iOS, you direct them to Apple customer support
-
**Pass/Fail Criteria:** Verify that the refund is seen in RevenueCat in the `CANCELLATION` event.
@@ -163,7 +163,8 @@ Since granting refunds is done through the App Store themselves, testing this in
**Expected Results:** New subscription starts and old subscription ends.
-**Pass/Fail Criteria:**
+**Pass/Fail Criteria:**
+
- **Google Play:** The new subscription is started on time based on the `PRORATION` method that you use.
- **iOS:** The new subscription is started on time based on Apple's timing for whether this was an upgrade, downgrade, or crossgrade.
@@ -416,6 +417,7 @@ Purchases.sharedInstance.purchaseWith(
- [RevenueCat Documentation - Displaying Products](https://www.revenuecat.com/docs/getting-started/displaying-products)
**Preconditions:**
+
- The RevenueCat SDK is integrated into the app.
- Offerings are configured in the RevenueCat dashboard. \* The app's paywalls are set up to display offerings and packages.
@@ -933,6 +935,7 @@ if (!("gold_entitlement" in customerInfo.entitlements.active)) {
- The customer loses access to any entitlements associated with the subscription.
**Pass/Fail Criteria:**
+
- **Pass:** The subscription expires correctly, and access to entitlements is revoked.
- **Fail:** If the subscription does not expire as expected or entitlements are not revoked, the test fails.
diff --git a/docs/integrations/attribution.mdx b/docs/integrations/attribution.mdx
index bc6604cdd..fa515779d 100644
--- a/docs/integrations/attribution.mdx
+++ b/docs/integrations/attribution.mdx
@@ -27,66 +27,66 @@ RevenueCat itself is not an attribution network, and by itself cannot inform you
RevenueCat can send revenue events into the following attribution networks:
If you use an attribution provider not listed here, [contact us](https://www.revenuecat.com/contact).
diff --git a/docs/integrations/attribution/adjust.mdx b/docs/integrations/attribution/adjust.mdx
index 9c9e36eb1..0fd316ccf 100644
--- a/docs/integrations/attribution/adjust.mdx
+++ b/docs/integrations/attribution/adjust.mdx
@@ -4,6 +4,7 @@ slug: adjust
excerpt: Integrate Purchases SDK with Adjust for precise revenue tracking
hidden: false
---
+
With our Adjust integration you can:
- Accurately track subscriptions generated from Adjust campaigns, allowing you to know precisely how much revenue your campaigns generate.
@@ -12,9 +13,9 @@ With our Adjust integration you can:
### Integration at a Glance
-| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
-| :--------------: | :-----------------------: | :------------------: | :----------------------------: | :-------------------: | :-------------------------------------------------------------: |
-| ✅ | ❌ | ✅ | ❌ | ❌ | `non_subscription_purchase_event_token` `expiration_event_token` |
+| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
+| :--------------: | :-----------------------: | :------------------: | :--------------------------: | :-------------------: | :--------------------------------------------------------------: |
+| ✅ | ❌ | ✅ | ❌ | ❌ | `non_subscription_purchase_event_token` `expiration_event_token` |
## 1. Install Adjust SDK
@@ -24,13 +25,13 @@ Before RevenueCat can integrate with Adjust, your app should be running the late
The Adjust integration requires some device-specific data. RevenueCat will only send events into Adjust if the below [Customer Attribute](/customers/customer-attributes) keys have been set for the device.
-| Key | Description | Required |
-| :----------- | :---------------------------------------------------------------------------------------------------------------------------------------------- | :--------------- |
-| `$adjustId` | Adjust Id. The unique Adjust identifier for the user | ✅ (required) |
-| `$idfa` | iOS [advertising identifier](https://developer.apple.com/documentation/adsupport/asidentifiermanager/1614151-advertisingidentifier) UUID | ✅ (recommended) |
-| `$gpsAdId` | Google [advertising identifier](https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.Info) | ✅ (recommended) |
-| `$idfv` | iOS [vender identifier](https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor) UUID | ✅ (recommended) |
-| `$ip` | The IP address of the device | ✅ (recommended) |
+| Key | Description | Required |
+| :---------- | :---------------------------------------------------------------------------------------------------------------------------------------------- | :--------------- |
+| `$adjustId` | Adjust Id. The unique Adjust identifier for the user | ✅ (required) |
+| `$idfa` | iOS [advertising identifier](https://developer.apple.com/documentation/adsupport/asidentifiermanager/1614151-advertisingidentifier) UUID | ✅ (recommended) |
+| `$gpsAdId` | Google [advertising identifier](https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.Info) | ✅ (recommended) |
+| `$idfv` | iOS [vender identifier](https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor) UUID | ✅ (recommended) |
+| `$ip` | The IP address of the device | ✅ (recommended) |
:::warning Android ID deprecation
Due to policy changes from the Play Store, Android ID is no longer collected by RevenueCat's Android SDKs starting on versions 6.9.8+, 7.11.1+, and later major versions.
@@ -43,16 +44,18 @@ These properties can be set manually, like any other [Customer Attributes](/cust
import swiftContent from "!!raw-loader!@site/code_blocks/integrations/attribution/adjust_1.swift";
import javaContent from "!!raw-loader!@site/code_blocks/integrations/attribution/adjust_2.java";
-
+ type: RCCodeBlock.languages.java,
+ content: javaContent,
+ },
+ ]}
+/>
You should make sure to set attributes after the _Purchases SDK_ is configured, and before the first purchase occurs. It's safe to set this multiple times, as only the new/updated values will be sent to RevenueCat.
@@ -107,9 +110,11 @@ If you've enabled [S2S authentication on Adjust](https://help.adjust.com/en/arti
If you have a specific token per platform, you can override it on each platform section.
#### iOS
+

-#### Android
+#### Android
+

:::danger Missing Authentication Token Error (401)
@@ -164,4 +169,4 @@ Below is a sample event sent to Adjust. The type of the event (e.g. initial purc
import jsonContent from "!!raw-loader!@site/code_blocks/integrations/attribution/adjust_3.json";
-
+
diff --git a/docs/integrations/attribution/apple-search-ads.mdx b/docs/integrations/attribution/apple-search-ads.mdx
index 9f4d7aded..e7f66dd95 100644
--- a/docs/integrations/attribution/apple-search-ads.mdx
+++ b/docs/integrations/attribution/apple-search-ads.mdx
@@ -15,6 +15,7 @@ With our Apple Search Ads integration you can:
- Filter and segment RevenueCat charts by Apple Search Ads campaigns or ad groups.
Collecting Apple Search Ads data is a two part process:
+
1. You must collect the user's attribution token and send it to RevenueCat
2. With this token, RevenueCat will request attribution data from Apple directly within a 24 hour period
@@ -98,13 +99,15 @@ import flutterContent from "!!raw-loader!@site/code_blocks/integrations/attribut
import reactNativeContent from "!!raw-loader!@site/code_blocks/integrations/attribution/apple-search-ads_4.js";
import cordovaContent from "!!raw-loader!@site/code_blocks/integrations/attribution/apple-search-ads_5.js";
-
+
That's it! The Purchases SDK will collect the attribution token and send it to RevenueCat in the background.
@@ -118,7 +121,7 @@ To request consent from a user, implement the `requestTrackingAuthorization` met
import swiftContent2 from "!!raw-loader!@site/code_blocks/integrations/attribution/apple-search-ads_6.swift";
-
+
After automatic collection is enabled, Purchases will sync the attribution token with the RevenueCat backend. Please note that if you enable automatic collection _before_ requesting authorization, the attribution token will only be valid for Standard and not Detailed attribution data.
diff --git a/docs/integrations/attribution/branch.mdx b/docs/integrations/attribution/branch.mdx
index 48df0e6e3..00c87c30c 100644
--- a/docs/integrations/attribution/branch.mdx
+++ b/docs/integrations/attribution/branch.mdx
@@ -4,6 +4,7 @@ slug: branch
excerpt: Integrate Purchases SDK with Branch for precise revenue tracking
hidden: false
---
+
With our Branch integration you can:
- Accurately track subscriptions generated from Branch campaigns, allowing you to know precisely how much revenue your campaigns generate.
@@ -11,13 +12,14 @@ With our Branch integration you can:
- Continue to follow your cohorts for months to know the long tail revenue generated by your campaigns.
### Integration at a Glance
-| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
-|:----------------:|:-------------------------:|:---------------------:|:------------------------------:|:---------------------:|:---------------------------------------------------------------------------:|
-| ✅ | ❌ | Requires test API key | ❌ | ❌ | `non_subscription_purchase_event` `expiration_event` `product_change_event` |
+
+| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
+| :--------------: | :-----------------------: | :-------------------: | :--------------------------: | :-------------------: | :-------------------------------------------------------------------------: |
+| ✅ | ❌ | Requires test API key | ❌ | ❌ | `non_subscription_purchase_event` `expiration_event` `product_change_event` |
## 1. Set Branch user identity
-In order to attach attribution data to the correct user, make sure the App User Ids for RevenueCat and Branch match. The easiest way to do this is to set the Branch SDK identity to match the _Purchases_ App User Id whether you're providing your own ids or using our randomly generated ids.
+In order to attach attribution data to the correct user, make sure the App User Ids for RevenueCat and Branch match. The easiest way to do this is to set the Branch SDK identity to match the _Purchases_ App User Id whether you're providing your own ids or using our randomly generated ids.
### (Optional) Set a separate identity in Branch and RevenueCat
@@ -32,23 +34,25 @@ import objectiveCContent from "!!raw-loader!@site/code_blocks/integrations/attri
import javaContent from "!!raw-loader!@site/code_blocks/integrations/attribution/branch_3.java";
import reactNativeContent from "!!raw-loader!@site/code_blocks/integrations/attribution/branch_4.js";
-
+
## 2. Send device data to RevenueCat
The Branch integration accepts some device-specific data that can be sent to RevenueCat through reserved [Attribute](/customers/customer-attributes) keys.
-| Key | Description | Required |
-| :----------- | :---------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------ |
-| `$idfa` | iOS [advertising identifier](https://developer.apple.com/documentation/adsupport/asidentifiermanager/1614151-advertisingidentifier) UUID | ✅ (required) if no `$idfv` |
-| `$idfv` | iOS [vender identifier](https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor) UUID | ✅ (required) if no `$idfa` |
-| `$gpsAdId` | Google [advertising identifier](https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.Info) | ✅ (required) |
-| `$ip` | The IP address of the device | ✅ (required) |
+| Key | Description | Required |
+| :--------- | :---------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------- |
+| `$idfa` | iOS [advertising identifier](https://developer.apple.com/documentation/adsupport/asidentifiermanager/1614151-advertisingidentifier) UUID | ✅ (required) if no `$idfv` |
+| `$idfv` | iOS [vender identifier](https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor) UUID | ✅ (required) if no `$idfa` |
+| `$gpsAdId` | Google [advertising identifier](https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.Info) | ✅ (required) |
+| `$ip` | The IP address of the device | ✅ (required) |
:::warning Android ID deprecation
Due to policy changes from the Play Store, Android ID is no longer collected by RevenueCat's Android SDKs starting on versions 6.9.8+, 7.11.1+, and later major versions.
@@ -56,7 +60,7 @@ Due to policy changes from the Play Store, Android ID is no longer collected by
Therefore, Google's Advertising ID acts as the primary device identifier for Android devices in RevenueCat and when connecting with third-party integrations.
:::
-These properties can be set manually, like any other [Attribute](/customers/customer-attributes), or through the helper method `collectDeviceIdentifiers()`.
+These properties can be set manually, like any other [Attribute](/customers/customer-attributes), or through the helper method `collectDeviceIdentifiers()`.
import swiftContent2 from "!!raw-loader!@site/code_blocks/integrations/attribution/branch_5.swift";
import objectiveCContent2 from "!!raw-loader!@site/code_blocks/integrations/attribution/branch_6.m";
@@ -66,15 +70,15 @@ import cordovaContent from "!!raw-loader!@site/code_blocks/integrations/attribut
{/* Use the RCCodeBlock component to render the code blocks with tabs */}
-
-
-
+
You should make sure to call `collectDeviceIdentifiers()` after the _Purchases SDK_ is configured, and before the first purchase occurs. It's safe to call this multiple times, as only the new/updated values will be sent to RevenueCat.
@@ -88,14 +92,13 @@ The AdSupport framework is required to access the IDFA parameter on iOS. Don't f

-
:::danger Remove client-side purchase tracking
Make sure to remove all client-side tracking of revenue. Since RevenueCat will be sending events for all revenue actions, tracking purchases with the Branch SDK directly can lead to double counting of revenue in Branch.
:::
### (Optional) Send campaign data to RevenueCat
-RevenueCat itself is not an attribution network, and can't determine which specific ad drove an install/conversion. However, if you're able to collect this information from another source, such as Branch, it's possible to attach it to a user in RevenueCat using [Customer Attributes](/customers/customer-attributes) as well.
+RevenueCat itself is not an attribution network, and can't determine which specific ad drove an install/conversion. However, if you're able to collect this information from another source, such as Branch, it's possible to attach it to a user in RevenueCat using [Customer Attributes](/customers/customer-attributes) as well.
The below reserved key names can be used to optionally attach campaign data to a user. This data will then be sent through to other downstream analytics integrations and accessible via APIs and webhooks.
| Key |
@@ -107,16 +110,14 @@ The below reserved key names can be used to optionally attach campaign data to a
| `$keyword` |
| `$creative` |
-## 3. Send RevenueCat events into Branch
+## 3. Send RevenueCat events into Branch
After you've set up the _Purchases SDK_ to send attribution data from Branch to RevenueCat, you can "turn on" the integration and configure the event tokens from the RevenueCat dashboard.
-1. Navigate to your project in the RevenueCat dashboard and find the _Integrations_ card in the left menu. Select **+ New**
+1. Navigate to your project in the RevenueCat dashboard and find the _Integrations_ card in the left menu. Select **+ New**

-
-
2. Choose **Branch** from the Integrations menu
3. Add your test key and live key from Branch
4. Enter the event names that RevenueCat will send or choose the default event names
@@ -146,15 +147,12 @@ Navigate the the [Customer View](/dashboard-and-metrics/customer-history/basic-i

-
-
### Check that the Branch event delivered successfully
-While still on the Customer View, click into the test purchase event in the [Customer History](/dashboard-and-metrics/customer-history) and make sure that the Branch integration event exists and was delivered successfully.
+While still on the Customer View, click into the test purchase event in the [Customer History](/dashboard-and-metrics/customer-history) and make sure that the Branch integration event exists and was delivered successfully.

-
:::success You've done it!
You should start seeing events from RevenueCat appear in Branch.
:::
diff --git a/docs/integrations/attribution/facebook-ads.mdx b/docs/integrations/attribution/facebook-ads.mdx
index a68b65b6c..c3de5f6f8 100644
--- a/docs/integrations/attribution/facebook-ads.mdx
+++ b/docs/integrations/attribution/facebook-ads.mdx
@@ -4,6 +4,7 @@ slug: facebook-ads
excerpt: Integrate Purchases SDK with Facebook Ads for precise revenue tracking
hidden: false
---
+
With our Facebook Ads integration you can:
- Accurately track subscriptions generated from Facebook Ad campaigns, allowing you to know precisely how much revenue your campaigns generate.
@@ -13,8 +14,8 @@ With our Facebook Ads integration you can:
### Integration at a Glance
| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
-| :--------------: | :-----------------------: | :----------------------------------------------: | :----------------------------: | :-------------------: | :------------------: |
-| ✅ | ❌ | Requires sandbox Client Token and sandbox App ID | ❌ | ❌ | ❌ |
+| :--------------: | :-----------------------: | :----------------------------------------------: | :--------------------------: | :-------------------: | :------------------: |
+| ✅ | ❌ | Requires sandbox Client Token and sandbox App ID | ❌ | ❌ | ❌ |
## 1. Install Facebook SDK
@@ -51,12 +52,14 @@ import flutterContent from "!!raw-loader!@site/code_blocks/integrations/attribut
import kotlinContent from "!!raw-loader!@site/code_blocks/integrations/attribution/facebook-ads_3.kt";
import reactNativeContent from "!!raw-loader!@site/code_blocks/integrations/attribution/facebook-ads_4.js";
-
+
You should make sure to set attributes after the _Purchases SDK_ is configured, and before the first purchase occurs. It's safe to set this multiple times, as only the new/updated values will be sent to RevenueCat.
@@ -82,9 +85,7 @@ import swiftContent2 from "!!raw-loader!@site/code_blocks/integrations/attributi
{/* Use the RCCodeBlock component to render the code blocks with tabs */}
-
+
You can see Facebook's App Events Reference [here](https://developers.facebook.com/docs/app-events/reference).
diff --git a/docs/integrations/attribution/splitmetrics-acquire.mdx b/docs/integrations/attribution/splitmetrics-acquire.mdx
index f464fb7bc..7b08c0c65 100644
--- a/docs/integrations/attribution/splitmetrics-acquire.mdx
+++ b/docs/integrations/attribution/splitmetrics-acquire.mdx
@@ -4,6 +4,7 @@ slug: splitmetrics-acquire
excerpt: Formerly SearchAdsHQ
hidden: false
---
+
With our SplitMetrics Acquire | Formerly SearchAdsHQ integration you can:
- Accurately track subscriptions generated from Apple Search Ads campaigns, allowing you to know precisely how much revenue your campaigns generate.
@@ -11,23 +12,32 @@ With our SplitMetrics Acquire | Formerly SearchAdsHQ integration you can:
- Continue to follow your cohorts for months to know the long tail revenue generated by your campaigns.
### Integration at a Glance
-| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
-|:----------------:|:-------------------------:|:--------------------:|:------------------------------:|:---------------------:|:---------------------------------------------------------------------------:|
-| ✅ | ❌ | ✅ | ❌ | ❌ | `non_subscription_purchase_event` `uncancellation_event` `expiration_event` |
+
+| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
+| :--------------: | :-----------------------: | :------------------: | :--------------------------: | :-------------------: | :-------------------------------------------------------------------------: |
+| ✅ | ❌ | ✅ | ❌ | ❌ | `non_subscription_purchase_event` `uncancellation_event` `expiration_event` |
## 1. Send attribution data to RevenueCat
-The SplitMetrics Acquire integration requires that Apple Search Ads attribution data is sent from the device to RevenueCat.
+The SplitMetrics Acquire integration requires that Apple Search Ads attribution data is sent from the device to RevenueCat.
The simplest way to collect this information is by calling `enableAdServicesAttributionTokenCollection` **after** configuring the _Purchases SDK_.
-import swiftContent from "!!raw-loader!@site/code_blocks/integrations/attribution/apple-search-ads_1.swift";
-import objectiveCContent from "!!raw-loader!@site/code_blocks/integrations/attribution/apple-search-ads_2.m";
-import flutterContent from "!!raw-loader!@site/code_blocks/integrations/attribution/apple-search-ads_3.dart";
-import reactNativeContent from "!!raw-loader!@site/code_blocks/integrations/attribution/apple-search-ads_4.js";
+import swiftContent from "!!raw-loader!@site/code_blocks/integrations/attribution/apple-search-ads_1.swift";
+import objectiveCContent from "!!raw-loader!@site/code_blocks/integrations/attribution/apple-search-ads_2.m";
+import flutterContent from "!!raw-loader!@site/code_blocks/integrations/attribution/apple-search-ads_3.dart";
+import reactNativeContent from "!!raw-loader!@site/code_blocks/integrations/attribution/apple-search-ads_4.js";
import cordovaContent from "!!raw-loader!@site/code_blocks/integrations/attribution/apple-search-ads_5.js";
-
+
Our guide on [Apple Search Ads attribution](/integrations/attribution/apple-search-ads) outlines this step in more detail.
@@ -39,12 +49,10 @@ Please ensure you've enabled the [Basic](/integrations/attribution/apple-search-
After you've set up the _Purchases SDK_ to send device data to RevenueCat, you can "turn on" the integration and configure the event names from the RevenueCat dashboard.
-1. Navigate to your project in the RevenueCat dashboard and find the _Integrations_ card in the left menu. Select **+ New**
+1. Navigate to your project in the RevenueCat dashboard and find the _Integrations_ card in the left menu. Select **+ New**

-
-
2. Choose **SplitMetrics Acquire** from the Integrations menu.
3. Add your SplitMetrics Acquire Client ID.
4. Enter the event names that RevenueCat will send or choose the default event names.
@@ -70,7 +78,7 @@ Navigate the the [Customer View](/dashboard-and-metrics/customer-history/basic-i
### Check that the SplitMetrics Acquire event delivered successfully
-While still on the Customer View, click into the test purchase event in the [Customer History](/dashboard-and-metrics/customer-history) and make sure that the SplitMetrics Acquire integration event exists and was delivered successfully.
+While still on the Customer View, click into the test purchase event in the [Customer History](/dashboard-and-metrics/customer-history) and make sure that the SplitMetrics Acquire integration event exists and was delivered successfully.

diff --git a/docs/integrations/data-onboarding.md b/docs/integrations/data-onboarding.md
index 3a33cf198..77ed63894 100644
--- a/docs/integrations/data-onboarding.md
+++ b/docs/integrations/data-onboarding.md
@@ -5,24 +5,24 @@ excerpt: Get Started with Your Data in RevenueCat
hidden: false
---
-So, you're a data person, huh? Well you’re in luck, because we have a lot of it. Here, we’ll cover some of the basics to help you get started with RevenueCat.
+So, you're a data person, huh? Well you’re in luck, because we have a lot of it. Here, we’ll cover some of the basics to help you get started with RevenueCat.
## Core Data Definitions
-Let’s start with some definitions to help you understand & analyze your RevenueCat data. You can think about the following core metrics as foundational measures for your conversion funnel.
+Let’s start with some definitions to help you understand & analyze your RevenueCat data. You can think about the following core metrics as foundational measures for your conversion funnel.
-* New Customers: 'New Customers' includes the number of unique users (App User IDs) created in a given time window. Multiple App User IDs aliased together will be counted as 1 New Customer. Note: New Customers ≠ Active Subscribers. New Customers simply represents new users that were seen in your app.
-* Initial Conversions: Customers that converted on any product or subscription within the specified Conversion Timeframe
-* Active Subscriptions: Active Subscriptions shows the number of unexpired, paid subscriptions. This includes active paid subscriptions which may be cancelled, or within a grace period, until they expire.
+- New Customers: 'New Customers' includes the number of unique users (App User IDs) created in a given time window. Multiple App User IDs aliased together will be counted as 1 New Customer. Note: New Customers ≠ Active Subscribers. New Customers simply represents new users that were seen in your app.
+- Initial Conversions: Customers that converted on any product or subscription within the specified Conversion Timeframe
+- Active Subscriptions: Active Subscriptions shows the number of unexpired, paid subscriptions. This includes active paid subscriptions which may be cancelled, or within a grace period, until they expire.
## Example Chart: Trial Conversions
-This becomes a bit more nuanced when observing all current states of your users, including trials, pending conversions, and abandons. A chart that data engineers reference frequently is Trial Conversion Chart, which gives a detailed view into the conversion funnel, from New Customer to Trials Started, Converted, Pending & Abandoned.
-
-* Trials Started: The number of new customers that were first seen during the cohort period.
-* Conversion Rate: The number of trials started by customers in this cohort.
-* Pending Rate: The number of active trials that are set to auto-convert on completion.
-* Abandon Rate: The number of trials that have completed without converting or that are active but are not set to auto-convert on completion.
+This becomes a bit more nuanced when observing all current states of your users, including trials, pending conversions, and abandons. A chart that data engineers reference frequently is Trial Conversion Chart, which gives a detailed view into the conversion funnel, from New Customer to Trials Started, Converted, Pending & Abandoned.
+
+- Trials Started: The number of new customers that were first seen during the cohort period.
+- Conversion Rate: The number of trials started by customers in this cohort.
+- Pending Rate: The number of active trials that are set to auto-convert on completion.
+- Abandon Rate: The number of trials that have completed without converting or that are active but are not set to auto-convert on completion.
## Solving Common Data Challenges with RevenueCat
@@ -32,8 +32,7 @@ This becomes a bit more nuanced when observing all current states of your users,
RevenueCat events work by connecting directly to the app stores, meaning they are not dependent on any in-app usage or activity and are always sent from RevenueCat's servers. Server-side event detection is crucial for subscription apps since most interesting events occur when your app is inactive (e.g. trial conversions, renewals, cancellations, etc.).
-Read more about Events and explore Common Webhook Flows used to notify you throughout a customer’s journey.
-
+Read more about Events and explore Common Webhook Flows used to notify you throughout a customer’s journey.
### More Popular Features & FAQs
@@ -43,4 +42,3 @@ Read more about Events Overview & Getting Data Out of RevenueCat
5. Scheduled Data Exports
6. 3rd Party Integrations
-
diff --git a/docs/integrations/scheduled-data-exports/scheduled-data-exports-s3.mdx b/docs/integrations/scheduled-data-exports/scheduled-data-exports-s3.mdx
index 864bba517..02e580907 100644
--- a/docs/integrations/scheduled-data-exports/scheduled-data-exports-s3.mdx
+++ b/docs/integrations/scheduled-data-exports/scheduled-data-exports-s3.mdx
@@ -61,9 +61,9 @@ In the policy editor, switch to the JSON view and paste in the following code. B
import jsonContent from "!!raw-loader!@site/code_blocks/integrations/scheduled-data-exports/scheduled-data-exports-s3_1.jsonc";
-
+
This policy will allow RevenueCat to list the contents of your bucket, as well as read, write, delete files to it. When you've pasted in the code, click **Review policy\***.
@@ -134,4 +134,3 @@ Download the CSV or enter your access key and secret access key into RevenueCat.
**Error: `The provided ETL credentials or bucket name are incorrect.`**
Please ensure your IAM policy reflects the correct bucket name. If you've changed the bucket name, you'll need to update the policy to reflect the new name.
-
diff --git a/docs/integrations/third-party-integrations/airship.mdx b/docs/integrations/third-party-integrations/airship.mdx
index 4f42746d8..7b6a8bf37 100644
--- a/docs/integrations/third-party-integrations/airship.mdx
+++ b/docs/integrations/third-party-integrations/airship.mdx
@@ -22,28 +22,28 @@ With accurate and up-to-date subscription data in Airship, you'll be set to turb
### Integration at a Glance
-| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
-| :--------------: | :-----------------------: | :------------------------: | :----------------------------: | :-------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------: |
-| ✅ | ✅ | Requires Token and App key | ✅ | ❌ | `non_subscription_purchase_event` `uncancellation_event``subscription_paused_event``expiration_event``billing_issue_event` `product_change_event` |
+| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
+| :--------------: | :-----------------------: | :------------------------: | :--------------------------: | :-------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------: |
+| ✅ | ✅ | Requires Token and App key | ✅ | ❌ | `non_subscription_purchase_event` `uncancellation_event``subscription_paused_event``expiration_event``billing_issue_event` `product_change_event` |
## Events
The Airship integration tracks the following events:
-| Event Type | Default Event Name | Description | App Store | Play Store | Amazon | Stripe | Promo |
-| ------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ---------- | ------ | ------ | ----- |
-| Initial Purchase | `rc_initial_purchase_event` | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Started | `rc_trial_started_event` | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Converted | `rc_trial_converted_event` | When an auto-renewing subscription product converts from a free trial to normal paid period. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Cancelled | `rc_trial_cancelled_event` | When a user turns off renewals for an auto-renewing subscription product during a free trial period. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Renewal | `rc_renewal_event` | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Cancellation | `rc_cancellation_event` | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Uncancellation | `rc_uncancellation_event` | A non-expired cancelled subscription has been re-enabled. | ✅ | ✅ | ✅ | ❌ | ❌ |
-| Non Subscription Purchase | `rc_non_subscription_purchase_event` | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Subscription Paused | `rc_subscription_paused_event` | A subscription has been paused. | ❌ | ✅ | ❌ | ❌ | ❌ |
+| Event Type | Default Event Name | Description | App Store | Play Store | Amazon | Stripe | Promo |
+| ------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ---------- | ------ | ------ | ----- |
+| Initial Purchase | `rc_initial_purchase_event` | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Started | `rc_trial_started_event` | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Converted | `rc_trial_converted_event` | When an auto-renewing subscription product converts from a free trial to normal paid period. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Cancelled | `rc_trial_cancelled_event` | When a user turns off renewals for an auto-renewing subscription product during a free trial period. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Renewal | `rc_renewal_event` | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Cancellation | `rc_cancellation_event` | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Uncancellation | `rc_uncancellation_event` | A non-expired cancelled subscription has been re-enabled. | ✅ | ✅ | ✅ | ❌ | ❌ |
+| Non Subscription Purchase | `rc_non_subscription_purchase_event` | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Subscription Paused | `rc_subscription_paused_event` | A subscription has been paused. | ❌ | ✅ | ❌ | ❌ | ❌ |
| Expiration | `rc_expiration_event` | A subscription has expired and access should be removed. If you have [Platform Server Notifications](/platform-resources/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 | `rc_billing_issue_event` | 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 | `rc_product_change_event` | A subscriber has changed the product of their subscription. This does not mean the new subscription is in effect immediately. See [Managing Subscriptions](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
+| Billing Issue | `rc_billing_issue_event` | 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 | `rc_product_change_event` | A subscriber has changed the product of their subscription. This does not mean the new subscription is in effect immediately. See [Managing Subscriptions](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
For events that have revenue, such as trial conversions and renewals, RevenueCat will automatically record this amount along with the event in Airship.
@@ -62,12 +62,14 @@ import objectiveCContent from "!!raw-loader!@site/code_blocks/integrations/third
import kotlinContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/airship_3.kt";
import javaContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/airship_4.java";
-
+
#### [Advanced Alternative] Set Airship User Identity Using Named Users
@@ -78,12 +80,14 @@ import objectiveCContent2 from "!!raw-loader!@site/code_blocks/integrations/thir
import kotlinContent2 from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/airship_7.kt";
import javaContent2 from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/airship_8.java";
-
+
### 2. Send RevenueCat Events to Airship
@@ -109,24 +113,32 @@ import renewalContent from "!!raw-loader!@site/code_blocks/integrations/third-pa
import cancellationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/airship_14.json";
import uncancellationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/airship_15.json";
-
+
import nonSubscriptionPurchaseContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/airship_16.json";
import expirationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/airship_17.json";
import billingIssueContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/airship_18.json";
import productChangeContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/airship_19.json";
-
\ No newline at end of file
+
diff --git a/docs/integrations/third-party-integrations/amplitude.mdx b/docs/integrations/third-party-integrations/amplitude.mdx
index 7ea9e66e7..b291759e7 100644
--- a/docs/integrations/third-party-integrations/amplitude.mdx
+++ b/docs/integrations/third-party-integrations/amplitude.mdx
@@ -20,29 +20,28 @@ With accurate and up-to-date subscription data in Amplitude, you'll be set to tu
### Integration at a Glance
-| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
-| :--------------: | :-----------------------: | :------------------: | :----------------------------: | :-------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------: |
-| ✅ | ✅ | Requires API key | ✅ | ❌ | `non_subscription_purchase_event` `uncancellation_event` `subscription_paused_event` `expiration_event` `billing_issue_event` `product_change_event` |
+| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
+| :--------------: | :-----------------------: | :------------------: | :--------------------------: | :-------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------: |
+| ✅ | ✅ | Requires API key | ✅ | ❌ | `non_subscription_purchase_event` `uncancellation_event` `subscription_paused_event` `expiration_event` `billing_issue_event` `product_change_event` |
## Events
The Amplitude integration tracks the following events:
-| Event | Default Event Name | Description | App Store | Play Store | Amazon | Stripe | Promo |
-|--------------------------|----------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|------------|--------|--------|-------|
-| Initial Purchase | rc_initial_purchase_event | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Started | rc_trial_started_event | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Converted | rc_trial_converted_event | When an auto-renewing subscription product converts from a free trial to normal paid period. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Cancelled | rc_trial_cancelled_event | When a user turns off renewals for an auto-renewing subscription product during a free trial period. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Renewal | rc_renewal_event | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Cancellation | rc_cancellation_event | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Uncancellation | rc_uncancellation_event | A non-expired cancelled subscription has been re-enabled. | ✅ | ✅ | ✅ | ❌ | ❌ |
-| Non Subscription Purchase| rc_non_subscription_purchase_event | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Subscription Paused | rc_subscription_paused_event | A subscription has been paused. | ❌ | ✅ | ❌ | ❌ | ❌ |
-| Expiration | rc_expiration_event | A subscription has expired and access should be removed. If you have [Platform Server Notifications](/platform-resources/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 Issues | rc_billing_issue_event | 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 | rc_product_change_event | A subscriber has changed the product of their subscription. This does not mean the new subscription is in effect immediately. See [Managing Subscriptions](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
-
+| Event | Default Event Name | Description | App Store | Play Store | Amazon | Stripe | Promo |
+| ------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ---------- | ------ | ------ | ----- |
+| Initial Purchase | rc_initial_purchase_event | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Started | rc_trial_started_event | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Converted | rc_trial_converted_event | When an auto-renewing subscription product converts from a free trial to normal paid period. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Cancelled | rc_trial_cancelled_event | When a user turns off renewals for an auto-renewing subscription product during a free trial period. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Renewal | rc_renewal_event | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Cancellation | rc_cancellation_event | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Uncancellation | rc_uncancellation_event | A non-expired cancelled subscription has been re-enabled. | ✅ | ✅ | ✅ | ❌ | ❌ |
+| Non Subscription Purchase | rc_non_subscription_purchase_event | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Subscription Paused | rc_subscription_paused_event | A subscription has been paused. | ❌ | ✅ | ❌ | ❌ | ❌ |
+| Expiration | rc_expiration_event | A subscription has expired and access should be removed. If you have [Platform Server Notifications](/platform-resources/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 Issues | rc_billing_issue_event | 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 | rc_product_change_event | A subscriber has changed the product of their subscription. This does not mean the new subscription is in effect immediately. See [Managing Subscriptions](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
For events that have revenue, such as trial conversions and renewals, RevenueCat will automatically record this amount along with the event in Amplitude.
@@ -58,11 +57,13 @@ import swiftContent from "!!raw-loader!@site/code_blocks/integrations/third-part
import objectiveCContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/amplitude_2.m";
import javaContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/amplitude_3.java";
-
+ { type: RCCodeBlock.languages.java, content: javaContent },
+ ]}
+/>
### Send Amplitude User Identifiers to RevenueCat (Optional)
@@ -106,15 +107,17 @@ import renewalContent from "!!raw-loader!@site/code_blocks/integrations/third-pa
import cancellationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/amplitude_9.json";
import uncancellationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/amplitude_10.json";
-
+
import nonSubscriptionPurchaseContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/amplitude_11.json";
import subscriptionPausedContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/amplitude_12.json";
@@ -122,31 +125,41 @@ import expirationContent from "!!raw-loader!@site/code_blocks/integrations/third
import billingIssuesContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/amplitude_14.json";
import productChangeContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/amplitude_15.json";
-
+
## Subscription Status Attribute
Whenever RevenueCat sends an event to Amplitude, we'll update the `rc_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](/dashboard-and-metrics/customer-history/promotionals) |
-| 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. |
+| 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](/dashboard-and-metrics/customer-history/promotionals) |
+| 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. Therefore, we recommend using `rc_active_entitlements` to understand whether your customers have multiple active subscriptions to be accounted for.
diff --git a/docs/integrations/third-party-integrations/braze.mdx b/docs/integrations/third-party-integrations/braze.mdx
index 23c160ff1..3def2b3e8 100644
--- a/docs/integrations/third-party-integrations/braze.mdx
+++ b/docs/integrations/third-party-integrations/braze.mdx
@@ -148,19 +148,19 @@ import productChangeContent from "!!raw-loader!@site/code_blocks/integrations/th
Whenever RevenueCat sends an event to Braze, we'll update the `rc_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](/dashboard-and-metrics/customer-history/promotionals) |
-| 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. |
+| 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](/dashboard-and-metrics/customer-history/promotionals) |
+| 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. Therefore, we recommend using `rc_active_entitlements` to understand whether your customers have multiple active subscriptions to be accounted for.
diff --git a/docs/integrations/third-party-integrations/clevertap.mdx b/docs/integrations/third-party-integrations/clevertap.mdx
index f1778bdfa..1fc5dc5db 100644
--- a/docs/integrations/third-party-integrations/clevertap.mdx
+++ b/docs/integrations/third-party-integrations/clevertap.mdx
@@ -21,26 +21,26 @@ With accurate and up-to-date subscription data in CleverTap, you'll be set to tu
### Integration at a Glance
| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
-| :--------------: | :-----------------------: | :----------------------: | :----------------------------: | :-------------------: | :-------------------------------------------------------------: |
-| ✅ | ❌ | Requires ID and Passcode | ✅ | ❌ | `expiration_event` `billing_issue_event` `product_change_event` |
+| :--------------: | :-----------------------: | :----------------------: | :--------------------------: | :-------------------: | :-------------------------------------------------------------: |
+| ✅ | ❌ | Requires ID and Passcode | ✅ | ❌ | `expiration_event` `billing_issue_event` `product_change_event` |
## Events
The CleverTap integration tracks the following events:
-| Event | Default Event Name | Description | App Store | Play Store | Amazon | Stripe | Promo |
-|--------------------------|------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|------------|--------|--------|-------|
-| Initial Purchase | rc_initial_purchase_event | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Started | rc_trial_started_event | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Converted | rc_trial_converted_event | When an auto-renewing subscription product converts from a free trial to normal paid period. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Cancelled | rc_trial_cancelled_event | When a user turns off renewals for an auto-renewing subscription product during a free trial period. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Renewal | rc_renewal_event | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Cancellation | rc_cancellation_event | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Uncancellation | rc_uncancellation_event | A non-expired cancelled subscription has been re-enabled. | ✅ | ✅ | ✅ | ❌ | ❌ |
-| Non Subscription Purchase| rc_non_subscription_purchase_event | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Expiration | rc_expiration_event | A subscription has expired and access should be removed. If you have [Platform Server Notifications](/platform-resources/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 Issues | rc_billing_issue_event | 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 | rc_product_change_event | A subscriber has changed the product of their subscription. This does not mean the new subscription is in effect immediately. See [Managing Subscriptions](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
+| Event | Default Event Name | Description | App Store | Play Store | Amazon | Stripe | Promo |
+| ------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ---------- | ------ | ------ | ----- |
+| Initial Purchase | rc_initial_purchase_event | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Started | rc_trial_started_event | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Converted | rc_trial_converted_event | When an auto-renewing subscription product converts from a free trial to normal paid period. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Cancelled | rc_trial_cancelled_event | When a user turns off renewals for an auto-renewing subscription product during a free trial period. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Renewal | rc_renewal_event | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Cancellation | rc_cancellation_event | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Uncancellation | rc_uncancellation_event | A non-expired cancelled subscription has been re-enabled. | ✅ | ✅ | ✅ | ❌ | ❌ |
+| Non Subscription Purchase | rc_non_subscription_purchase_event | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Expiration | rc_expiration_event | A subscription has expired and access should be removed. If you have [Platform Server Notifications](/platform-resources/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 Issues | rc_billing_issue_event | 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 | rc_product_change_event | A subscriber has changed the product of their subscription. This does not mean the new subscription is in effect immediately. See [Managing Subscriptions](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
For events that have revenue, such as trial conversions and renewals, RevenueCat will automatically record this amount along with the event in CleverTap.
@@ -61,12 +61,14 @@ import objectiveCContent from "!!raw-loader!@site/code_blocks/integrations/third
import kotlinContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/clevertap_3.kt";
import javaContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/clevertap_4.java";
-
+
### 2. Send RevenueCat Events to CleverTap
@@ -99,14 +101,16 @@ import trialCancelledContent from "!!raw-loader!@site/code_blocks/integrations/t
import renewalContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/clevertap_9.json";
import cancellationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/clevertap_10.json";
-
+
import uncancellationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/clevertap_11.json";
import nonSubscriptionPurchaseContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/clevertap_12.json";
@@ -114,10 +118,16 @@ import expirationContent from "!!raw-loader!@site/code_blocks/integrations/third
import billingIssueContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/clevertap_14.json";
import productChangeContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/clevertap_15.json";
-
+
diff --git a/docs/integrations/third-party-integrations/discord.mdx b/docs/integrations/third-party-integrations/discord.mdx
index a89986118..0bf071109 100644
--- a/docs/integrations/third-party-integrations/discord.mdx
+++ b/docs/integrations/third-party-integrations/discord.mdx
@@ -15,18 +15,17 @@ Receive instant updates on your Discord server from RevenueCat whenever a new pu
The Discord integration tracks the following events:
-| Event Type | Default Event Name (Fallback) | Description | App Store | Play Store | Amazon | Stripe | Promo |
-|----------------------------|------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|------------|--------|--------|-------|
-| Initial Purchase | Customer \ just started a subscription of \ | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Started | Customer \ just started a free trial of \ | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Converted | Customer \ just converted from a free trial of \ | When an auto-renewing subscription product converts from a free trial to normal paid period. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Cancelled | Customer \ just cancelled their free trial of \ | When a user turns off renewals for an auto-renewing subscription product during a free trial period. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Renewal | Customer \ just renewed their subscription of \ | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Cancellation | Customer \ just cancelled their subscription of \ | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Non Subscription Purchase | Customer \ just purchased \ | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Billing Issue | Customer \ got a billing issue on \ | 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 | Customer \ got a product change from \ to \ | A subscriber has changed the product of their subscription. This does not mean the new subscription is in effect immediately. See [Managing Subscriptions](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
-
+| Event Type | Default Event Name (Fallback) | Description | App Store | Play Store | Amazon | Stripe | Promo |
+| ------------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ---------- | ------ | ------ | ----- |
+| Initial Purchase | Customer \ just started a subscription of \ | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Started | Customer \ just started a free trial of \ | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Converted | Customer \ just converted from a free trial of \ | When an auto-renewing subscription product converts from a free trial to normal paid period. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Cancelled | Customer \ just cancelled their free trial of \ | When a user turns off renewals for an auto-renewing subscription product during a free trial period. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Renewal | Customer \ just renewed their subscription of \ | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Cancellation | Customer \ just cancelled their subscription of \ | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Non Subscription Purchase | Customer \ just purchased \ | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Billing Issue | Customer \ got a billing issue on \ | 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 | Customer \ got a product change from \ to \ | A subscriber has changed the product of their subscription. This does not mean the new subscription is in effect immediately. See [Managing Subscriptions](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
## Configure Discord server
@@ -55,22 +54,29 @@ import trialCancelledContent from "!!raw-loader!@site/code_blocks/integrations/t
import renewalContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/discord_5.json";
import cancellationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/discord_6.json";
-
-
+
import nonSubscriptionPurchaseContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/discord_7.json";
import billingIssueContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/discord_8.json";
import productChangeContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/discord_9.json";
-
\ No newline at end of file
+
diff --git a/docs/integrations/third-party-integrations/firebase-integration.mdx b/docs/integrations/third-party-integrations/firebase-integration.mdx
index 8915a78db..bcc1823f4 100644
--- a/docs/integrations/third-party-integrations/firebase-integration.mdx
+++ b/docs/integrations/third-party-integrations/firebase-integration.mdx
@@ -19,16 +19,16 @@ This Firebase integration has 2 parts that can be used independently of each oth
Each part of the integration requires additional setup, which you can see outlined in the table below.
-| Integration | What's required |
-| ------------------ | ----------------------------------------------------------------------------------------------------------------------- |
-| Google Analytics | ✅ `$firebaseAppInstanceId` customer attribute ❌ (optional, but highly recommended) Setting Firebase user identity |
-| Firebase Extension | ✅ Setting Firebase user identity |
+| Integration | What's required |
+| ------------------ | -------------------------------------------------------------------------------------------------------------------------- |
+| Google Analytics | ✅ `$firebaseAppInstanceId` customer attribute ❌ (optional, but highly recommended) Setting Firebase user identity |
+| Firebase Extension | ✅ Setting Firebase user identity |
### Integration at a Glance
| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
-| :--------------: | :-----------------------: | :------------------: | :----------------------------: | :-------------------: | :------------------: |
-| ✅ | ❌ | ✅ | ❌ | ✅ | ❌ |
+| :--------------: | :-----------------------: | :------------------: | :--------------------------: | :-------------------: | :------------------: |
+| ✅ | ❌ | ✅ | ❌ | ✅ | ❌ |
## 1. Set up Firebase services in your project
@@ -51,9 +51,7 @@ You should make sure to use the Firebase UID as the RevenueCat app user ID when
import swiftContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/firebase-integration_1.swift";
-
+
## 3. Send analytics events to Google Analytics
@@ -65,9 +63,7 @@ Please ensure you're getting the app instance ID from the [Firebase Analytics](h
import swiftContent2 from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/firebase-integration_2.swift";
-
+
:::warning
Setting an incorrect app instance ID will prevent events from displaying in Google Analytics.
@@ -104,20 +100,19 @@ Remember to select 'Add Integration'.
The Google Analytics portion of the Firebase integration tracks the following events:
-| Event Type | Default Event Name | Description | App Store | Play Store | Amazon | Stripe | Promo |
-|----------------------------------|---------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|------------|--------|--------|-------|
-| Initial Purchase | purchase | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Started | rc_trial_start | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Renewal (incl. trial conversion) | purchase | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Cancellation (incl. during trial)| rc_cancellation | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Uncancellation | rc_uncancellation | A non-expired cancelled subscription has been re-enabled. | ✅ | ✅ | ✅ | ❌ | ❌ |
-| Non Subscription Purchase | purchase | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Subscription Paused | rc_subscription_paused | A subscription has been paused. | ❌ | ✅ | ❌ | ❌ | ❌ |
-| Expiration | rc_expiration | A subscription has expired and access should be removed. If you have [Platform Server Notifications](/platform-resources/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 | rc_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 | rc_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](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
-| Transfer | rc_transfer_event | A transfer of transactions and entitlements was initiated between one App User ID(s) to another. Please note: Two events will be sent for each transfer, one for the original user and another for the destination user. | ✅ | ✅ | ✅ | ✅ | ❌ |
-
+| Event Type | Default Event Name | Description | App Store | Play Store | Amazon | Stripe | Promo |
+| --------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ---------- | ------ | ------ | ----- |
+| Initial Purchase | purchase | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Started | rc_trial_start | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Renewal (incl. trial conversion) | purchase | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Cancellation (incl. during trial) | rc_cancellation | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Uncancellation | rc_uncancellation | A non-expired cancelled subscription has been re-enabled. | ✅ | ✅ | ✅ | ❌ | ❌ |
+| Non Subscription Purchase | purchase | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Subscription Paused | rc_subscription_paused | A subscription has been paused. | ❌ | ✅ | ❌ | ❌ | ❌ |
+| Expiration | rc_expiration | A subscription has expired and access should be removed. If you have [Platform Server Notifications](/platform-resources/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 | rc_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 | rc_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](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
+| Transfer | rc_transfer_event | A transfer of transactions and entitlements was initiated between one App User ID(s) to another. Please note: Two events will be sent for each transfer, one for the original user and another for the destination user. | ✅ | ✅ | ✅ | ✅ | ❌ |
### Testing Google Analytics
@@ -160,9 +155,7 @@ Set your security rules so that only authenticated users can access customer inf
import firebaseRules from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/firebase-integration_3.js";
-
+
### Enable Firebase Extension
@@ -206,20 +199,20 @@ Follow [this installation link](https://console.firebase.google.com/project/_/ex
##### Available Events:
-| Event | Description |
-| :--------------------- | :------------------------------------------------------------------------------------------------------------------------- |
-| `test` | Occurs whenever a test event issued through the RevenueCat dashboard. |
-| `initial_purchase` | Occurs whenever a new subscription has been purchased or a lapsed user has resubscribed. |
+| Event | Description |
+| :---------------------- | :------------------------------------------------------------------------------------------------------------------------- |
+| `test` | Occurs whenever a test event issued through the RevenueCat dashboard. |
+| `initial_purchase` | Occurs whenever a new subscription has been purchased or a lapsed user has resubscribed. |
| `non_renewing_purchase` | Occurs whenever a customer has made a purchase that will not auto-renew. |
-| `renewal ` | Occurs whenever an existing subscription has been renewed. |
-| `product_change` | Occurs whenever a subscriber has changed the product of their subscription. |
-| `cancellation` | Occurs whenever a subscription or non-renewing purchase has been cancelled. See cancellation reasons for more details. |
-| `uncancellation ` | Occurs whenever an auto-renew status has been re-enabled for a subscription. |
-| `billing_issue` | Occurs whenever there has been a problem trying to charge the subscriber. This does not mean the subscription has expired. |
-| `subscriber_alias` | Deprecated. Occurs whenever a new app_user_id has been registered for an existing subscriber. |
-| `subscription_paused` | Occurs whenever a subscription has been paused. |
-| `transfer ` | Occurs whenever a transfer of transactions and entitlements was initiated between one App User ID(s) to another. |
-| `expiration ` | Occurs whenever a subscription has expired and access should be removed. |
+| `renewal ` | Occurs whenever an existing subscription has been renewed. |
+| `product_change` | Occurs whenever a subscriber has changed the product of their subscription. |
+| `cancellation` | Occurs whenever a subscription or non-renewing purchase has been cancelled. See cancellation reasons for more details. |
+| `uncancellation ` | Occurs whenever an auto-renew status has been re-enabled for a subscription. |
+| `billing_issue` | Occurs whenever there has been a problem trying to charge the subscriber. This does not mean the subscription has expired. |
+| `subscriber_alias` | Deprecated. Occurs whenever a new app_user_id has been registered for an existing subscriber. |
+| `subscription_paused` | Occurs whenever a subscription has been paused. |
+| `transfer ` | Occurs whenever a transfer of transactions and entitlements was initiated between one App User ID(s) to another. |
+| `expiration ` | Occurs whenever a subscription has expired and access should be removed. |
- Select 'Install extension'. This will take about 3-5 minutes to complete
@@ -331,14 +324,16 @@ import trialConvertedContent from "!!raw-loader!@site/code_blocks/integrations/t
import renewalContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/firebase-integration_8.json";
import cancellationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/firebase-integration_9.json";
-
+
import uncancellationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/firebase-integration_10.json";
import nonSubscriptionPurchaseContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/firebase-integration_11.json";
@@ -348,15 +343,25 @@ import billingIssuesContent from "!!raw-loader!@site/code_blocks/integrations/th
import productChangeContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/firebase-integration_15.json";
import transferContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/firebase-integration_16.json";
-
+
### Using the Extension
@@ -366,9 +371,7 @@ To check access to entitlements, you can either [use the RevenueCat SDK](/gettin
import jsContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/firebase-integration_17.js";
-
+
#### List a user's active subscriptions
@@ -376,9 +379,7 @@ To list a user's active subscriptions, you could use the following Firebase code
import jsContent2 from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/firebase-integration_18.js";
-
+
#### React to subscription lifecycle events
diff --git a/docs/integrations/third-party-integrations/intercom.mdx b/docs/integrations/third-party-integrations/intercom.mdx
index 11161424d..85f705095 100644
--- a/docs/integrations/third-party-integrations/intercom.mdx
+++ b/docs/integrations/third-party-integrations/intercom.mdx
@@ -22,25 +22,25 @@ With accurate and up-to-date subscription data in Intercom, you'll be set to tur
### Integration at a Glance
| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
-| :--------------: | :-----------------------: | :-------------------: | :----------------------------: | :-------------------: | :-----------------------------------------------------------------------------------------------: |
-| ❌ | ❌ | Toggle on in Settings | ❌ | ❌ | `non_subscription_purchase_event` `expiration_event` `billing_issue_event` `product_change_event` |
+| :--------------: | :-----------------------: | :-------------------: | :--------------------------: | :-------------------: | :-----------------------------------------------------------------------------------------------: |
+| ❌ | ❌ | Toggle on in Settings | ❌ | ❌ | `non_subscription_purchase_event` `expiration_event` `billing_issue_event` `product_change_event` |
## Events
The Intercom integration tracks the following events:
-| Event Type | Default Event Name | Description | App Store | Play Store | Amazon | Stripe | Promo |
-|--------------------------|--------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|------------|--------|--------|-------|
-| Initial Purchase | rc_initial_purchase_event | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Started | rc_trial_started_event | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Converted | rc_trial_converted_event | When an auto-renewing subscription product converts from a free trial to normal paid period. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Cancelled | rc_trial_cancelled_event | When a user turns off renewals for an auto-renewing subscription product during a free trial period. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Renewal | rc_renewal_event | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Cancellation | rc_cancellation_event | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Non Subscription Purchase| rc_non_subscription_purchase_event | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Expiration | rc_expiration_event | A subscription has expired and access should be removed. If you have [Platform Server Notifications](/platform-resources/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 | rc_billing_issue_event | 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 | rc_product_change_event | rc_product_change_event A subscriber has changed the product of their subscription. This does not mean the new subscription is in effect immediately. See [Managing Subscriptions](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
+| Event Type | Default Event Name | Description | App Store | Play Store | Amazon | Stripe | Promo |
+| ------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ---------- | ------ | ------ | ----- |
+| Initial Purchase | rc_initial_purchase_event | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Started | rc_trial_started_event | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Converted | rc_trial_converted_event | When an auto-renewing subscription product converts from a free trial to normal paid period. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Cancelled | rc_trial_cancelled_event | When a user turns off renewals for an auto-renewing subscription product during a free trial period. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Renewal | rc_renewal_event | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Cancellation | rc_cancellation_event | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Non Subscription Purchase | rc_non_subscription_purchase_event | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Expiration | rc_expiration_event | A subscription has expired and access should be removed. If you have [Platform Server Notifications](/platform-resources/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 | rc_billing_issue_event | 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 | rc_product_change_event | rc_product_change_event A subscriber has changed the product of their subscription. This does not mean the new subscription is in effect immediately. See [Managing Subscriptions](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
## Setup
@@ -78,17 +78,22 @@ import cancellationContent from "!!raw-loader!@site/code_blocks/integrations/thi
import nonSubscriptionPurchaseContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/intercom_7.json";
import expirationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/intercom_8.json";
-
-
+
## Subscription Status Attribute
@@ -98,20 +103,20 @@ If you created your Intercom integration before February 2024, you may be using
Whenever RevenueCat sends an event to Intercom, we'll send a `subscription_status` user custom 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](/dashboard-and-metrics/customer-history/promotionals) |
-| 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. |
+| 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](/dashboard-and-metrics/customer-history/promotionals) |
+| 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 January 2024) will not have this attribute set until/unless a future event (renewal, cancellation, etc) occurs.
\ No newline at end of file
+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 January 2024) will not have this attribute set until/unless a future event (renewal, cancellation, etc) occurs.
diff --git a/docs/integrations/third-party-integrations/iterable.mdx b/docs/integrations/third-party-integrations/iterable.mdx
index aa1d14d4a..f21dee8ac 100644
--- a/docs/integrations/third-party-integrations/iterable.mdx
+++ b/docs/integrations/third-party-integrations/iterable.mdx
@@ -20,28 +20,28 @@ With accurate and up-to date subscription data in Iterable, you’ll be set to t
### Integration at a Glance
-| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
-| :--------------: | :-----------------------: | :------------------: | :----------------------------: | :-------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------: |
-| ✅ | ✅ | Requires API Key | ✅ | ❌ | `non_subscription_purchase_event` `uncancellation_event` `subscription_paused_event` `expiration_event` `billing_issue_event` `product_change_event` |
+| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
+| :--------------: | :-----------------------: | :------------------: | :--------------------------: | :-------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------: |
+| ✅ | ✅ | Requires API Key | ✅ | ❌ | `non_subscription_purchase_event` `uncancellation_event` `subscription_paused_event` `expiration_event` `billing_issue_event` `product_change_event` |
## Events
The Iterable integration tracks the following events:
-| RevenueCat Event Type | Iterable Event Type | Default Event Name | Description | App Store | Play Store | Amazon | Stripe | Promo |
-|-----------------------------|---------------------|--------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|------------|--------|--------|-------|
-| Initial Purchase | Purchase | rc_initial_purchase_event | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Started | Purchase | rc_trial_started_event | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Converted | Purchase | rc_trial_converted_event | When an auto-renewing subscription product converts from a free trial to normal paid period. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Cancelled | Custom | rc_trial_cancelled_event | When a user turns off renewals for an auto-renewing subscription product during a free trial period. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Renewal | Purchase | rc_renewal_event | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Cancellation | Custom | rc_cancellation_event | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Uncancellation | Custom | rc_uncancellation_event | A non-expired cancelled subscription has been re-enabled. | ✅ | ✅ | ✅ | ❌ | ❌ |
-| Non Subscription Purchase | Purchase | rc_non_subscription_purchase_event | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Subscription Paused | Custom | rc_subscription_paused_event | A subscription has been paused. | ❌ | ✅ | ❌ | ❌ | ❌ |
-| Expiration | Custom | rc_expiration_event | A subscription has expired and access should be removed. If you have [Platform Server Notifications](/platform-resources/server-notifications) configured, this event will occur as soon as we are notified (within seconds to minutes) of the expiration. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Billing Issue | Custom | rc_billing_issue_event | 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 | Custom | rc_product_change_event | A subscriber has changed the product of their subscription. This does not mean the new subscription is in effect immediately. See [Managing Subscriptions](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
+| RevenueCat Event Type | Iterable Event Type | Default Event Name | Description | App Store | Play Store | Amazon | Stripe | Promo |
+| ------------------------- | ------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ---------- | ------ | ------ | ----- |
+| Initial Purchase | Purchase | rc_initial_purchase_event | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Started | Purchase | rc_trial_started_event | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Converted | Purchase | rc_trial_converted_event | When an auto-renewing subscription product converts from a free trial to normal paid period. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Cancelled | Custom | rc_trial_cancelled_event | When a user turns off renewals for an auto-renewing subscription product during a free trial period. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Renewal | Purchase | rc_renewal_event | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Cancellation | Custom | rc_cancellation_event | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Uncancellation | Custom | rc_uncancellation_event | A non-expired cancelled subscription has been re-enabled. | ✅ | ✅ | ✅ | ❌ | ❌ |
+| Non Subscription Purchase | Purchase | rc_non_subscription_purchase_event | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Subscription Paused | Custom | rc_subscription_paused_event | A subscription has been paused. | ❌ | ✅ | ❌ | ❌ | ❌ |
+| Expiration | Custom | rc_expiration_event | A subscription has expired and access should be removed. If you have [Platform Server Notifications](/platform-resources/server-notifications) configured, this event will occur as soon as we are notified (within seconds to minutes) of the expiration. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Billing Issue | Custom | rc_billing_issue_event | 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 | Custom | rc_product_change_event | A subscriber has changed the product of their subscription. This does not mean the new subscription is in effect immediately. See [Managing Subscriptions](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
For events that have revenue, such as trial conversions and renewals, RevenueCat will automatically record this amount along with the event in Iterable.
@@ -65,13 +65,15 @@ import javaContent from "!!raw-loader!@site/code_blocks/integrations/third-party
import reactNativeContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/iterable_4.js";
import curlContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/iterable_5.curl";
-
+
### 2. Send RevenueCat Events to Iterable
@@ -124,15 +126,17 @@ import renewalContent from "!!raw-loader!@site/code_blocks/integrations/third-pa
import cancellationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/iterable_11.json";
import uncancellationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/iterable_12.json";
-
+
import nonSubscriptionPurchaseContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/iterable_13.json";
import subscriptionPausedContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/iterable_14.json";
@@ -140,13 +144,23 @@ import expirationContent from "!!raw-loader!@site/code_blocks/integrations/third
import billingIssuesContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/iterable_16.json";
import productChangeContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/iterable_17.json";
-
+
## Considerations
diff --git a/docs/integrations/third-party-integrations/mixpanel.mdx b/docs/integrations/third-party-integrations/mixpanel.mdx
index 9c77627ff..b5b14c404 100644
--- a/docs/integrations/third-party-integrations/mixpanel.mdx
+++ b/docs/integrations/third-party-integrations/mixpanel.mdx
@@ -13,35 +13,35 @@ Mixpanel can be a useful integration tool for seeing all events and revenue that
With our Mixpanel integration, you can:
-- Formulate a data model using interactions between a user and your product.
+- Formulate a data model using interactions between a user and your product.
- Use interactive reports to understand when a user converts and why.
With accurate and up-to-date subscription data in Mixpanel, you'll be set to turbocharge your product analytics ⚡️
### Integration at a Glance
-| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
-|:----------------:|:-------------------------:|:--------------------:|:------------------------------:|:---------------------:|:---------------------------------------------------------------------------------------------------------------------------------------------------:|
-| ✅ | ✅ | Requires Token | ✅ | ❌ | `non_subscription_purchase_event` `uncancellation_event` `subscription_paused_event` `expiration_event` `billing_issue_event` `product_change_event` |
+
+| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
+| :--------------: | :-----------------------: | :------------------: | :--------------------------: | :-------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------: |
+| ✅ | ✅ | Requires Token | ✅ | ❌ | `non_subscription_purchase_event` `uncancellation_event` `subscription_paused_event` `expiration_event` `billing_issue_event` `product_change_event` |
## Events
The Mixpanel integration tracks the following events:
-| Event | Default Event Name | Description | App Store | Play Store | Amazon | Stripe | Promo |
-|--------------------------|-----------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|------------|--------|--------|-------|
-| Initial Purchase | rc_initial_purchase_event | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Started | rc_trial_started_event | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Converted | rc_trial_converted_event | When an auto-renewing subscription product converts from a free trial to normal paid period. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Cancelled | rc_trial_cancelled_event | When a user turns off renewals for an auto-renewing subscription product during a free trial period. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Renewal | rc_renewal_event | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Cancellation | rc_cancellation_event | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Uncancellation | rc_uncancellation_event | A non-expired cancelled subscription has been re-enabled. | ✅ | ✅ | ✅ | ❌ | ❌ |
-| Non Subscription Purchase| rc_non_subscription_purchase_event | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Subscription Paused | rc_subscription_paused_event | A subscription has been paused. | ❌ | ✅ | ❌ | ❌ | ❌ |
-| Expiration | rc_expiration_event | A subscription has expired and access should be removed. If you have [Platform Server Notifications](/platform-resources/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 Issues | rc_billing_issue_event | 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 | rc_product_change_event | A subscriber has changed the product of their subscription. This does not mean the new subscription is in effect immediately. See [Managing Subscriptions](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
-
+| Event | Default Event Name | Description | App Store | Play Store | Amazon | Stripe | Promo |
+| ------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ---------- | ------ | ------ | ----- |
+| Initial Purchase | rc_initial_purchase_event | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Started | rc_trial_started_event | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Converted | rc_trial_converted_event | When an auto-renewing subscription product converts from a free trial to normal paid period. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Cancelled | rc_trial_cancelled_event | When a user turns off renewals for an auto-renewing subscription product during a free trial period. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Renewal | rc_renewal_event | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Cancellation | rc_cancellation_event | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Uncancellation | rc_uncancellation_event | A non-expired cancelled subscription has been re-enabled. | ✅ | ✅ | ✅ | ❌ | ❌ |
+| Non Subscription Purchase | rc_non_subscription_purchase_event | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Subscription Paused | rc_subscription_paused_event | A subscription has been paused. | ❌ | ✅ | ❌ | ❌ | ❌ |
+| Expiration | rc_expiration_event | A subscription has expired and access should be removed. If you have [Platform Server Notifications](/platform-resources/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 Issues | rc_billing_issue_event | 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 | rc_product_change_event | A subscriber has changed the product of their subscription. This does not mean the new subscription is in effect immediately. See [Managing Subscriptions](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
For events that have revenue, such as trial conversions and renewals, RevenueCat will automatically record this amount along with the event in Mixpanel.
@@ -51,7 +51,7 @@ For events that have revenue, such as trial conversions and renewals, RevenueCat
If you're using the Mixpanel SDK, you can set the Distinct Id to match the RevenueCat App User Id. This way, events sent from the Mixpanel SDK and events sent from RevenueCat can be synced to the same user.
-Use the `.identify()` method on the Mixpanel SDK to set the same App User ID that is set in RevenueCat.
+Use the `.identify()` method on the Mixpanel SDK to set the same App User ID that is set in RevenueCat.
##### Reserved Mixpanel Customer Attribute
@@ -63,17 +63,19 @@ import swiftContent from "!!raw-loader!@site/code_blocks/integrations/third-part
import objectiveCContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/mixpanel_2.m";
import javaContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/mixpanel_3.java";
-
+
### 2. Send RevenueCat Events to Mixpanel
After you've set up the _Purchases SDK_ and Mixpanel SDK, you can "turn on" the integration and configure the event names from the RevenueCat dashboard.
-1. Navigate to your project in the RevenueCat dashboard and find the _Integrations_ card in the left menu. Select **+ New**
+1. Navigate to your project in the RevenueCat dashboard and find the _Integrations_ card in the left menu. Select **+ New**

@@ -96,33 +98,39 @@ import renewalContent from "!!raw-loader!@site/code_blocks/integrations/third-pa
import cancellationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/mixpanel_9.json";
import nonSubscriptionPurchaseContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/mixpanel_10.json";
-
+
## Subscription Status Attribute
Whenever RevenueCat sends an event to Mixpanel, we'll update the `rc_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](/dashboard-and-metrics/customer-history/promotionals) |
-| 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. |
+| 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](/dashboard-and-metrics/customer-history/promotionals) |
+| 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.
diff --git a/docs/integrations/third-party-integrations/mparticle.mdx b/docs/integrations/third-party-integrations/mparticle.mdx
index baa55c0f6..92e895646 100644
--- a/docs/integrations/third-party-integrations/mparticle.mdx
+++ b/docs/integrations/third-party-integrations/mparticle.mdx
@@ -21,30 +21,29 @@ With accurate and up-to-date subscription data in mParticle, you'll be set to tu
### Integration at a Glance
| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
-| :--------------: | :-----------------------: | :------------------: | :----------------------------: | :-------------------: | :------------------: |
-| ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
+| :--------------: | :-----------------------: | :------------------: | :--------------------------: | :-------------------: | :------------------: |
+| ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
## Events
The mParticle 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](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Uncancellation | uncancellation | A non-expired cancelled subscription has been re-enabled. | ✅ | ✅ | ✅ | ❌ | ❌ |
-| Non Subscription Purchase| non_renewing_purchase | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Subscription Paused | rc_subscription_paused_event | A subscription has been paused. | ❌ | ✅ | ❌ | ❌ | ❌ |
-| Expiration | expiration | A subscription has expired and access should be removed. If you have [Platform Server Notifications](/platform-resources/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 Issues | 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](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
-| Refund | refund | When a user canceled their subscription via customer support. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Transfer | rc_transfer_event | A transfer of transactions and entitlements was initiated between one App User ID(s) to another.
Please note: Two events will be sent for each transfer, one for the original user and another for the destination user. | ✅ | ✅ | ✅ | ✅ | ❌ |
-
+| 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](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Uncancellation | uncancellation | A non-expired cancelled subscription has been re-enabled. | ✅ | ✅ | ✅ | ❌ | ❌ |
+| Non Subscription Purchase | non_renewing_purchase | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Subscription Paused | rc_subscription_paused_event | A subscription has been paused. | ❌ | ✅ | ❌ | ❌ | ❌ |
+| Expiration | expiration | A subscription has expired and access should be removed. If you have [Platform Server Notifications](/platform-resources/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 Issues | 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](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
+| Refund | refund | When a user canceled their subscription via customer support. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Transfer | rc_transfer_event | A transfer of transactions and entitlements was initiated between one App User ID(s) to another.
Please note: Two events will be sent for each transfer, one for the original user and another for the destination user. | ✅ | ✅ | ✅ | ✅ | ❌ |
For events that have revenue, such as trial conversions and renewals, RevenueCat will automatically record this amount along with the event in mParticle.
@@ -78,11 +77,13 @@ import swiftContent from "!!raw-loader!@site/code_blocks/integrations/third-part
import objectiveCContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/mparticle_2.m";
import javaContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/mparticle_3.java";
-
+
mParticle also allows you to log a user in after starting the SDK and log a user out; you should handle both of these cases:
@@ -90,21 +91,25 @@ import swiftContent2 from "!!raw-loader!@site/code_blocks/integrations/third-par
import objectiveCContent2 from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/mparticle_5.m";
import javaContent2 from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/mparticle_6.java";
-
+
import swiftContent3 from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/mparticle_7.swift";
import objectiveCContent3 from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/mparticle_8.m";
import javaContent3 from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/mparticle_9.java";
-
+
:::danger Device identifiers with iOS App Tracking Transparency (iOS 14.5+)
If you are requesting the App Tracking permission through ATT to access the IDFA, you can call `.collectDeviceIdentifiers()` _again_ if the customer accepts the permission to update the `$idfa` attribute in RevenueCat.
@@ -171,22 +176,26 @@ import renewalContent from "!!raw-loader!@site/code_blocks/integrations/third-pa
import cancellationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/mparticle_15.json";
import uncancellationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/mparticle_16.json";
-
+
import expirationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/mparticle_17.json";
import billingIssueContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/mparticle_18.json";
import productChangeContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/mparticle_19.json";
-
\ No newline at end of file
+
diff --git a/docs/integrations/third-party-integrations/onesignal.mdx b/docs/integrations/third-party-integrations/onesignal.mdx
index 1c279d1ae..e4348455f 100644
--- a/docs/integrations/third-party-integrations/onesignal.mdx
+++ b/docs/integrations/third-party-integrations/onesignal.mdx
@@ -42,27 +42,27 @@ RevenueCat only updates data tags in OneSignal in response to auto-renewing subs
### 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](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-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. | ❌ | ✅ | ❌ | ❌ | ❌ |
+| 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](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-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](/platform-resources/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](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
+| 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](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
## 1. Send device data to RevenueCat
@@ -71,8 +71,8 @@ The OneSignal integration tracks the following events:
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](doc:subscriber-attributes) for the user.
| Key | Description | Required |
-|:-------------------|:---------------------------------------------------------------------------------------------------------------| :------- |
-| `$onesignalUserId` | The [OneSignal ID](https://documentation.onesignal.com/docs/users#user-properties) used to represent the user. | ✅ |
+| :----------------- | :------------------------------------------------------------------------------------------------------------- | :------- |
+| `$onesignalUserId` | The [OneSignal ID](https://documentation.onesignal.com/docs/users#user-properties) used to represent the user. | ✅ |
This property can be set manually, like any other [Subscriber Attributes](doc:subscriber-attributes), or through the helper method `setOnesignalUserID()`.
@@ -81,7 +81,12 @@ You can listen for changes to the OneSignal Id through their SDK, and send the v
import onesignalV11Content from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/onesignal_14.swift";
import onesignalV11ContentSwiftUi from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/onesignal_15.swift";
-
+
### 1.2 Device-centric API versions of OneSignal (9.0 and below)
@@ -97,7 +102,7 @@ You can listen for changes to the OneSignal Id through their SDK, and send the v
import onesignalV9Content from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/onesignal_1.swift";
-
+
## 2. Send RevenueCat events into OneSignal
@@ -148,21 +153,30 @@ import expirationContent from "!!raw-loader!@site/code_blocks/integrations/third
import billingIssueContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/onesignal_10.json";
import productChangeContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/onesignal_11.json";
-
-
+
:::warning Why are tags not working?
If your tags aren't working and RevenueCat is sending events successfully with 200 codes, check out [OneSignal's troubleshooting guide](https://documentation.onesignal.com/docs/add-user-data-tags#why-are-tags-not-working).
@@ -176,19 +190,19 @@ You should start seeing subscription data from RevenueCat appear on users in One
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](/dashboard-and-metrics/customer-history/promotionals) |
-| 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. |
+| 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](/dashboard-and-metrics/customer-history/promotionals) |
+| 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.
diff --git a/docs/integrations/third-party-integrations/segment.mdx b/docs/integrations/third-party-integrations/segment.mdx
index 6b7e58127..a6710b742 100644
--- a/docs/integrations/third-party-integrations/segment.mdx
+++ b/docs/integrations/third-party-integrations/segment.mdx
@@ -19,29 +19,29 @@ With our Segment integration, you can:
With accurate and up-to-date subscription data in Segment, you'll be set to turbocharge your user engagement ⚡️
### Integration at a Glance
-| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
-|:----------------:|:-------------------------:|:---------------------:|:------------------------------:|:---------------------:|:---------------------------------------------------------------------------------------------------------------------------------------------------:|
-| ✅ | ✅ | Toggle on in Settings | ✅ | ❌ | `non_subscription_purchase_event` `uncancellation_event` `subscription_paused_event` `expiration_event` `billing_issue_event` `product_change_event` |
+
+| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
+| :--------------: | :-----------------------: | :-------------------: | :--------------------------: | :-------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------: |
+| ✅ | ✅ | Toggle on in Settings | ✅ | ❌ | `non_subscription_purchase_event` `uncancellation_event` `subscription_paused_event` `expiration_event` `billing_issue_event` `product_change_event` |
## Events
The Segment integration tracks the following events:
-| Event Type | Default Event Name | Description | App Store | Play Store | Amazon | Stripe | Promo |
-|----------------------|------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|------------|--------|--------|-------|
-| Initial Purchase | `rc_initial_purchase_event` | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Started | `rc_trial_started_event` | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Converted | `rc_trial_converted_event` | When an auto-renewing subscription product converts from a free trial to normal paid period. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Cancelled | `rc_trial_cancelled_event` | When a user turns off renewals for an auto-renewing subscription product during a free trial period. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Renewal | `rc_renewal_event` | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Cancellation | `rc_cancellation_event` | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Uncancellation | `rc_uncancellation_event` | A non-expired cancelled subscription has been re-enabled. | ✅ | ✅ | ✅ | ❌ | ❌ |
-| Non Subscription Purchase | `rc_non_subscription_purchase_event` | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Subscription Paused | `rc_subscription_paused_event` | A subscription has been paused. | ❌ | ✅ | ❌ | ❌ | ❌ |
-| Expiration | `rc_expiration_event` | A subscription has expired and access should be removed. If you have [Platform Server Notifications](/platform-resources/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 | `rc_billing_issue_event` | 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 | `rc_product_change_event` | A subscriber has changed the product of their subscription. This does not mean the new subscription is in effect immediately. See [Managing Subscriptions](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
-
+| Event Type | Default Event Name | Description | App Store | Play Store | Amazon | Stripe | Promo |
+| ------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ---------- | ------ | ------ | ----- |
+| Initial Purchase | `rc_initial_purchase_event` | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Started | `rc_trial_started_event` | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Converted | `rc_trial_converted_event` | When an auto-renewing subscription product converts from a free trial to normal paid period. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Cancelled | `rc_trial_cancelled_event` | When a user turns off renewals for an auto-renewing subscription product during a free trial period. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Renewal | `rc_renewal_event` | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Cancellation | `rc_cancellation_event` | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Uncancellation | `rc_uncancellation_event` | A non-expired cancelled subscription has been re-enabled. | ✅ | ✅ | ✅ | ❌ | ❌ |
+| Non Subscription Purchase | `rc_non_subscription_purchase_event` | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Subscription Paused | `rc_subscription_paused_event` | A subscription has been paused. | ❌ | ✅ | ❌ | ❌ | ❌ |
+| Expiration | `rc_expiration_event` | A subscription has expired and access should be removed. If you have [Platform Server Notifications](/platform-resources/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 | `rc_billing_issue_event` | 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 | `rc_product_change_event` | A subscriber has changed the product of their subscription. This does not mean the new subscription is in effect immediately. See [Managing Subscriptions](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
For events that have revenue, such as trial conversions and renewals, RevenueCat will automatically record this amount along with the event in Segment.
@@ -57,12 +57,13 @@ import swiftContent from "!!raw-loader!@site/code_blocks/integrations/third-part
import objectiveCContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/segment_2.m";
import javaContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/segment_3.java";
-
-
+
### 2. Generate a Segment Write Key
@@ -74,7 +75,7 @@ In Segment, add a HTTP API as a source and copy the Write Key.
After you've set up the _Purchases SDK_ and Segment SDK to have the same user identity, you can "turn on" the integration and configure the event names from the RevenueCat dashboard.
-1. Navigate to your project in the RevenueCat dashboard and find the _Integrations_ card in the left menu. Select **+ New**
+1. Navigate to your project in the RevenueCat dashboard and find the _Integrations_ card in the left menu. Select **+ New**

@@ -99,15 +100,17 @@ import renewalContent from "!!raw-loader!@site/code_blocks/integrations/third-pa
import cancellationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/segment_9.json";
import uncancellationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/segment_10.json";
-
+
import nonSubscriptionPurchaseContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/segment_11.json";
import subscriptionPausedContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/segment_12.json";
@@ -115,31 +118,41 @@ import expirationContent from "!!raw-loader!@site/code_blocks/integrations/third
import billingIssueContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/segment_14.json";
import productChangeContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/segment_15.json";
-
+
## Subscription Status Attribute
Whenever RevenueCat sends an event to Segment, we'll update the `rc_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](/dashboard-and-metrics/customer-history/promotionals) |
-| 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. |
+| 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](/dashboard-and-metrics/customer-history/promotionals) |
+| 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.
diff --git a/docs/integrations/third-party-integrations/slack.mdx b/docs/integrations/third-party-integrations/slack.mdx
index 21060fff6..02ae229c5 100644
--- a/docs/integrations/third-party-integrations/slack.mdx
+++ b/docs/integrations/third-party-integrations/slack.mdx
@@ -14,24 +14,24 @@ RevenueCat can send you Slack message to a channel any time an event happens in
### Integration at a Glance
| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
-| :--------------: | :-----------------------: | :-------------------: | :----------------------------: | :-------------------: | :------------------: |
-| ✅ | ❌ | Toggle on in Settings | ❌ | ❌ | ❌ |
+| :--------------: | :-----------------------: | :-------------------: | :--------------------------: | :-------------------: | :------------------: |
+| ✅ | ❌ | Toggle on in Settings | ❌ | ❌ | ❌ |
## Events
The Slack integration tracks the following events:
-| Event Type | Default Event Name (Fallback) | Description | App Store | Play Store | Amazon | Stripe | Promo |
-|----------------------|-------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|------------|--------|--------|-------|
-| Initial Purchase | Customer `` just started a subscription of `` | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Started | Customer `` just started a free trial of `` | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Converted | Customer `` just converted from a free trial of `` | When an auto-renewing subscription product converts from a free trial to normal paid period. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Trial Cancelled | Customer `` just cancelled their free trial of `` | When a user turns off renewals for an auto-renewing subscription product during a free trial period. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Renewal | Customer `` just renewed their subscription of `` | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Cancellation | Customer `` just cancelled their subscription of `` | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Non Subscription Purchase | Customer `` just purchased `` | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Billing Issue | Customer `` got a billing issue on `` | 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 | Customer `` got a product change from `` to `` | A subscriber has changed the product of their subscription. This does not mean the new subscription is in effect immediately. See [Managing Subscriptions](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
+| Event Type | Default Event Name (Fallback) | Description | App Store | Play Store | Amazon | Stripe | Promo |
+| ------------------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ---------- | ------ | ------ | ----- |
+| Initial Purchase | Customer `` just started a subscription of `` | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Started | Customer `` just started a free trial of `` | The start of an auto-renewing subscription product free trial. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Converted | Customer `` just converted from a free trial of `` | When an auto-renewing subscription product converts from a free trial to normal paid period. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Trial Cancelled | Customer `` just cancelled their free trial of `` | When a user turns off renewals for an auto-renewing subscription product during a free trial period. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Renewal | Customer `` just renewed their subscription of `` | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Cancellation | Customer `` just cancelled their subscription of `` | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Non Subscription Purchase | Customer `` just purchased `` | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Billing Issue | Customer `` got a billing issue on `` | 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 | Customer `` got a product change from `` to `` | A subscriber has changed the product of their subscription. This does not mean the new subscription is in effect immediately. See [Managing Subscriptions](/subscription-guidance/managing-subscriptions) for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
## Configure Slack Workspace
@@ -80,21 +80,29 @@ import trialCancelledContent from "!!raw-loader!@site/code_blocks/integrations/t
import renewalContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/slack_5.json";
import cancellationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/slack_6.json";
-
+
import nonSubscriptionPurchaseContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/slack_7.json";
import billingIssueContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/slack_8.json";
import productChangeContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/slack_9.json";
-
+
diff --git a/docs/integrations/third-party-integrations/statsig.mdx b/docs/integrations/third-party-integrations/statsig.mdx
index b0793045a..e109c46d1 100644
--- a/docs/integrations/third-party-integrations/statsig.mdx
+++ b/docs/integrations/third-party-integrations/statsig.mdx
@@ -22,24 +22,24 @@ With accurate and up-to-date subscription data in Statsig, you'll be set to turb
### Integration at a Glance
| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
-| :--------------: | :-----------------------: | :-------------------: | :----------------------------: | :-------------------: | :------------------: |
-| ✅ | ✅ | Toggle on in Settings | ✅ | ✅ | ❌ |
+| :--------------: | :-----------------------: | :-------------------: | :--------------------------: | :-------------------: | :------------------: |
+| ✅ | ✅ | Toggle on in Settings | ✅ | ✅ | ❌ |
## Events
The Statsig integration tracks the following events:
-| Event Type | Default Event Name | Description | App Store | Play Store | Amazon | Stripe | Promo |
-| ------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ---------- | ------ | ------ | ----- |
-| Initial Purchase | `rc_initial_purchase_event` | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Renewal | `rc_renewal_event` | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Cancellation | `rc_cancellation_event` | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Uncancellation | `rc_uncancellation_event` | A non-expired cancelled subscription has been re-enabled. | ✅ | ✅ | ✅ | ❌ | ❌ |
-| Non Subscription Purchase | `rc_non_subscription_purchase_event` | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
-| Subscription Paused | `rc_subscription_paused_event` | A subscription has been paused. | ❌ | ✅ | ❌ | ❌ | ❌ |
+| Event Type | Default Event Name | Description | App Store | Play Store | Amazon | Stripe | Promo |
+| ------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ---------- | ------ | ------ | ----- |
+| Initial Purchase | `rc_initial_purchase_event` | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Renewal | `rc_renewal_event` | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Cancellation | `rc_cancellation_event` | A subscription or non-renewing purchase has been cancelled. See [cancellation reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons) for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Uncancellation | `rc_uncancellation_event` | A non-expired cancelled subscription has been re-enabled. | ✅ | ✅ | ✅ | ❌ | ❌ |
+| Non Subscription Purchase | `rc_non_subscription_purchase_event` | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Subscription Paused | `rc_subscription_paused_event` | A subscription has been paused. | ❌ | ✅ | ❌ | ❌ | ❌ |
| Expiration | `rc_expiration_event` | A subscription has expired and access should be removed. If you have [Platform Server Notifications](/platform-resources/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 | `rc_billing_issue_event` | 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. | ✅ | ✅ | ✅ | ✅ | ❌ |
-| Transfer | `rc_transfer_event` | A transfer of transactions and entitlements was initiated between one App User ID(s) to another. Please note: Two events will be sent for each transfer, one for the original user and another for the destination user. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Billing Issue | `rc_billing_issue_event` | 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. | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Transfer | `rc_transfer_event` | A transfer of transactions and entitlements was initiated between one App User ID(s) to another. Please note: Two events will be sent for each transfer, one for the original user and another for the destination user. | ✅ | ✅ | ✅ | ✅ | ❌ |
## 0. Matching RevenueCat Users with Statsig Users
@@ -99,25 +99,37 @@ import uncancellationContent from "!!raw-loader!@site/code_blocks/integrations/t
import nonSubscriptionPurchaseContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/statsig_5.json";
import subscriptionPausedContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/statsig_6.json";
-
+
import expirationContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/statsig_7.json";
import billingIssueContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/statsig_8.json";
import productChangeContent from "!!raw-loader!@site/code_blocks/integrations/third-party-integrations/statsig_9.json";
-
+
:::success You've done it!
You should start seeing subscription data from RevenueCat appear in Statsig.
-:::
\ No newline at end of file
+:::
diff --git a/docs/integrations/third-party-integrations/telemetrydeck.mdx b/docs/integrations/third-party-integrations/telemetrydeck.mdx
index d6f952a63..391cf4496 100644
--- a/docs/integrations/third-party-integrations/telemetrydeck.mdx
+++ b/docs/integrations/third-party-integrations/telemetrydeck.mdx
@@ -15,7 +15,7 @@ TelemetryDeck can be a useful integration tool for seeing all events and revenue
| Includes Revenue | Supports Negative Revenue | Sends Sandbox Events | Includes Customer Attributes | Sends Transfer Events | Optional Event Types |
| :--------------: | :-----------------------: | :------------------: | :--------------------------: | :-------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------: |
-| ✅ | ✅ | ✅ | ✅ | ✅ | `non_subscription_purchase_event` `uncancellation_event` `subscription_paused_event` `expiration_event` `billing_issue_event` `product_change_event` |
+| ✅ | ✅ | ✅ | ✅ | ✅ | `non_subscription_purchase_event` `uncancellation_event` `subscription_paused_event` `expiration_event` `billing_issue_event` `product_change_event` |
## Setup
@@ -24,6 +24,7 @@ Please follow the instructions in [TelemetryDeck's documentation](https://teleme
### 1. Set TelemetryDeck User Identity
In order to associate RevenueCat data with a TelemetryDeck User, the following [Customer Attributes](/customers/customer-attributes) should be set in RevenueCat:
+
- `$telemetryDeckAppId`: This attribute should be set to your TelemetryDeck App ID, the same one you pass into the TelemetryDeck SDK for initialization.
- `$telemetryDeckUserId`: This attribute needs to be the already-hashed user identifier that TelemetryDeck is using.
@@ -37,7 +38,6 @@ After you've set up the Purchase SDK and TelemetryDeck SDK to have the same user
2. Choose **TelemetryDeck** from the Integrations menu
-
-3. Click **Add Integration**
+ 3. Click **Add Integration**
-That's it! No configuration is needed on the RevenueCat side.
\ No newline at end of file
+That's it! No configuration is needed on the RevenueCat side.
diff --git a/docs/integrations/webhooks/event-flows.md b/docs/integrations/webhooks/event-flows.md
index 94b1df3fa..17d1a4856 100644
--- a/docs/integrations/webhooks/event-flows.md
+++ b/docs/integrations/webhooks/event-flows.md
@@ -33,11 +33,12 @@ A customer can resubscribe to a subscription if they resume a subscription after
For resubscriptions on Google Play, Google may classify the transaction as a renewal rather than an initial purchase. While we typically mark a resubscription as an `INITIAL_PURCHASE`, there are cases where it may be marked as a `RENEWAL` based on the information provided by Google. This discrepancy is due to Google's timeframe and how they consider the transaction to either be marked as a renewal or an initial purchase.
-This can sometimes cause the customer history to appear out of order because we backdate the renewal to the effective renewal date on the customer dashboard however, the actual event will show the original time of the renewal in the `event_timestamp_ms` field.
+This can sometimes cause the customer history to appear out of order because we backdate the renewal to the effective renewal date on the customer dashboard however, the actual event will show the original time of the renewal in the `event_timestamp_ms` field.
+
- `RENEWAL`: If the resubscription occurs during the grace period before expiration.
- `INITIAL_PURCHASE`: If the resubscription occurs after the previous subscription has expired.
-
+
### Subscription Paused Flow (Android Only)
diff --git a/docs/integrations/webhooks/event-types-and-fields.mdx b/docs/integrations/webhooks/event-types-and-fields.mdx
index bcba0a586..cb0f3c29d 100644
--- a/docs/integrations/webhooks/event-types-and-fields.mdx
+++ b/docs/integrations/webhooks/event-types-and-fields.mdx
@@ -69,8 +69,8 @@ If we have to retry a webhook for any reason, the retry will have the same `id`
| `store` | String | Store the subscription belongs to. | `AMAZON`, `APP_STORE`, `MAC_APP_STORE`, `PLAY_STORE`, `PROMOTIONAL`, `STRIPE`. |
| `environment` | String | Store environment. | `SANDBOX`, `PRODUCTION`. |
| `is_trial_conversion` | Boolean | Only available for `RENEWAL` events. Whether the previous transaction was a free trial or not. | `true` or `false`. |
-| `cancel_reason` | String | Only available for `CANCELLATION` events. See [Cancellation and Expiration Reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons). | `UNSUBSCRIBE`, `BILLING_ERROR`, `DEVELOPER_INITIATED`, `PRICE_INCREASE`, `CUSTOMER_SUPPORT`, `UNKNOWN`. |
-| `expiration_reason` | String | Only available for `EXPIRATION` events. See [Cancellation and Expiration Reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons). | `UNSUBSCRIBE`, `BILLING_ERROR`, `DEVELOPER_INITIATED`, `PRICE_INCREASE`, `CUSTOMER_SUPPORT`, `UNKNOWN`. |
+| `cancel_reason` | String | Only available for `CANCELLATION` events. See [Cancellation and Expiration Reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons). | `UNSUBSCRIBE`, `BILLING_ERROR`, `DEVELOPER_INITIATED`, `PRICE_INCREASE`, `CUSTOMER_SUPPORT`, `UNKNOWN`. |
+| `expiration_reason` | String | Only available for `EXPIRATION` events. See [Cancellation and Expiration Reasons](/integrations/webhooks/event-types-and-fields#cancellation-and-expiration-reasons). | `UNSUBSCRIBE`, `BILLING_ERROR`, `DEVELOPER_INITIATED`, `PRICE_INCREASE`, `CUSTOMER_SUPPORT`, `UNKNOWN`. |
| `new_product_id` | String | Product identifier of the new product the subscriber has switched to. Only available for App Store subscriptions and `PRODUCT_CHANGE` events. | |
| `presented_offering_id` | String | Not available for apps using legacy entitlements. The identifier for the offering that was presented to the user during their initial purchase. Can be `NULL` if the purchase was made using `purchaseProduct` instead of `purchasePackage` or if the purchase was made outside of your app or before you integrated RevenueCat. | |
| `price` | Double | The USD price of the transaction. Can be `NULL` if the price is unknown, and `0` for free trials. Can be negative for refunds. | |
@@ -87,7 +87,7 @@ If we have to retry a webhook for any reason, the retry will have the same `id`
| `transferred_to` | String[] | This field is only available when `type` is set to `TRANSFER`. App User ID(s) that are receiving the transactions and entitlements taken from `transferred_from`. | |
| `country_code` | String | The ISO 3166 country code that the product was purchased in. The two-letter country code (e.g., US, GB, CA) of the app user's location (this country code is derived from the last seen request from the SDK for the subscriber.) | `US`, `CA`, etc. |
| `offer_code` | String | Not available when `type` is set to `SUBSCRIBER_ALIAS` or `TRANSFER`. The offer code that the customer used to redeem the transaction. Available for App Store and Play Store. For App Store this property corresponds to the [`offer_code_ref_name`](https://developer.apple.com/documentation/appstorereceipts/offer_code_ref_name). For Play Store this corresponds to the [`promotionCode`](https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.subscriptions). Can be null if no offer code was used for this product. | |
-| `renewal_number` | Integer | The number of renewals that this subscription has already gone through. Always starts at 1. Trial conversions are counted as renewals. `is_trial_conversion` is used to signify whether a transaction was a trial conversion. | |
+| `renewal_number` | Integer | The number of renewals that this subscription has already gone through. Always starts at 1. Trial conversions are counted as renewals. `is_trial_conversion` is used to signify whether a transaction was a trial conversion. | |
:::info
To get the RevenueCat event `id` from a Subscription Lifecycle webhook, simply make an API call to our GET `/subscribers`endpoint with the `app_user_id` after receiving the webhook and look for the latest purchase in the [subscription](https://www.revenuecat.com/reference/subscribers#the-subscription-object)/[non-subscription](https://www.revenuecat.com/reference/subscribers#the-non-subscription-object) object.
diff --git a/docs/integrations/webhooks/sample-events.mdx b/docs/integrations/webhooks/sample-events.mdx
index 438a127e2..bb979459e 100644
--- a/docs/integrations/webhooks/sample-events.mdx
+++ b/docs/integrations/webhooks/sample-events.mdx
@@ -4,6 +4,7 @@ slug: sample-events
excerpt: Example webhooks sent from RevenueCat
hidden: false
---
+
These are some representative samples of webhooks you might receive from RevenueCat. Keep in mind that webhooks can include additional fields to what's shown here.
import initialPurchaseContent from "!!raw-loader!@site/code_blocks/integrations/webhooks/sample-events_1.json";
@@ -13,15 +14,24 @@ import uncancellationContent from "!!raw-loader!@site/code_blocks/integrations/w
import nonRenewingPurchaseContent from "!!raw-loader!@site/code_blocks/integrations/webhooks/sample-events_5.json";
import subscriptionPausedContent from "!!raw-loader!@site/code_blocks/integrations/webhooks/sample-events_6.json";
-
-
+
import billingIssueContent from "!!raw-loader!@site/code_blocks/integrations/webhooks/sample-events_7.json";
import expirationContent from "!!raw-loader!@site/code_blocks/integrations/webhooks/sample-events_13.json";
@@ -30,22 +40,29 @@ import refundContent from "!!raw-loader!@site/code_blocks/integrations/webhooks/
import productChangeContent from "!!raw-loader!@site/code_blocks/integrations/webhooks/sample-events_10.json";
import subscriptionExtendedContent from "!!raw-loader!@site/code_blocks/integrations/webhooks/sample-events_14.json";
-
-
+
Here are some events you will see regarding trials:
import trialStartedContent from "!!raw-loader!@site/code_blocks/integrations/webhooks/sample-events_11.json";
import trialCancelledContent from "!!raw-loader!@site/code_blocks/integrations/webhooks/sample-events_12.json";
-
\ No newline at end of file
+
diff --git a/docs/migrating-to-revenuecat/migrating-existing-subscriptions.mdx b/docs/migrating-to-revenuecat/migrating-existing-subscriptions.mdx
index 480399d54..a0cfa3e5a 100644
--- a/docs/migrating-to-revenuecat/migrating-existing-subscriptions.mdx
+++ b/docs/migrating-to-revenuecat/migrating-existing-subscriptions.mdx
@@ -5,7 +5,7 @@ excerpt: How to migrate subscriptions from your existing setup
hidden: false
---
-Importing existing purchase data to RevenueCat can be done server-side, or client-side.
+Importing existing purchase data to RevenueCat can be done server-side, or client-side.
A server-side migration is preferable whenever possible because it ensures that all subscriptions will be recorded in RevenueCat regardless of any in-app activity, but if you don't have your existing purchase tokens or receipts stored, you can use a client-side migration.
@@ -35,19 +35,19 @@ The way to do this is: if your existing in-app purchase code knows that the cust
See the following pseudo example.
-
import content from "!!raw-loader!@site/code_blocks/migrating-to-revenuecat/migrating-existing-subscriptions_1.js";
-
+ type: "swift",
+ content: content,
+ },
+ ]}
+/>
When a customer launches with the first version containing RevenueCat it will trigger a sync. Once the sync is complete, it won't be triggered again.
:::warning Do not sync or restore on every app launch
It's okay to trigger a sync once per subscriber programmatically the first time they open a version of your app containing RevenueCat. You **should not** call this programmatically on every app launch for every user. This can increase latency in your app and can unintentionally alias customers together.
:::
-
diff --git a/docs/migrating-to-revenuecat/migrating-existing-subscriptions/receipt-imports.md b/docs/migrating-to-revenuecat/migrating-existing-subscriptions/receipt-imports.md
index 7277e857d..f7ebd2e40 100644
--- a/docs/migrating-to-revenuecat/migrating-existing-subscriptions/receipt-imports.md
+++ b/docs/migrating-to-revenuecat/migrating-existing-subscriptions/receipt-imports.md
@@ -15,7 +15,7 @@ Please note that depending on the size, bulk imports can take time to complete,
If you already have existing purchases or subscriptions and have been saving the complete raw receipt files or tokens, you can import those purchases into RevenueCat. If you don't have the proper data saved on your server, see the client-side migration section of the [Migrating Subscriptions](/migrating-to-revenuecat/migrating-existing-subscriptions) doc.
-Before kicking off an import, it's important that new purchases are being forwarded. This can be achieved by integrating the SDK or forwarding receipts/purchase tokens from your backend via our REST API.
+Before kicking off an import, it's important that new purchases are being forwarded. This can be achieved by integrating the SDK or forwarding receipts/purchase tokens from your backend via our REST API.
:::info Bulk imports DO NOT trigger webhooks or integrations
Bulk imports done by RevenueCat will not trigger any webhook or integration events. If this is a requirement, then you'll need to perform an import using the REST API as mentioned above.
@@ -26,6 +26,7 @@ Bulk imports done by RevenueCat will not trigger any webhook or integration even
To do a receipt import we'll need a CSV file for each of the stores you want to import data from (Apple App Store, Google Play Store, Stripe). The CSV needs to contain the columns outlined below.
=======
+
#### Apple App Store
- app_user_id
diff --git a/docs/migrating-to-revenuecat/migration-paths.mdx b/docs/migrating-to-revenuecat/migration-paths.mdx
index 744a4bc71..4cf0dd1e3 100644
--- a/docs/migrating-to-revenuecat/migration-paths.mdx
+++ b/docs/migrating-to-revenuecat/migration-paths.mdx
@@ -36,7 +36,7 @@ Level up your data, marketing, and product teams be sending actionable events in
### Connect to a store and set up Server Notifications (required)
-You can start populating data in RevenueCat with minimal effort by connecting to a store and setting up Server Notifications.
+You can start populating data in RevenueCat with minimal effort by connecting to a store and setting up Server Notifications.
By toggling 'Track new purchases' in your RevenueCat app settings, RevenueCat will automatically start tracking new purchases that we receive from the connected store, with no SDK implementation required.
@@ -50,10 +50,10 @@ Read our [Migrating Existing Subscriptions](/migrating-to-revenuecat/migrating-e
### Integrate the RevenueCat SDK (optional)
-RevenueCat's SDK provides powerful features like Paywalls, Experiments, and Targeting. If you're looking to take advantage of these features, you'll need to integrate the RevenueCat SDK into your app. Get started with our [Installing the SDK](/getting-started/installation) guide.
+RevenueCat's SDK provides powerful features like Paywalls, Experiments, and Targeting. If you're looking to take advantage of these features, you'll need to integrate the RevenueCat SDK into your app. Get started with our [Installing the SDK](/getting-started/installation) guide.
_Not sure if you need the SDK? Read our [SDK or Not](/migrating-to-revenuecat/sdk-or-not) guide to learn more about the benefits of the SDK._
#### Use existing purchase code
-Do you have existing purchase code that you'd like to keep? No problem - RevenueCat's SDK can detect purchases made with your existing code, without needing to migrate your purchase logic. [Read more](/migrating-to-revenuecat/sdk-or-not/finishing-transactions) about how to finish transactions with your existing code.
\ No newline at end of file
+Do you have existing purchase code that you'd like to keep? No problem - RevenueCat's SDK can detect purchases made with your existing code, without needing to migrate your purchase logic. [Read more](/migrating-to-revenuecat/sdk-or-not/finishing-transactions) about how to finish transactions with your existing code.
diff --git a/docs/migrating-to-revenuecat/sdk-or-not.mdx b/docs/migrating-to-revenuecat/sdk-or-not.mdx
index e3a69df52..f12602ff6 100644
--- a/docs/migrating-to-revenuecat/sdk-or-not.mdx
+++ b/docs/migrating-to-revenuecat/sdk-or-not.mdx
@@ -1,10 +1,11 @@
---
title: Do I need the SDK?
slug: sdk-or-not
-excerpt: Determining whether or not you need to integrate the RevenueCat SDK
+excerpt: Determining whether or not you need to integrate the RevenueCat SDK
hidden: false
---
-If you have an existing app with in-app purchases and you want to use RevenueCat, you can decide whether or not to implement the RevenueCat SDK. For new apps, or existing apps that have not yet implemented in-app purchases, we recommend integrating the SDK for access to all RevenueCat features and the most seamless experience.
+
+If you have an existing app with in-app purchases and you want to use RevenueCat, you can decide whether or not to implement the RevenueCat SDK. For new apps, or existing apps that have not yet implemented in-app purchases, we recommend integrating the SDK for access to all RevenueCat features and the most seamless experience.
To start with RevenueCat with an app that already supports in-app purchases, you can use the following information to determine whether you should implement one of our Mobile or Web SDKs:
@@ -12,14 +13,15 @@ To start with RevenueCat with an app that already supports in-app purchases, you
If you want to make use of RevenueCat to streamline your purchasing logic, remotely control and test paywalls, pricing and packaging, or deliver targeted offers to customers, you will need to **integrate one of our [SDKs](/getting-started/installation)**. Integrating the SDK requires shipping an updated version of your mobile or web app.
-The following RevenueCat features *require an SDK to be integrated*:
-* [Remotely configuring your product catalog](/getting-started/entitlements)
-* Remotely configuring [paywall templates](/tools/paywalls) and [other aspects of your app](/tools/offering-metadata)
-* [Experiments](/tools/experiments-v1) to A/B test pricing, packaging, and other monetization related aspects of your app
-* [Targeting](/tools/targeting) different segments of customers with specific offerings
-* [Apple Search Ads attribution](/integrations/attribution/apple-search-ads)
-* [Replacing your in-app purchase logic with RevenueCat](/getting-started/quickstart#4-using-revenuecats-purchases-sdk) to reduce ongoing engineering effort
-* [Supporting your customers automatically with Customer Center](/tools/customer-center)
+The following RevenueCat features _require an SDK to be integrated_:
+
+- [Remotely configuring your product catalog](/getting-started/entitlements)
+- Remotely configuring [paywall templates](/tools/paywalls) and [other aspects of your app](/tools/offering-metadata)
+- [Experiments](/tools/experiments-v1) to A/B test pricing, packaging, and other monetization related aspects of your app
+- [Targeting](/tools/targeting) different segments of customers with specific offerings
+- [Apple Search Ads attribution](/integrations/attribution/apple-search-ads)
+- [Replacing your in-app purchase logic with RevenueCat](/getting-started/quickstart#4-using-revenuecats-purchases-sdk) to reduce ongoing engineering effort
+- [Supporting your customers automatically with Customer Center](/tools/customer-center)
:::info Using the RevenueCat SDK alongside your existing logic
If you have existing code to handle in-app purchases and you want to start using some RevenueCat features but not replace all of your existing code, you can always use RevenueCat alongside your existing code and selectively use RevenueCat features. [Read more about how to set up the RevenueCat SDK alongside your existing IAP code](/migrating-to-revenuecat/sdk-or-not/finishing-transactions).
@@ -27,20 +29,17 @@ If you have existing code to handle in-app purchases and you want to start using
[Follow our quickstart guide to learn how to integrate the SDK →](/getting-started/quickstart)
-
## Integrating without using the SDK
-If you are planning on using RevenueCat mostly to collect and analyze accurate and actionable purchase data, you may choose a **server-side integration**. The following RevenueCat features work *without implementing the SDK*:
-* [Charts](/dashboard-and-metrics/charts)
-* [Customer history](/dashboard-and-metrics/customer-history)
-* [Customer lists](/dashboard-and-metrics/customer-lists)
-* [Purchase lifecycle events](/integrations/integrations), [webhooks](/integrations/webhooks), and [integrations with third party tools](/integrations/third-party-integrations)
-* [Scheduled data exports](/integrations/scheduled-data-exports) to your data warehouse
-* [Checking customer entitlements via the REST API](/customers/customer-info#getting-subscription-status-via-the-rest-api)
+If you are planning on using RevenueCat mostly to collect and analyze accurate and actionable purchase data, you may choose a **server-side integration**. The following RevenueCat features work _without implementing the SDK_:
+
+- [Charts](/dashboard-and-metrics/charts)
+- [Customer history](/dashboard-and-metrics/customer-history)
+- [Customer lists](/dashboard-and-metrics/customer-lists)
+- [Purchase lifecycle events](/integrations/integrations), [webhooks](/integrations/webhooks), and [integrations with third party tools](/integrations/third-party-integrations)
+- [Scheduled data exports](/integrations/scheduled-data-exports) to your data warehouse
+- [Checking customer entitlements via the REST API](/customers/customer-info#getting-subscription-status-via-the-rest-api)
You can always start with a server-side integration without the SDK, and add the SDK later. In the case where purchases are made through the SDK and also sent on the server side, RevenueCat will automatically deduplicate them, so there is no risk in this approach.
[Read more about using RevenueCat without the SDK →](/migrating-to-revenuecat/sdk-or-not/sdk-less-integration)
-
-
-
diff --git a/docs/migrating-to-revenuecat/sdk-or-not/sdk-less-integration.mdx b/docs/migrating-to-revenuecat/sdk-or-not/sdk-less-integration.mdx
index fa0624eb0..5935083b9 100644
--- a/docs/migrating-to-revenuecat/sdk-or-not/sdk-less-integration.mdx
+++ b/docs/migrating-to-revenuecat/sdk-or-not/sdk-less-integration.mdx
@@ -14,7 +14,7 @@ You can always start with a no-code integration, and add the SDK later. In the c
## No-code, or server-side integration
RevenueCat can automatically detect purchases by enabling "Track new purchases" in your RevenueCat app settings after enabling [Server Notifications](/platform-resources/server-notifications). This will automatically start tracking purchases that we receive from a connected store or app, with no SDK implementation required. Read more about [how to connect to a store](/projects/connect-a-store) and start tracking new purchases from Server Notifications.
-
+
If you want to manually send purchases to RevenueCat, you can do so by sending receipts and/or purchase tokens to the `POST /receipts` [REST API endpoint](/api-v1#tag/transactions/operation/receipts). This will create the customer in RevenueCat, RevenueCat will validate the purchase and keep the purchase status up-to-date.
## Using RevenueCat without the SDK
@@ -33,4 +33,4 @@ If you are planning on using RevenueCat integrations with third party tools, ple
Even if you don't use the SDK, you can use RevenueCat as your source of the truth for subscription and entitlement status. To do so, start by setting up [products and entitlements in RevenueCat](/getting-started/entitlements), and then use the `GET /subscribers/{app_user_id}` [REST API endpoint](/api-v1#tag/customers) to access information about a customer's subscriptions, purchases, and entitlements.
-Alternatively, if you prefer to keep a copy of a customer's purchase and entitlement status in your own database, you can also listen to RevenueCat's [webhooks](/integrations/webhooks) to update your database whenever there is a new or updated purchase.
\ No newline at end of file
+Alternatively, if you prefer to keep a copy of a customer's purchase and entitlement status in your own database, you can also listen to RevenueCat's [webhooks](/integrations/webhooks) to update your database whenever there is a new or updated purchase.
diff --git a/docs/migrating-to-revenuecat/swiftystorekit.mdx b/docs/migrating-to-revenuecat/swiftystorekit.mdx
index a15926747..128c2cfd8 100644
--- a/docs/migrating-to-revenuecat/swiftystorekit.mdx
+++ b/docs/migrating-to-revenuecat/swiftystorekit.mdx
@@ -21,26 +21,29 @@ Apple recommends registering an `SKPaymentTransactionObserver` as soon as the ap
**SwiftyStoreKit:**
-
import ssk_1 from "!!raw-loader!@site/code_blocks/migrating-to-revenuecat/swiftystorekit_1.swift";
-
+ type: "swift",
+ content: ssk_1,
+ },
+ ]}
+/>
**RevenueCat:**
import ssk_2 from "!!raw-loader!@site/code_blocks/migrating-to-revenuecat/swiftystorekit_2.swift";
-
+ type: "swift",
+ content: ssk_2,
+ },
+ ]}
+/>
**Migration Steps:**
Remove the SwiftyStoreKit `completeTransactions()` method, and replace it with the _Purchases SDK_ `configure()` method.
@@ -55,23 +58,27 @@ Remove the SwiftyStoreKit `completeTransactions()` method, and replace it with t
import ssk_3 from "!!raw-loader!@site/code_blocks/migrating-to-revenuecat/swiftystorekit_3.swift";
-
+ type: "swift",
+ content: ssk_3,
+ },
+ ]}
+/>
**RevenueCat:**
import ssk_4 from "!!raw-loader!@site/code_blocks/migrating-to-revenuecat/swiftystorekit_4.swift";
-
+ type: "swift",
+ content: ssk_4,
+ },
+ ]}
+/>
**Migration Steps:**
In RevenueCat, Offerings are [configured in the dashboard](/getting-started/entitlements), and mapped to `SKProduct`s. Once you setup your products in RevenueCat, replace `retrieveProductsInfo()` in SwiftyStoreKit with `offerings()` in _Purchases SDK_.
@@ -84,23 +91,27 @@ Products are automatically fetched and cached when the _Purchases SDK_ is config
import ssk_5 from "!!raw-loader!@site/code_blocks/migrating-to-revenuecat/swiftystorekit_5.swift";
-
+ type: "swift",
+ content: ssk_5,
+ },
+ ]}
+/>
**RevenueCat:**
import ssk_6 from "!!raw-loader!@site/code_blocks/migrating-to-revenuecat/swiftystorekit_6.swift";
-
+ type: "swift",
+ content: ssk_6,
+ },
+ ]}
+/>
**Migration Steps:**
In SwiftyStoreKit, purchases can be initiated from a product Id or an `SKProduct`. In _Purchases SDK_ the preferred method is to provide a package to purchase. Replace the `purchaseProduct()` method in SwiftyStoreKit with `purchase(package:)`, and pass the package that was included with the RevenueCat Offering.
@@ -115,23 +126,27 @@ To check if the subscription has been successfully activated, check if the `cust
import ssk_7 from "!!raw-loader!@site/code_blocks/migrating-to-revenuecat/swiftystorekit_7.swift";
-
+ type: "swift",
+ content: ssk_7,
+ },
+ ]}
+/>
**RevenueCat:**
import ssk_8 from "!!raw-loader!@site/code_blocks/migrating-to-revenuecat/swiftystorekit_8.swift";
-
+ type: "swift",
+ content: ssk_8,
+ },
+ ]}
+/>
**Migration Steps:**
RevenueCat handles purchases initiated through the App Store with an optional delegate method. Replace the `shouldAddStorePaymentHandler` in SwiftyStoreKit with the `shouldPurchasePromoProduct` in _Purchases SDK_.
@@ -144,23 +159,27 @@ With _Purchases SDK_ you have the option of deferring the purchase until a later
import ssk_9 from "!!raw-loader!@site/code_blocks/migrating-to-revenuecat/swiftystorekit_9.swift";
-
+ type: "swift",
+ content: ssk_9,
+ },
+ ]}
+/>
**RevenueCat:**
import ssk_10 from "!!raw-loader!@site/code_blocks/migrating-to-revenuecat/swiftystorekit_10.swift";
-
+ type: "swift",
+ content: ssk_10,
+ },
+ ]}
+/>
**Migration Steps:**
The _Purchases SDK_ has a similar method to SwiftyStoreKit to restore transactions - replace `restorePurchases()` in SwiftyStoreKit with `restoreTransactions()`. To check if the subscription has been restored, check if the `customerInfo` object contains an active entitlement for the "pro" content you configured in the RevenueCat dashboard.
@@ -177,23 +196,27 @@ Receipts are automatically verified by RevenueCat. You don't need any local or s
import ssk_11 from "!!raw-loader!@site/code_blocks/migrating-to-revenuecat/swiftystorekit_11.swift";
-
+ type: "swift",
+ content: ssk_11,
+ },
+ ]}
+/>
**RevenueCat:**
import ssk_12 from "!!raw-loader!@site/code_blocks/migrating-to-revenuecat/swiftystorekit_12.swift";
-
+ type: "swift",
+ content: ssk_12,
+ },
+ ]}
+/>
**Migration Steps:**
RevenueCat keeps a subscribers status up-to-date on the server and shares this information with the _Purchases SDK_ to determine what subscriptions are active for the current user.
diff --git a/docs/platform-resources/amazon-platform-resources.md b/docs/platform-resources/amazon-platform-resources.mdx
similarity index 90%
rename from docs/platform-resources/amazon-platform-resources.md
rename to docs/platform-resources/amazon-platform-resources.mdx
index a916b75c3..df870ed68 100644
--- a/docs/platform-resources/amazon-platform-resources.md
+++ b/docs/platform-resources/amazon-platform-resources.mdx
@@ -22,13 +22,15 @@ When the SDK is configured to not complete purchases on the Amazon Appstore, `sy
import om7 from "!!raw-loader!@site/code_blocks/migrating-to-revenuecat/observer-mode_7.cs";
import om8 from "!!raw-loader!@site/code_blocks/migrating-to-revenuecat/observer-mode_8.kt";
-
\ No newline at end of file
+ ]}
+/>
diff --git a/docs/platform-resources/apple-platform-resources/handling-refund-requests.md b/docs/platform-resources/apple-platform-resources/handling-refund-requests.md
index 7c3383f43..2d24f861b 100644
--- a/docs/platform-resources/apple-platform-resources/handling-refund-requests.md
+++ b/docs/platform-resources/apple-platform-resources/handling-refund-requests.md
@@ -4,16 +4,18 @@ slug: handling-refund-requests
hidden: false
---
-The Apple App Store evaluates several factors when deciding whether to approve or deny your customer's refund request. RevenueCat can help influence this process by providing Apple additional data about your customer's consumption of the purchase, along with your preferred resolution at the time of their refund request. Apple will use this information to help inform their refund decisions.
+The Apple App Store evaluates several factors when deciding whether to approve or deny your customer's refund request. RevenueCat can help influence this process by providing Apple additional data about your customer's consumption of the purchase, along with your preferred resolution at the time of their refund request. Apple will use this information to help inform their refund decisions.
RevenueCat charges no extra fees for refund request handling. For additional insights in your refund requests, check out our [App Store Refund Requests Chart](/dashboard-and-metrics/charts/app-store-refund-requests-chart).
## Prerequisites
-In order for RevenueCat to be notified of refund requests, you must have Apple App Store Server Notifications configured. If you do not have this set up yet, follow our setup instructions [here](/platform-resources/server-notifications/apple-server-notifications).
+
+In order for RevenueCat to be notified of refund requests, you must have Apple App Store Server Notifications configured. If you do not have this set up yet, follow our setup instructions [here](/platform-resources/server-notifications/apple-server-notifications).
Regardless of if you're on V1 or V2 of Apple App Store Server Notifications, RevenueCat supports both versions and we will be able to detect refund requests from Apple. For the best reliability, we recommend using V2 of the notifications.
## Handling of Refund Requests
+
To allow RevenueCat to send additional data of your customer's purchases to Apple, navigate to your RevenueCat app settings page and expand the **"Handling of refund requests"** section.

@@ -21,6 +23,7 @@ To allow RevenueCat to send additional data of your customer's purchases to Appl
The dropdown selector under **"Refund requests handling preference"** allows you to choose your preferred outcome for the refund request. Note that your refund preference is one of the several factors that Apple will use to inform its refund decisions.
For all refund requests, you can select from the following options:
+
- **Do not handle**: RevenueCat will not respond to Apple's refund request on your behalf.
- **Always prefer granting refunds**: You prefer that Apple grants the refund.
- **Always prefer declining refunds**: You prefer that Apple declines the refund.
@@ -29,9 +32,11 @@ For all refund requests, you can select from the following options:
Choose the option that best fits the majority of your use cases.
### Overriding refund preference
+
If, for example, you chose "Always prefer declining refunds", but have a specific customer or certain conditions under which you'd prefer Apple to grant a refund, you can override this preference before your customer submits their refund request directly to Apple.
To do so, you can use RevenueCat's [customer attributes](/customers/customer-attributes) to set a specific preference for any customer. RevenueCat provides a reserved customer attribute field, `$appleRefundHandlingPreference`, where you can set values such as:
+
- `DO_NOT_HANDLE`: Refund requests will not be handled for this customer. You can use this option to disable the feature for customers that have not provided consent.
- `GRANT_REFUND`: You prefer that Apple grants the refund for this customer.
- `DECLINE_REFUND`: You prefer that Apple declines the refund for this customer.
@@ -46,6 +51,7 @@ Overriding the customer's refund preference will only apply if you have enabled
:::
### Obtaining customer consent
+
By enabling this feature, you confirm that you have obtained consent from your customers to share their consumption data with Apple.
Here's a template to help get you started:
@@ -59,22 +65,23 @@ For general guidelines from Apple, visit their [documentation](https://developer
If you have a use case where you only update your Terms & Conditions (or an equivalent document) for new customers, while existing customers remain on the original terms, contact [RevenueCat support](https://app.revenuecat.com/settings/support) for assistance.
## Data RevenueCat sends to Apple
+
Below are the [properties](https://developer.apple.com/documentation/appstoreserverapi/consumptionrequest) and data that RevenueCat will send to Apple when a refund request comes in.
-| Property | Description | What RevenueCat sends |
-|----------------------------|-----------------------------|------------------------------------------|
-| accountTenure | The age of the customer’s account. |
If customer exists in RC: Calculate age based on the creation date of that customer and assess the [range](https://developer.apple.com/documentation/appstoreserverapi/accounttenure).
If customer does not exist in RC: 0 (*undeclared*)
|
-| appAccountToken | The optionally UUID of the in-app user account that completed the in-app purchase transaction. | Empty string |
-| consumptionStatus | A value that indicates the extent to which the customer consumed the in-app purchase. | 0 (*undeclared*) |
-| customerConsented | A Boolean value of true or false that indicates whether the customer consented to provide consumption data. | true, by turning this on this functionality, we assume you are asking your customers for consent. |
-| deliveryStatus | A value that indicates whether the app successfully delivered an in-app purchase that works properly. |
If the transaction exists in RC: 0 (*The app delivered the consumable in-app purchase and it’s working properly.*)
If the transaction does not exist in RC: 5 (*The app didn’t deliver the consumable in-app purchase for other reasons.*)
|
-| lifetimeDollarsPurchased | A value that indicates the total amount, in USD, of in-app purchases the customer has made in your app, across all platforms. | Calculate the total of non-refunded transactions in USD and assess the [range](https://developer.apple.com/documentation/appstoreserverapi/lifetimedollarspurchased). |
-| lifetimeDollarsRefunded | A value that indicates the total amount, in USD, of refunds the customer has received, in your app, across all platforms. | Calculate the total of refunded transactions in USD and assess the [range](https://developer.apple.com/documentation/appstoreserverapi/lifetimedollarsrefunded). |
-| platform | A value that indicates the platform on which the customer consumed the in-app purchase. |
If your customer only has transactions from the App Store: 1 (*An Apple platform*)
If your customer has transactions from multiple stores: 0 (*undeclared*)
|
-| playTime | A value that indicates the amount of time that the customer used the app. | 0 (*undeclared*) |
-| refundPreference | A value that indicates your preference, based on your operational logic, as to whether Apple should grant the refund. |
The value for your customer's reserved customer attribute `$appleRefundHandlingPreference`
Otherwise, we will fall back to the option you chose in the dropdown selector
|
-| sampleContentProvided | A Boolean value of true or false that indicates whether you provided, prior to its purchase, a free sample or trial of the content, or information about its functionality. | true |
-| userStatus | The status of the customer’s account. |
If the transaction exists in RC: 1 (*The customer’s account is active.*)
If the transaction does not exist in RC: 0 (*undeclared*)
|
+| Property | Description | What RevenueCat sends |
+| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| accountTenure | The age of the customer’s account. |
If customer exists in RC: Calculate age based on the creation date of that customer and assess the [range](https://developer.apple.com/documentation/appstoreserverapi/accounttenure).
If customer does not exist in RC: 0 (_undeclared_)
|
+| appAccountToken | The optionally UUID of the in-app user account that completed the in-app purchase transaction. | Empty string |
+| consumptionStatus | A value that indicates the extent to which the customer consumed the in-app purchase. | 0 (_undeclared_) |
+| customerConsented | A Boolean value of true or false that indicates whether the customer consented to provide consumption data. | true, by turning this on this functionality, we assume you are asking your customers for consent. |
+| deliveryStatus | A value that indicates whether the app successfully delivered an in-app purchase that works properly. |
If the transaction exists in RC: 0 (_The app delivered the consumable in-app purchase and it’s working properly._)
If the transaction does not exist in RC: 5 (_The app didn’t deliver the consumable in-app purchase for other reasons._)
|
+| lifetimeDollarsPurchased | A value that indicates the total amount, in USD, of in-app purchases the customer has made in your app, across all platforms. | Calculate the total of non-refunded transactions in USD and assess the [range](https://developer.apple.com/documentation/appstoreserverapi/lifetimedollarspurchased). |
+| lifetimeDollarsRefunded | A value that indicates the total amount, in USD, of refunds the customer has received, in your app, across all platforms. | Calculate the total of refunded transactions in USD and assess the [range](https://developer.apple.com/documentation/appstoreserverapi/lifetimedollarsrefunded). |
+| platform | A value that indicates the platform on which the customer consumed the in-app purchase. |
If your customer only has transactions from the App Store: 1 (_An Apple platform_)
If your customer has transactions from multiple stores: 0 (_undeclared_)
|
+| playTime | A value that indicates the amount of time that the customer used the app. | 0 (_undeclared_) |
+| refundPreference | A value that indicates your preference, based on your operational logic, as to whether Apple should grant the refund. |
The value for your customer's reserved customer attribute `$appleRefundHandlingPreference`
Otherwise, we will fall back to the option you chose in the dropdown selector
|
+| sampleContentProvided | A Boolean value of true or false that indicates whether you provided, prior to its purchase, a free sample or trial of the content, or information about its functionality. | true |
+| userStatus | The status of the customer’s account. |
If the transaction exists in RC: 1 (_The customer’s account is active._)
If the transaction does not exist in RC: 0 (_undeclared_)
|
:::info Share your feedback
If you have any feedback about this feature, please reach out to our [RevenueCat support](https://app.revenuecat.com/settings/support) and we'll be happy to discuss your feedback or feature request!
diff --git a/docs/platform-resources/apple-platform-resources/legacy-mac-apps.mdx b/docs/platform-resources/apple-platform-resources/legacy-mac-apps.mdx
index f0eb93891..f5993b198 100644
--- a/docs/platform-resources/apple-platform-resources/legacy-mac-apps.mdx
+++ b/docs/platform-resources/apple-platform-resources/legacy-mac-apps.mdx
@@ -36,15 +36,16 @@ If you are going to add an iOS app, enter the iOS/universal Mac app's bundle ID
This step is only required if you have both a legacy Mac app and an iOS/universal Mac app. In the **universal Mac app**, add this line of code right before `Purchases.configure`:
-
import content1 from "!!raw-loader!@site/code_blocks/platform-resources/legacy-mac-apps_1.swift";
-
+ type: "swift",
+ content: content1,
+ },
+ ]}
+/>
:::tip You're done 🎉
You've successfully configured your Mac app in RevenueCat!
diff --git a/docs/platform-resources/apple-platform-resources/swiftui-helpers.mdx b/docs/platform-resources/apple-platform-resources/swiftui-helpers.mdx
index 1eaa0e851..9c177c772 100644
--- a/docs/platform-resources/apple-platform-resources/swiftui-helpers.mdx
+++ b/docs/platform-resources/apple-platform-resources/swiftui-helpers.mdx
@@ -13,15 +13,16 @@ The Purchases SDK includes a debug overlay that allows developers to see various
SwiftUI Previews allow developers to preview their views directly in Xcode without building and running your app. The Purchases SDK includes convenience types for displaying mock products and offerings to avoid having to build and run your app to test your paywall.
-
import content1 from "!!raw-loader!@site/code_blocks/platform-resources/swiftui-app-lifecycle_1.swift";
-
+ type: "swift",
+ content: content1,
+ },
+ ]}
+/>
## SDK Initialization
@@ -33,12 +34,14 @@ For basic initialization without delegate methods, you can implement the App `in
import content2 from "!!raw-loader!@site/code_blocks/platform-resources/swiftui-app-lifecycle_2.swift";
-
+ type: "swift",
+ content: content2,
+ },
+ ]}
+/>
### Option 2: App Delegate
@@ -46,16 +49,18 @@ Another method of initialization is to use the `@UIApplicationDelegateAdaptor` p
#### Creating a Delegate
-Begin by creating a delegate class and initializing the *Purchases* SDK like the following:
+Begin by creating a delegate class and initializing the _Purchases_ SDK like the following:
import content3 from "!!raw-loader!@site/code_blocks/platform-resources/swiftui-app-lifecycle_3.swift";
-
+ type: "swift",
+ content: content3,
+ },
+ ]}
+/>
#### Attaching the Delegate
@@ -63,13 +68,15 @@ As previously mentioned, the new `@UIApplicationDelegateAdaptor` property attach
import content4 from "!!raw-loader!@site/code_blocks/platform-resources/swiftui-app-lifecycle_4.swift";
-
+ type: "swift",
+ content: content4,
+ },
+ ]}
+/>
-Build and run the app, and *Purchases* will be initialized on app launch.
+Build and run the app, and _Purchases_ will be initialized on app launch.
For more information on configuring the SDK, check out the [Configuring SDK](/getting-started/configuring-sdk) guide.
diff --git a/docs/platform-resources/developer-store-payments.md b/docs/platform-resources/developer-store-payments.md
index a4690013c..2d28773df 100644
--- a/docs/platform-resources/developer-store-payments.md
+++ b/docs/platform-resources/developer-store-payments.md
@@ -7,31 +7,31 @@ hidden: false
## How do you receive your revenue from purchases?
-As RevenueCat is not the payment processor when your customers make a purchase, you will receive the revenue generated from the purchases from the stores themselves. Apple, Google, Amazon, and Stripe will take a percentage of the revenue as payment for their services before sending the remaining portion to your account. Depending on the store and the country where you are based, different rules may be applied to your revenue.
+As RevenueCat is not the payment processor when your customers make a purchase, you will receive the revenue generated from the purchases from the stores themselves. Apple, Google, Amazon, and Stripe will take a percentage of the revenue as payment for their services before sending the remaining portion to your account. Depending on the store and the country where you are based, different rules may be applied to your revenue.
## Instructions on Setting up Your Payment Information
In order to receive these payments from the stores, you will need to provide them with your banking information through their developer portals.
- - Apple App Store: [Entering Banking Information](https://developer.apple.com/help/app-store-connect/manage-banking-information/enter-banking-information)
- - Google Play Store: [Create a Payments Profile](https://support.google.com/paymentscenter/answer/7161426?hl=en)
- - Stripe: [Add a Bank Account for Payouts](https://support.stripe.com/questions/add-a-bank-account-for-payouts)
- - Amazon App Store: [How to get paid on the Amazon Appstore](https://developer.amazon.com/apps-and-games/blogs/2024/06/getting-paid-on-amazon-appstore)
+- Apple App Store: [Entering Banking Information](https://developer.apple.com/help/app-store-connect/manage-banking-information/enter-banking-information)
+- Google Play Store: [Create a Payments Profile](https://support.google.com/paymentscenter/answer/7161426?hl=en)
+- Stripe: [Add a Bank Account for Payouts](https://support.stripe.com/questions/add-a-bank-account-for-payouts)
+- Amazon App Store: [How to get paid on the Amazon Appstore](https://developer.amazon.com/apps-and-games/blogs/2024/06/getting-paid-on-amazon-appstore)
## When will you receive your revenue?
Apple, Google, Amazon, and Stripe all distribute payments according to their own schedules. You can find the timeline for each of these stores in the documentation below:
- - Apple App Store: [Payment Days on Apple's Fiscal Calendar](https://www.revenuecat.com/blog/growth/apple-fiscal-calendar-year-payment-dates/)
- - Google Play Store: [Monthly Payouts and Reporting](https://support.google.com/googleplay/android-developer/answer/137997)
- - Stripe: [Payout Schedule](https://docs.stripe.com/payouts#payout-schedule)
- - Amazon App Store: [Receiving Payments](https://developer.amazon.com/docs/reports-promo/payments-understand.html#receiving-payments)
+- Apple App Store: [Payment Days on Apple's Fiscal Calendar](https://www.revenuecat.com/blog/growth/apple-fiscal-calendar-year-payment-dates/)
+- Google Play Store: [Monthly Payouts and Reporting](https://support.google.com/googleplay/android-developer/answer/137997)
+- Stripe: [Payout Schedule](https://docs.stripe.com/payouts#payout-schedule)
+- Amazon App Store: [Receiving Payments](https://developer.amazon.com/docs/reports-promo/payments-understand.html#receiving-payments)
## Country Availability
The country availability of RevenueCat is based on the availability of in-app purchases for each of the individual app stores. We support all countries that are supported by the different stores. The availability of in-app purchases by app store are listed below:
-
- - Apple App Store: [Availability of Apple Media Services](https://support.apple.com/en-us/118205)
- - Google Play Store: [Supported locations for distribution to Google Play users](https://play.google.com/supported-locations/?hl=en&sjid=15964040598086024356-NA)
- - Amazon App Store: [Countries & Territories Eligible to Shop for Apps](https://www.amazon.com/gp/help/customer/display.html?nodeId=GSXRFWKVKXYMK8GS)
- - Stripe: [Global availability](https://stripe.com/global)
+
+- Apple App Store: [Availability of Apple Media Services](https://support.apple.com/en-us/118205)
+- Google Play Store: [Supported locations for distribution to Google Play users](https://play.google.com/supported-locations/?hl=en&sjid=15964040598086024356-NA)
+- Amazon App Store: [Countries & Territories Eligible to Shop for Apps](https://www.amazon.com/gp/help/customer/display.html?nodeId=GSXRFWKVKXYMK8GS)
+- Stripe: [Global availability](https://stripe.com/global)
diff --git a/docs/platform-resources/google-platform-resources/reduced-service-fee.md b/docs/platform-resources/google-platform-resources/reduced-service-fee.md
index a87bf9abf..da1e063d6 100644
--- a/docs/platform-resources/google-platform-resources/reduced-service-fee.md
+++ b/docs/platform-resources/google-platform-resources/reduced-service-fee.md
@@ -4,13 +4,14 @@ slug: 15-reduced-service-fee
excerpt: How to have the reduced commission rate reflected in RevenueCat
hidden: false
---
+
Google allows developers that earn less than $1,000,000 USD per year to enroll in a reduced service fee tier. The service fee is 15%, instead of the usual 30%. RevenueCat automatically assumes developers are enrolled in the reduced service fee tier.
As of January 1st, 2022, [all Google Play subscription transactions](https://support.google.com/googleplay/android-developer/answer/112622?hl=en) are calculated using a 15% service fee, regardless of how much revenue a developer earns in one year or whether the developer is enrolled in the reduced service fee program. This is automatically reflected in RevenueCat metrics and events.
## How RevenueCat calculates Google Play service fees
-For non-subscription transactions (or subscription transactions that occurred in 2021) RevenueCat assumes you are part of the reduced service fee program.
+For non-subscription transactions (or subscription transactions that occurred in 2021) RevenueCat assumes you are part of the reduced service fee program.
Once you cross $1,000,000 in a calendar year, RevenueCat will automatically switch from the 15% rate to a 30% service fee rate for the rest of the year.
@@ -27,4 +28,4 @@ If you find that the service fee displayed on RevenueCat is incorrect, [contact
To opt-in to Google Play's reduced service fee rate, you'll need to create an account group and link your account. Google has instructions on how to do this [here](https://support.google.com/googleplay/android-developer/answer/10632485).
-Once this is done, you'll automatically be opted in to the reduced fee for your first $1,000,000 USD in revenue per year.
\ No newline at end of file
+Once this is done, you'll automatically be opted in to the reduced fee for your first $1,000,000 USD in revenue per year.
diff --git a/docs/platform-resources/non-subscriptions.mdx b/docs/platform-resources/non-subscriptions.mdx
index 83e94bda3..c0d9ea1e4 100644
--- a/docs/platform-resources/non-subscriptions.mdx
+++ b/docs/platform-resources/non-subscriptions.mdx
@@ -17,10 +17,10 @@ Although RevenueCat is primarily used to handle subscription purchases, our SDK
## Platform Support
-| Platform | Supported Purchase Types |
-| :------: | :-------------------------------------------------------------------: |
-| iOS | Consumables, non-consumables, non-renewing subscriptions |
-| Android | Consumables, non-renewing subscriptions |
+| Platform | Supported Purchase Types |
+| :------: | :----------------------------------------------------------------------------------------------: |
+| iOS | Consumables, non-consumables, non-renewing subscriptions |
+| Android | Consumables, non-renewing subscriptions |
| Stripe | One-time purchases supported when using [Stripe Checkout](/web/stripe#one-time-stripe-purchases) |
:::warning Google Play Store IAPs
@@ -29,6 +29,7 @@ Google Play Store does not provide an option to mark IAPs as consumable or non-c
To replicate the behavior of a non-consumable IAP for Android users, you must ensure your user will not be offered the IAP after the initial purchase. Failure to do so will enable the user to re-purchase the IAP.
:::
+
## Entitlements
Entitlements are used to unlock access to content after a user purchases a product. This means: if you add a consumable product to an entitlement, RevenueCat will report that entitlement as unlocked (forever), even after one purchase. This is because there is no expiration date for consumables, like there is for a subscription. This may work for some use-cases, but generally, you wouldn't add a consumable product to an entitlement meant to be unlocked by a subscription.
@@ -63,15 +64,16 @@ If you haven't already, you'll need to set up products in the respective app sto
Attach your products to each package, and you're ready to use to Purchases SDK to display your offering. On iOS, you could fetch the offering like this:
-
import content1 from "!!raw-loader!@site/code_blocks/platform-resources/non-subscriptions_1.swift";
-
+ type: "swift",
+ content: content1,
+ },
+ ]}
+/>
For more information displaying products, check out the [Displaying Products](/getting-started/displaying-products) guide.
@@ -79,12 +81,14 @@ When you're ready to purchase one of the coin packages, pass the package object
import content2 from "!!raw-loader!@site/code_blocks/platform-resources/non-subscriptions_2.swift";
-
+ type: "swift",
+ content: content2,
+ },
+ ]}
+/>
:::warning
It's important to note that at the moment, logic for keeping track of consumable redemptions must be handled outside of RevenueCat. We recommend your server is set up to receive [Webhook](/integrations/webhooks) events for `NON_RENEWING_PURCHASE` to appropriately provide consumable content for your users.
diff --git a/docs/platform-resources/sample-apps.mdx b/docs/platform-resources/sample-apps.mdx
index 055742e78..fb86a3412 100644
--- a/docs/platform-resources/sample-apps.mdx
+++ b/docs/platform-resources/sample-apps.mdx
@@ -10,197 +10,197 @@ Sample apps are currently included in each SDK repository and demonstrate how to
## Platforms
diff --git a/docs/platform-resources/sdk-reference.mdx b/docs/platform-resources/sdk-reference.mdx
index 30f282299..be2524007 100644
--- a/docs/platform-resources/sdk-reference.mdx
+++ b/docs/platform-resources/sdk-reference.mdx
@@ -10,7 +10,6 @@ If you are looking for a quick overlook and trying to get started, check the [SD
The API reference documentation provides detailed information for each of the classes and methods in the RevenueCat SDK. Choose your platform from the list below.
-
[iOS Reference →](https://revenuecat.github.io/purchases-ios-docs/)
[Android Reference →](https://sdk.revenuecat.com/android/index.html)
diff --git a/docs/platform-resources/server-notifications/apple-server-notifications.mdx b/docs/platform-resources/server-notifications/apple-server-notifications.mdx
index 6e1aeaec4..44a1c3d6e 100644
--- a/docs/platform-resources/server-notifications/apple-server-notifications.mdx
+++ b/docs/platform-resources/server-notifications/apple-server-notifications.mdx
@@ -20,7 +20,7 @@ RevenueCat does not require server notifications from the App Store, however doi
## Tracking new purchases using Apple App Store Server Notifications
-By default, RevenueCat ignores any Apple App Store Server Notifications for purchases that have not yet been posted to the RevenueCat API by one of our SDKs or from your own backend. For RevenueCat to track new purchases from Apple App Store Server Notifications, you can enable the **"Track new purchases from server-to-server notifications"** option in our Dashboard.
+By default, RevenueCat ignores any Apple App Store Server Notifications for purchases that have not yet been posted to the RevenueCat API by one of our SDKs or from your own backend. For RevenueCat to track new purchases from Apple App Store Server Notifications, you can enable the **"Track new purchases from server-to-server notifications"** option in our Dashboard.
Enabling this option ensures that all purchases are tracked, even in the case of network issues between your app and RevenueCat’s backend or if your customer was using a version of the app without the RevenueCat SDK.
@@ -28,21 +28,20 @@ Enabling this option ensures that all purchases are tracked, even in the case of
### User identity
-* The subscriber's app user ID will be taken from the [`appAccountToken`](https://developer.apple.com/documentation/appstoreserverapi/appaccounttoken) field of the transaction.
- * If the `appAccountToken` is set and does not match with an existing subscriber: RevenueCat will create a new subscriber with an app user ID matching the `appAccountToken` value set.
- * If the `appAccountToken` is set and matches with an existing subscriber: No new subscriber will be created, and the purchase will be linked to that existing subscriber.
- * If the `appAccountToken` is not set: RevenueCat will generate an anonymous app user ID to associate that purchase with.
-* If you are using RevenueCat's SDK to track purchases, we may receive the notification directly from the store before the SDK. When this happens, we will follow the app user ID logic as described in the bullet point above, and then proceed with your [transfer behavior](/getting-started/restoring-purchases) for the new app user ID sent by the SDK.
+- The subscriber's app user ID will be taken from the [`appAccountToken`](https://developer.apple.com/documentation/appstoreserverapi/appaccounttoken) field of the transaction.
+ - If the `appAccountToken` is set and does not match with an existing subscriber: RevenueCat will create a new subscriber with an app user ID matching the `appAccountToken` value set.
+ - If the `appAccountToken` is set and matches with an existing subscriber: No new subscriber will be created, and the purchase will be linked to that existing subscriber.
+ - If the `appAccountToken` is not set: RevenueCat will generate an anonymous app user ID to associate that purchase with.
+- If you are using RevenueCat's SDK to track purchases, we may receive the notification directly from the store before the SDK. When this happens, we will follow the app user ID logic as described in the bullet point above, and then proceed with your [transfer behavior](/getting-started/restoring-purchases) for the new app user ID sent by the SDK.
:::warning Customer attributes in events
RevenueCat will start processing the purchase as soon as we receive the Apple server notification. If you rely on [RevenueCat customer attributes](/customers/customer-attributes) being attached to the customer before the purchase is created on RevenueCat (e.g: sending customer attributes to your enabled [third-party integrations](/integrations/third-party-integrations) or [webhooks](/integrations/webhooks)), you should make sure to **send and sync** the customer attributes as soon as you have them or before the purchase is completed.
:::
:::warning
-If you have enabled [*Keep with original App User ID*](/getting-started/restoring-purchases#keep-with-original-app-user-id) or [*Transfer if there are no active subscriptions*](/getting-started/restoring-purchases#transfer-if-there-are-no-active-subscriptions) transfer behavior, we highly recommend turning this setting off unless you are not setting the `appAccountToken` or if the `appAccountToken` will match their RevenueCat app user ID.
+If you have enabled [_Keep with original App User ID_](/getting-started/restoring-purchases#keep-with-original-app-user-id) or [_Transfer if there are no active subscriptions_](/getting-started/restoring-purchases#transfer-if-there-are-no-active-subscriptions) transfer behavior, we highly recommend turning this setting off unless you are not setting the `appAccountToken` or if the `appAccountToken` will match their RevenueCat app user ID.
:::
-
## Receiving Apple notifications on your server
Most customers won't need to receive Apple's notifications to their server directly. Instead, we recommend using RevenueCat's [webhooks](/integrations/webhooks) integration to receive notifications about user purchases on your server.
@@ -60,6 +59,7 @@ If you still want to receive Apple's notifications to your server, you can confi
:::info
If your server needs to have specific hostnames or IP addresses on its allowlist to receive App Store Server Notifications, you can add the hostname `dps.iso.aple.com` and IP addresses `17.58.0.0/18` and `17.58.192.0/18`. These IP addresses are same for sandbox and production.
:::
+
@@ -95,22 +95,26 @@ Here's a basic example of these steps using Node, Express, and Axios:
import content from "!!raw-loader!@site/code_blocks/platform-resources/apple-server-notifications_1.js";
-
+ type: "js",
+ content: content,
+ },
+ ]}
+/>
## Considerations
RevenueCat will be able to process V1 or V2 notifications, however, we recommend utilizing V2 for the following reasons:
+
- [Auto-detect price changes](/subscription-guidance/price-changes)
- Better reliability for [handling refund requests](/platform-resources/apple-platform-resources/handling-refund-requests)
Here are some key points to keep in mind when considering this switch:
+
- RevenueCat continues to operate normally without relying on notifications. Even if there's a brief downtime during the transition, there is no risk of data interruptions.
- Apple has [deprecated](https://developer.apple.com/documentation/appstoreservernotifications/app-store-server-notifications-v1) their V1 notifications and will continue to make improvements to their V2 notifications.
- The main reason to stay on V1 notifications is if your system has specific logic tied to V1. For example, if you have custom logic for processing notifications and are forwarding V1 notifications from RevenueCat to your own systems or from your systems to RevenueCat. You will have to update your custom logic before making the switch to V2.
diff --git a/docs/platform-resources/server-notifications/google-server-notifications.md b/docs/platform-resources/server-notifications/google-server-notifications.md
index c2fc3fc17..abc3d44e9 100644
--- a/docs/platform-resources/server-notifications/google-server-notifications.md
+++ b/docs/platform-resources/server-notifications/google-server-notifications.md
@@ -61,14 +61,16 @@ Once that test notification is sent, you can go back to your app config on the R

-
## Tracking new purchases using Google Cloud Pub/Sub
+
By default, RevenueCat ignores any Google Cloud Pub/Sub notifications for purchases that have not yet been posted to the RevenueCat API by one of our SDKs or from your own backend. For RevenueCat to track new purchases from Google Cloud Pub/Sub, you can enable the **"Track new purchases from server-to-server notifications"** option in our Dashboard. This allows RevenueCat to process new purchases from server-to-server notifications that are not yet in our system. This ensures all purchases are tracked, even in the case of network issues between your app and RevenueCat’s backend or if your customer was using a version of the app without the RevenueCat SDK.

### App User ID Detection Methods
+
RevenueCat provides different ways to detect the App User ID for purchases coming through Google Pub/Sub notifications. The purchase will be associated with the detected App User ID.
+
1. **Use anonymous App User IDs:** RevenueCat will generate a RevenueCat anonymous App User ID to associate the new purchase with. If you are using the RevenueCat SDK, we **strongly recommend** selecting this option. The RevenueCat SDK automatically sets the `obfuscatedExternalAccountId` as a hashed App User ID, which can cause unintended overwrites.
2. **Use Google's obfuscatedExternalAccountId as App User ID:** RevenueCat will use the [`obfuscatedExternalAccountId`](https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.subscriptionsv2#externalaccountidentifiers) field as the RevenueCat App User ID. Only select this option if you are using both the `obfuscatedExternalAccountId` field as your RevenueCat app user ID **and** are [using RevenueCat without our SDK](/migrating-to-revenuecat/sdk-or-not/sdk-less-integration).
@@ -77,18 +79,19 @@ The diagram below will help you determine which App User ID detection method to

### Considerations
-* If you have selected the "Use Google's obfuscatedExternalAccountId as App User ID" option:
- * If the `obfuscatedExternalAccountId` is set and does not match with an existing subscriber: RevenueCat will create a new subscriber with an app user ID matching the `obfuscatedExternalAccountId` value provided.
- * If the `obfuscatedExternalAccountId` is set and matches with an existing subscriber: The purchase will be linked to that existing subscriber.
- * If the `obfuscatedExternalAccountId` is not set: RevenueCat will generate an anonymous app user ID to associate that purchase with.
-* If you are using RevenueCat's SDK to track purchases, we may receive the notification directly from the store before the SDK. When this happens, the App User ID detection method described above will be applied, and then RevenueCat will follow your [restore behavior](/projects/restore-behavior) for the new app user ID sent by the SDK.
+
+- If you have selected the "Use Google's obfuscatedExternalAccountId as App User ID" option:
+ - If the `obfuscatedExternalAccountId` is set and does not match with an existing subscriber: RevenueCat will create a new subscriber with an app user ID matching the `obfuscatedExternalAccountId` value provided.
+ - If the `obfuscatedExternalAccountId` is set and matches with an existing subscriber: The purchase will be linked to that existing subscriber.
+ - If the `obfuscatedExternalAccountId` is not set: RevenueCat will generate an anonymous app user ID to associate that purchase with.
+- If you are using RevenueCat's SDK to track purchases, we may receive the notification directly from the store before the SDK. When this happens, the App User ID detection method described above will be applied, and then RevenueCat will follow your [restore behavior](/projects/restore-behavior) for the new app user ID sent by the SDK.
:::warning Customer attributes in events
RevenueCat will start processing the purchase as soon as we receive the Google Cloud Pub/Sub notification. If you rely on [RevenueCat customer attributes](/customers/customer-attributes) being attached to the customer before the purchase is created on RevenueCat (e.g: sending customer attributes to your enabled [third-party integrations](/integrations/third-party-integrations) or [webhooks](/integrations/webhooks)), ensure you **send and sync** customer attributes as early as possible. Delays can result in missing attributes for purchases, which may affect third-party integrations or webhook events.
:::
:::warning
-If you have enabled [*Keep with original App User ID*](/projects/restore-behavior#keep-with-original-app-user-id) or [*Transfer if there are no active subscriptions*](/projects/restore-behavior#transfer-if-there-are-no-active-subscriptions) transfer behavior or [*Share between App User IDs (legacy)*](/projects/restore-behavior#share-between-app-user-ids-legacy), we highly recommend turning this setting off unless you have selected the "Use anonymous App User IDs" as the App User ID detection method or are [using RevenueCat without our SDK](/migrating-to-revenuecat/sdk-or-not/sdk-less-integration).
+If you have enabled [_Keep with original App User ID_](/projects/restore-behavior#keep-with-original-app-user-id) or [_Transfer if there are no active subscriptions_](/projects/restore-behavior#transfer-if-there-are-no-active-subscriptions) transfer behavior or [_Share between App User IDs (legacy)_](/projects/restore-behavior#share-between-app-user-ids-legacy), we highly recommend turning this setting off unless you have selected the "Use anonymous App User IDs" as the App User ID detection method or are [using RevenueCat without our SDK](/migrating-to-revenuecat/sdk-or-not/sdk-less-integration).
:::
## Considerations
diff --git a/docs/platform-resources/server-notifications/stripe-server-notifications.md b/docs/platform-resources/server-notifications/stripe-server-notifications.md
index b90fbef01..08c586493 100644
--- a/docs/platform-resources/server-notifications/stripe-server-notifications.md
+++ b/docs/platform-resources/server-notifications/stripe-server-notifications.md
@@ -31,6 +31,7 @@ You'll need to follow our [Stripe Web Payments](/web/stripe) guide and send your
- invoice.updated
If you plan to enable the ["Track new purchases from server-to-server notifications"](/platform-resources/server-notifications/stripe-server-notifications#tracking-new-purchases-using-stripe-server-notifications) feature, you should also select the following events:
+
- customer.subscription.created
- checkout.session.completed
@@ -52,12 +53,15 @@ If you choose other events besides what's listed above, our API will respond wit

## Tracking new purchases using Stripe Server Notifications
+
By default, RevenueCat will not process Stripe Server Notifications for any purchases that have not yet been posted to the RevenueCat API from your own backend. For RevenueCat to track new purchases from Stripe Server Notifications, you can enable the **"Track new purchases from server-to-server notifications"** option in our Dashboard. This allows RevenueCat to process new purchases from server-to-server notifications that are not yet in our system. This ensures all purchases are tracked, even in the case of network issues between your server's and RevenueCat's.

### App User ID Detection Methods
+
RevenueCat provides flexible ways to detect the App User ID for purchases coming through Stripe Server Notifications. The Stripe purchase will be associated with the detected App User ID.
+
1. **Use anonymous App User IDs**: RevenueCat will generate a RevenueCat anonymous App User ID to associate the purchase with.
2. **Use Stripe Customer ID as App User ID**: RevenueCat will use the [Stripe Customer ID field](https://docs.stripe.com/api/customers/object#customer_object-id) as the RevenueCat App User ID. Only select this option if you plan on using Stripe's Customer ID as your customer's App User ID throughout your system.
3. **Read App User ID from a Stripe metadata field**: If you are storing your customer's RevenueCat App User ID through [Stripe metadata](https://docs.stripe.com/metadata), you can specify the metadata field name in the `Metadata field key` textbox. RevenueCat will look for this field in the Checkout Session metadata for checkout sessions and in the Subscription metadata for subscriptions. Ensure that the metadata value will exactly match your RevenueCat App User ID.
@@ -67,9 +71,10 @@ In some cases, a Stripe Checkout Session may have a `NULL` value for the Stripe
:::
### Considerations
-* If your setup involves you [manually sending us the Stripe token](/web/stripe#5-send-stripe-tokens-to-revenuecat), RevenueCat may receive the notification from Stripe before your server's request. In this case:
- * The App User ID detection method described above will be applied.
- * RevenueCat will then follow your [transfer behavior](/getting-started/restoring-purchases) for the App User ID provided in your request.
+
+- If your setup involves you [manually sending us the Stripe token](/web/stripe#5-send-stripe-tokens-to-revenuecat), RevenueCat may receive the notification from Stripe before your server's request. In this case:
+ - The App User ID detection method described above will be applied.
+ - RevenueCat will then follow your [transfer behavior](/getting-started/restoring-purchases) for the App User ID provided in your request.
:::warning Customer attributes in events
RevenueCat will start processing the purchase as soon as we receive Stripe's server notification. If you rely on [RevenueCat customer attributes](/customers/customer-attributes) being attached to the customer before the purchase is created on RevenueCat (e.g: sending customer attributes to your enabled [third-party integrations](/integrations/third-party-integrations) or [webhooks](/integrations/webhooks)), you should make sure to **send and sync** the customer attributes as soon as you have them or before the purchase is completed.
diff --git a/docs/projects/restore-behavior.md b/docs/projects/restore-behavior.md
index 4cfa0f023..24acbb973 100644
--- a/docs/projects/restore-behavior.md
+++ b/docs/projects/restore-behavior.md
@@ -62,4 +62,4 @@ If you plan to enable the "Track new purchases from server-to-server notificatio
If you meet any of the above conditions, you can proceed with enabling the feature.
-If not, it may happen that we first track a purchase for **App User ID A** from a server-to-server notification and later we receive the same purchase from the SDK or the REST API under a different **App User ID B**. In this case, no transfer will occur, and **App User ID B** will never get access to the entitlement.
\ No newline at end of file
+If not, it may happen that we first track a purchase for **App User ID A** from a server-to-server notification and later we receive the same purchase from the SDK or the REST API under a different **App User ID B**. In this case, no transfer will occur, and **App User ID B** will never get access to the entitlement.
diff --git a/docs/revenuecat-support/general-troubleshooting.mdx b/docs/revenuecat-support/general-troubleshooting.mdx
index 93c72aa59..0883e7b52 100644
--- a/docs/revenuecat-support/general-troubleshooting.mdx
+++ b/docs/revenuecat-support/general-troubleshooting.mdx
@@ -3,14 +3,19 @@ title: General Troubleshooting
slug: general-troubleshooting
hidden: false
---
-If you are having any issues in RevenueCat, below is a list of some common questions that we see and some quick ways to troubleshoot them. If you are still having issues after checking this document, please feel free to reach out to [support](https://app.revenuecat.com/settings/support) or check out our [community](https://community.revenuecat.com/)!
+
+If you are having any issues in RevenueCat, below is a list of some common questions that we see and some quick ways to troubleshoot them. If you are still having issues after checking this document, please feel free to reach out to [support](https://app.revenuecat.com/settings/support) or check out our [community](https://community.revenuecat.com/)!
## General Issues
+
### Products or Offerings can't be fetched, or Offerings are empty?
-
+
-
+
If you can't fetch products, or your offerings are empty, this is nearly always a configuration issue. We have a guide detailing the next steps [in our community here](https://community.revenuecat.com/sdks-51/why-are-offerings-or-products-empty-124). For Google Play Store issues, please refer to our [Google Play Checklists](/service-credentials/creating-play-service-credentials/google-play-checklists).
@@ -25,18 +30,22 @@ Here's how it works under the hood:
If the stores are unable to return valid products, it means that somewhere in that cycle there is a configuration issue. If there is a typo in your product identifier, the request will fail. If the bundle ID doesn't match the configuration in App Store Connect (or package name for Google Play, etc.), the request will fail. The guide linked above details the potential configuration issues.
### Customer can't access their entitlements?
-This can happen for multiple reasons, but the most common reasons for this are the following:
+
+This can happen for multiple reasons, but the most common reasons for this are the following:
+
1. The user's identifier changed (via re-installation, created a new account, etc.). This is very common, and should be an expected part of your app's flow. This can happen automatically at times, like after a re-install of your app.
-3. The user's subscription purchases expired (in this case, they should re-purchase).
+2. The user's subscription purchases expired (in this case, they should re-purchase).
If a user has active purchases that are no longer synced to their user ID or they have lost access, they need to **[restore purchases](/getting-started/restoring-purchases)**. **You should always have a restore purchases button in your app** - typically located in your paywall or in-app settings page to make it easy for your users to find the option.
Restoring purchases will re-sync the user's purchase with the currently identified user ID and re-unlock any entitlements that have been lost due to a changed user ID. If this does not work, it might have to do with you're identifying users or how you are checking for entitlements. We recommend checking the respective docs linked below.
+
- [Restore behavior](https://www.revenuecat.com/docs/getting-started/restoring-purchases).
- [Identifying users](https://www.revenuecat.com/docs/customers/user-ids).
- [Checking subscription status](https://www.revenuecat.com/docs/customers/customer-info).
### A user's purchases were mistakenly transferred.
+
If a user's purchases were transferred, it means that a different user ID _claimed_ the transactions or purchases that another user in RevenueCat already owned. When we detect this, we perform a _transfer_ so that the user can continue accessing purchases on the device they are currently logged into.
While this may seem unexpected at times, this is **extremely common**, and is a valid case for apps with subscriptions. Since the transactions are actually associated with the **underlying store account**, when a user claims a receipt that is already owned by another user ID it means that:
@@ -44,28 +53,34 @@ While this may seem unexpected at times, this is **extremely common**, and is a
1. The user is logged into the underlying store account, indicating ownership of those purchases.
2. The user is attempting to restore those purchases from a different app user ID than the one that already owns the purchases.
-We recommend also looking more into your transfer settings as this can chang the behavior in your app when a transfer is made. More information on this can be found [here](https://www.revenuecat.com/docs/getting-started/restoring-purchases#transferring-purchases-seen-on-multiple-app-user-ids).
+We recommend also looking more into your transfer settings as this can chang the behavior in your app when a transfer is made. More information on this can be found [here](https://www.revenuecat.com/docs/getting-started/restoring-purchases#transferring-purchases-seen-on-multiple-app-user-ids).
### I accidentally logged in all of my app users with the same app user ID.
+
A simple way to fix this issue can be found below:
+
1. Release an app update that removes the hard-coded app user ID and for users who had that app user ID, either:
- 1. call logOut
- 2. set a different app user ID
+ 1. call logOut
+ 2. set a different app user ID
2. Wait until most of your users get the update.
3. Delete the hard-coded app user ID from the [dashboard](https://www.revenuecat.com/docs/dashboard-and-metrics/customer-history/manage-users) or the [API](https://www.revenuecat.com/docs/api-v1#tag/customers/operation/delete-subscriber).
4. Users who were reset/reidentified will need to restore purchases in order to re-gain their entitlements and re-link their subscription with their current app user ID.
-:::info
-You can delete the hard-coded user at any time that you see it pop up in the dashboard (This might happen since some users may be slower to update the app).
-:::
+ :::info
+ You can delete the hard-coded user at any time that you see it pop up in the dashboard (This might happen since some users may be slower to update the app).
+ :::
-### Can I reset customer attributes?
-While you can't directly reset customer attributes, you can delete your current attribute by passing null or an empty string as the key value. Once you do this you will have to call restorePurchases or syncPurchases to trigger an update to the cache. Individual attributes can also be cleared for a specific user in their customer view. Once you do this, you will be able to set these attributes to whatever they need to be set to effectively resetting them.
+### Can I reset customer attributes?
+
+While you can't directly reset customer attributes, you can delete your current attribute by passing null or an empty string as the key value. Once you do this you will have to call restorePurchases or syncPurchases to trigger an update to the cache. Individual attributes can also be cleared for a specific user in their customer view. Once you do this, you will be able to set these attributes to whatever they need to be set to effectively resetting them.
### Help, I am having issues with the SDK.
-We have gone ahead and created a document to troubleshoot SDK problems which we recommend checking out [here](https://www.revenuecat.com/docs/test-and-launch/debugging/troubleshooting-the-sdks)!
+
+We have gone ahead and created a document to troubleshoot SDK problems which we recommend checking out [here](https://www.revenuecat.com/docs/test-and-launch/debugging/troubleshooting-the-sdks)!
### What countries are supported?
+
Since RevenueCat works as a wrapper for purchases made by the respective store, we will support purchases from countries that each of the respective stores support.
+
- [App Store supported countries](https://support.apple.com/en-us/118205)
- [Google Play Store supported countries](https://support.google.com/googleplay/answer/143779?hl=en-GB&sjid=12085401994901043904-NC)
- [Amazon App Store supported countries](https://www.amazon.com/gp/help/customer/display.html?nodeId=GG6HESXQN45DZQ8N)
@@ -73,20 +88,25 @@ Since RevenueCat works as a wrapper for purchases made by the respective store,
- [RevenueCat Billing](https://www.revenuecat.com/docs/web/revenuecat-billing) - Since RevenueCat billing supports using Stripe as the payment gateway, we currently will use the same supported countries as Stripe does as seen in the link above.
### Why does my app keep getting rejected?
-If your app is being rejected from the respective store it can be for many different reasons. We have a useful document [here](https://www.revenuecat.com/docs/test-and-launch/app-store-rejections) that goes over common reasons for rejection and how to help get your app approved!
+
+If your app is being rejected from the respective store it can be for many different reasons. We have a useful document [here](https://www.revenuecat.com/docs/test-and-launch/app-store-rejections) that goes over common reasons for rejection and how to help get your app approved!
## Service credentials issues
-Service credentials issues can be tricky and can occur for multiple reasons but will stop you from making purchases successfully. Below is a list of things to check for your credentials in each store.
+
+Service credentials issues can be tricky and can occur for multiple reasons but will stop you from making purchases successfully. Below is a list of things to check for your credentials in each store.
### Google Play Service credentials Troubleshooting.
-We have a great document [here](https://www.revenuecat.com/docs/service-credentials/creating-play-service-credentials/google-play-checklists) that goes over how to check which part of your credentials is failing and if it is failing how to fix the issue at hand. We recommend checking that out if you are experiencing any issues in relation to this!
+
+We have a great document [here](https://www.revenuecat.com/docs/service-credentials/creating-play-service-credentials/google-play-checklists) that goes over how to check which part of your credentials is failing and if it is failing how to fix the issue at hand. We recommend checking that out if you are experiencing any issues in relation to this!
### App Store Connect API Key.
-Make sure to verify that your key ID and Issuer ID are set correctly in correlation with the file that you uploaded.
+
+Make sure to verify that your key ID and Issuer ID are set correctly in correlation with the file that you uploaded.
## Event Issues
### I see an event in RevenueCat, but it wasn't sent to webhooks or my own integration!
+
Missing events are often a configuration issue. Most third-party integrations that we support require additional configuration before events will be sent; if that configuration hasn't been completed, events won't be dispatched to the third-party provider.
For example, many integrations require a [Attribute](/customers/customer-attributes) to be set on each Customer before events can be dispatched. Ensure that this value (typically from the third-party SDK) is set on a user before contacting support.
@@ -94,6 +114,7 @@ For example, many integrations require a [Attribute](/customers/customer-attribu
## Metrics and Data troubleshooting
### Revenue data in RevenueCat doesn't match the real revenue data for individual transactions.
+
Revenue and pricing data in RevenueCat uses a **best-effort** approach. Some stores don't allow developers to see individual prices for transactions, so RevenueCat infers transaction prices based on the price of the product when it was originally purchased.
If you **change prices** of your products in App Store Connect or Google Play, revenue data in RevenueCat will be off by a larger margin. For this reason, we almost always recommend [creating a new product instead](/subscription-guidance/price-changes).
@@ -101,6 +122,7 @@ If you **change prices** of your products in App Store Connect or Google Play, r
In truth, the only **real** metric of earnings is the actual payout amounts that each payment processor (the stores) deposits into your account. You should use revenue metrics in RevenueCat's dashboard to track trends, but for accounting purposes we recommend using the actual store payout reports.
### Metrics that I'm seeing in RevenueCat don't match App Store Connect, Google Play, etc.
+
RevenueCat doesn't pull data from App Store or Google Play reports directly, so it's very likely the data you see in RevenueCat won't align 1:1 with those stores. This is expected behavior. Additionally, RevenueCat definitions don't always align with store definitions. For example, Google Play considers an 'active subscriber' to include free trials, whereas RevenueCat does not.
Furthermore, RevenueCat metrics (active subscriptions, active trials, etc.) are generated based on _the synced receipts we have for your users_. If those receipts/transactions aren't synced to RevenueCat, they **won't** be included in Charts or other RevenueCat metrics.
diff --git a/docs/revenuecat-support/support-first-steps.mdx b/docs/revenuecat-support/support-first-steps.mdx
index 6585524fd..eaf719578 100644
--- a/docs/revenuecat-support/support-first-steps.mdx
+++ b/docs/revenuecat-support/support-first-steps.mdx
@@ -4,13 +4,20 @@ slug: support-first-steps
excerpt: We can help, but we need your help first.
hidden: false
---
-import ExternalButton from '@site/src/components/ExternalButton'
+
+import ExternalButton from "@site/src/components/ExternalButton";
Our documentation (you're already here!) answers a lot of questions about Charts, the dashboard, Customer Lists, and SDK setup. Try looking through here first, as well as our community where other developers may have already asked your question.
-
+
-
+
### Contacting Support
@@ -22,7 +29,11 @@ When contacting support, it's extremely important that you provide enough inform
Finally, be sure to check the [status page](https://status.revenuecat.com) before creating a ticket if you're concerned about potential downtime.
-
+
### General Troubleshooting
+
For more troubleshooting, view our troubleshooting document [here](/revenuecat-support/general-troubleshooting)!
diff --git a/docs/sdk-guides/android-native-4x-to-5x-migration.mdx b/docs/sdk-guides/android-native-4x-to-5x-migration.mdx
index bdc482b66..1672a1efe 100644
--- a/docs/sdk-guides/android-native-4x-to-5x-migration.mdx
+++ b/docs/sdk-guides/android-native-4x-to-5x-migration.mdx
@@ -34,26 +34,28 @@ There were various updates to our API in this release, in order to best support
The `configure` function has been changed to accept a `PurchasesConfiguration.Builder`. The previous function is deprecated. The new function can be used like this:
-
import content1 from "!!raw-loader!@site/code_blocks/sdk-guides/android-native-4x-to-5x-migration_1.kt";
import content2 from "!!raw-loader!@site/code_blocks/sdk-guides/android-native-4x-to-5x-migration_2.kt";
-
+ type: "kotlin",
+ content: content1,
+ },
+ ]}
+/>
Or for Amazon:
-
-
+ type: "kotlin",
+ content: content2,
+ },
+ ]}
+/>
### Making purchases
diff --git a/docs/sdk-guides/android-native-5x-to-6x-migration.mdx b/docs/sdk-guides/android-native-5x-to-6x-migration.mdx
index 6982b5016..e0d1ccfb3 100644
--- a/docs/sdk-guides/android-native-5x-to-6x-migration.mdx
+++ b/docs/sdk-guides/android-native-5x-to-6x-migration.mdx
@@ -4,13 +4,14 @@ slug: android-native-5x-to-6x-migration
excerpt: New Google subscription model migration
hidden: false
---
+
## Google Product setup
Google introduced a lot of new concepts in their new subscription model. Here are some definitions:
- **Subscription**: A subscription represents access to a set of features of your app. It can have 1 or more base plans.
- **Base plan**: represents an auto-renewing or prepaid period subscription. You can have multiple base plans in a single subscription to support different subscription periods.
-- **Offer**: represents an offer on a base plan. Google’s billing client returns the offers that a user is eligible for. There are 3 eligibility criteria:
+- **Offer**: represents an offer on a base plan. Google’s billing client returns the offers that a user is eligible for. There are 3 eligibility criteria:

@@ -34,23 +35,23 @@ Our recommendation is to:
Existing subscriptions should still work, but you don’t need to create multiple subscriptions for different durations anymore. You should instead create multiple base plans for the same subscription.
:::
-If you plan to have multiple offers for the same plan or have developer-determined offers, we highly recommend you add tags for each offer so it’s easier to identify them later. It is not needed from a RevenueCat perspective but is just best practice for you to manage these offers on your paywall.
+If you plan to have multiple offers for the same plan or have developer-determined offers, we highly recommend you add tags for each offer so it’s easier to identify them later. It is not needed from a RevenueCat perspective but is just best practice for you to manage these offers on your paywall.
## RevenueCat Product Setup
-Once you have created your products in Google, you can add your products in the RevenueCat dashboard. The entitlements, offerings and packages of your dashboard should remain the same. However, to add new products, the UI has changed.
+Once you have created your products in Google, you can add your products in the RevenueCat dashboard. The entitlements, offerings and packages of your dashboard should remain the same. However, to add new products, the UI has changed.
-There are two ways to add products via the RevenueCat dashboard.
+There are two ways to add products via the RevenueCat dashboard.
### 1. Automatic Import
-Currently, this functionality is limited to importing subscriptions, but one-time purchases are in the works.
+Currently, this functionality is limited to importing subscriptions, but one-time purchases are in the works.

### 2. Manual Import
-For manual import, you need to add both your subscription ID and your base plan ID when adding a new product.
+For manual import, you need to add both your subscription ID and your base plan ID when adding a new product.

@@ -58,13 +59,13 @@ You can find this information in Google Play Console here:

-After you’ve added your products, you can assign them to packages the same as before. You can follow the documentation [here](/getting-started/entitlements). If you select a non backwards-compatible product and the [app compatibility setting](/getting-started/entitlements/google-subscriptions-and-backwards-compatibility) is set to "SDK v6+ and backwards compatible", you will have the ability to configure a backwards compatible fallback product. This product will be available for purchase in previous versions of the SDK which don't yet support non backwards compatible products.
+After you’ve added your products, you can assign them to packages the same as before. You can follow the documentation [here](/getting-started/entitlements). If you select a non backwards-compatible product and the [app compatibility setting](/getting-started/entitlements/google-subscriptions-and-backwards-compatibility) is set to "SDK v6+ and backwards compatible", you will have the ability to configure a backwards compatible fallback product. This product will be available for purchase in previous versions of the SDK which don't yet support non backwards compatible products.

## Default Offer Selection
-With the new configuration options, there could be multiple offers available when purchasing a Package or StoreProduct. When purchasing a Package or Product, the SDK will choose which option to purchase as the "default offer", mimicking how it worked on previous versions of our SDK. If you want more control, you can instead purchase a SubscriptionOption directly. For more information, check out [this guide](/subscription-guidance/subscription-offers#google-play).
+With the new configuration options, there could be multiple offers available when purchasing a Package or StoreProduct. When purchasing a Package or Product, the SDK will choose which option to purchase as the "default offer", mimicking how it worked on previous versions of our SDK. If you want more control, you can instead purchase a SubscriptionOption directly. For more information, check out [this guide](/subscription-guidance/subscription-offers#google-play).
## Migration Guide
@@ -74,90 +75,70 @@ These are the abstraction models we use to support Google’s new features:

-With v6.x, you can choose to pass in a `StoreProduct`, a `Package`, or a `SubscriptionOption` into the `PurchaseParams.Builder`.
+With v6.x, you can choose to pass in a `StoreProduct`, a `Package`, or a `SubscriptionOption` into the `PurchaseParams.Builder`.
### Migration implementation steps
1. Update RevenueCat to version `6.4.0`. You can do this in your app’s module build.gradle.
-
import content1 from "!!raw-loader!@site/code_blocks/sdk-guides/android-native-5x-to-6x-migration_1.kt";
import content2 from "!!raw-loader!@site/code_blocks/sdk-guides/android-native-5x-to-6x-migration_2.txt";
import content3 from "!!raw-loader!@site/code_blocks/sdk-guides/android-native-5x-to-6x-migration_3.txt";
import content4 from "!!raw-loader!@site/code_blocks/sdk-guides/android-native-5x-to-6x-migration_4.txt";
-
-
-{/* [block:file]
-[
- {
- "language": "kotlin",
- "name": "",
- "file": "code_blocks/📘 SDK Guides/migration-guides/android-native-5x-to-6x-migration_1.kt"
- },
- {
- "language": "Text",
- "name": "React Native",
- "file": "code_blocks/📘 SDK Guides/migration-guides/android-native-5x-to-6x-migration_2.txt"
- },
- {
- "language": "Text",
- "name": "Flutter",
- "file": "code_blocks/📘 SDK Guides/migration-guides/android-native-5x-to-6x-migration_3.txt"
- },
- {
- "language": "Text",
- "name": "Cordova",
- "file": "code_blocks/📘 SDK Guides/migration-guides/android-native-5x-to-6x-migration_4.txt"
- }
-]
-[/block] */}
-
-2. Adapt your paywall to use the new SDK.
+ type: "cordova",
+ name: "Cordova",
+ content: content4,
+ },
+ ]}
+/>
+
+2. Adapt your paywall to use the new SDK.
- The `price` property on `StoreProduct` (which is either the one-time purchase price or subscription's base plan price) is now a `Price` object
-- There are also price related fields on the `StoreProduct` > `SubscriptionOption` > `PricingPhase` model.
+- There are also price related fields on the `StoreProduct` > `SubscriptionOption` > `PricingPhase` model.
Follow the migration reference doc to migrate all the changes. These are some examples of code changes you might have to do:
import content5 from "!!raw-loader!@site/code_blocks/sdk-guides/android-native-5x-to-6x-migration_5.kt";
import content6 from "!!raw-loader!@site/code_blocks/sdk-guides/android-native-5x-to-6x-migration_6.kt";
-
+ type: "kotlin",
+ content: content5,
+ },
+ ]}
+/>
-
+ type: "kotlin",
+ content: content6,
+ },
+ ]}
+/>
3. If you are using products with offers:
-- If you keep using the existing purchase functions, the [default offer logic](#default-offer-selection) will be applied to choose which option to purchase.
+- If you keep using the existing purchase functions, the [default offer logic](#default-offer-selection) will be applied to choose which option to purchase.
- If you want more control, you will need to choose the purchase option that includes your offer from your `StoreProduct`. A possible way to identify a free trial is `storeProduct.subscriptionOptions?.freeTrial`. Alternatively, you can add tags to your offer and filter them through the `storeProduct.subscriptionOptions?.withTag("your-tag")`.
diff --git a/docs/sdk-guides/android-native-6x-to-7x-migration.mdx b/docs/sdk-guides/android-native-6x-to-7x-migration.mdx
index b42daf819..512a26745 100644
--- a/docs/sdk-guides/android-native-6x-to-7x-migration.mdx
+++ b/docs/sdk-guides/android-native-6x-to-7x-migration.mdx
@@ -21,18 +21,17 @@ See [Android Native - 5.x to 6.x Migration](/sdk-guides/android-native-5x-to-6x-
### Class/interface changes
| New |
-|-------------------------|
+| ----------------------- |
| `ReplacementMode` |
| `GoogleReplacementMode` |
-
| Deprecated | Replace with |
-|-----------------------|-------------------------|
+| --------------------- | ----------------------- |
| `ProrationMode` | `ReplacementMode` |
| `GoogleProrationMode` | `GoogleReplacementMode` |
| Temporarily removed |
-|--------------------------|
+| ------------------------ |
| `ProrationMode.DEFERRED` |
### Bumped minimum Android SDK version
diff --git a/docs/sdk-guides/android-native-7x-to-8x-migration.mdx b/docs/sdk-guides/android-native-7x-to-8x-migration.mdx
index 92bc35acc..eaa37a190 100644
--- a/docs/sdk-guides/android-native-7x-to-8x-migration.mdx
+++ b/docs/sdk-guides/android-native-7x-to-8x-migration.mdx
@@ -18,15 +18,15 @@ This migration guide has detailed class, property, and method changes.
### Class/interface changes
-| New |
-|------------------------------------------------------------------|
-| `InstallmentsInfo` |
-| `GoogleInstallmentsInfo` |
-| `PurchaseConfiguration.pendingTransactionsForPrepaidPlansEnabled`|
-| `SubscriptionOption.installmentsInfo` |
+| New |
+| ----------------------------------------------------------------- |
+| `InstallmentsInfo` |
+| `GoogleInstallmentsInfo` |
+| `PurchaseConfiguration.pendingTransactionsForPrepaidPlansEnabled` |
+| `SubscriptionOption.installmentsInfo` |
| Removed |
-|-----------------------------------------------------------------------|
+| --------------------------------------------------------------------- |
| `UpgradeInfo` |
| `ProrationMode` |
| `GoogleProrationMode` |
@@ -44,21 +44,26 @@ RevenueCat SDK v8 bumps minimum Android SDK version from Android 4.4 (API level
We've added support for [Google Play Installment subscriptions](https://rev.cat/googleplayinstallmentsubscriptions) which is a type of subscription where customers pay for the subscription in multiple installments over a period of time, rather than paying the entire subscription fee upfront. We've also extended our [product import functionality](/sdk-guides/android-native-5x-to-6x-migration#1-automatic-import) to import installment subscription products from the Google Play Console.
If you're looking to use Google's installment plans, all you'll need to do is create a base plan for an Installment subscription in Google Play Console! You can access the installment plan details from the SDK by using the `SubscriptionOption.installmentsInfo` property, like this:
+
```kotlin
val offerings = purchases.awaitOfferings()
// This provides the number of installments the customer commits to, and the number of installments the customer commits to upon a renewal.
val installmentsInfo = offerings.current?.monthly?.product?.defaultOption?.installmentsInfo
```
+
The `installmentsInfo` includes the following installment subscription details:
+
- `commitmentPaymentsCount`: Number of payments the customer commits to in order to purchase the subscription.
- `renewalCommitmentPaymentsCount`: The number of payments the user commits to upon a renewal. This number can either be 1, where the subscription will behave as a monthly subscription, or your commitment payment count number, where the subscription will renew for another commitment.
Installment subscriptions are currently only available in 4 countries: Brazil, Italy, Spain and France. (check Google Play Console for latest availability). As a result, these products will not be loaded in non-supported countries and you will need to provide a fallback to a different RevenueCat package.
-## Support for Google Play pending purchases
+## Support for Google Play pending purchases
+
We've added support for [Google Play pending transactions](https://rev.cat/googleplaypendingtransactions) for prepaid subscriptions. These are transactions that require one or more additional steps between customer initiation and the payment method being processed. For example, a user could start a transaction which involves them paying cash at a physical location.
Pending transactions for a prepaid subscription is disabled by default. If you want to enable this behavior during configuration of the RevenueCat SDK:
+
```kotlin
Purchases.configure(
PurchasesConfiguration.Builder(applicationContext, apiKey)
@@ -77,4 +82,4 @@ Observer mode is still supported in v8. Other than updating the SDK version, the
## Reporting undocumented issues:
-Feel free to file an issue! [New RevenueCat Issue](https://github.com/RevenueCat/purchases-android/issues/new/).
\ No newline at end of file
+Feel free to file an issue! [New RevenueCat Issue](https://github.com/RevenueCat/purchases-android/issues/new/).
diff --git a/docs/sdk-guides/ios-native-3x-to-4x-migration.mdx b/docs/sdk-guides/ios-native-3x-to-4x-migration.mdx
index c4c417089..3e6de96dd 100644
--- a/docs/sdk-guides/ios-native-3x-to-4x-migration.mdx
+++ b/docs/sdk-guides/ios-native-3x-to-4x-migration.mdx
@@ -15,45 +15,50 @@ View the iOS SDK Reference documentation [here →](https://revenuecat-docs.netl
Migrating from Objective-C to Swift required a number of API changes, but we feel that the changes resulted in the SDK having a more natural feel for developers.
## Xcode version requirements and updated deployment targets
-`purchases-ios` v4 requires using Xcode 13.2 or newer. It also updates the minimum deployment targets for iOS, macOS and tvOS.
+
+`purchases-ios` v4 requires using Xcode 13.2 or newer. It also updates the minimum deployment targets for iOS, macOS and tvOS.
#### Minimum deployment targets
-| | v3 | v4 |
-| :-: | :-: | :-: |
-| iOS | 9.0 | **11.0** |
-| tvOS | 9.0 | **11.0** |
-| macOS | 10.12 | **10.13** |
-| watchOS | 6.2 | 6.2 (unchanged) |
+
+| | v3 | v4 |
+| :-----: | :---: | :-------------: |
+| iOS | 9.0 | **11.0** |
+| tvOS | 9.0 | **11.0** |
+| macOS | 10.12 | **10.13** |
+| watchOS | 6.2 | 6.2 (unchanged) |
## Migration Steps
-To start us off, our framework name changed from `Purchases` to `RevenueCat`! 😻 You'll now need to explicitly import `RevenueCat` instead of `Purchases`.
+To start us off, our framework name changed from `Purchases` to `RevenueCat`! 😻 You'll now need to explicitly import `RevenueCat` instead of `Purchases`.
### 1. Update Framework references
###### Swift
-| Before | After |
-| :-: | :-: |
+
+| Before | After |
+| :----------------: | :-----------------: |
| `import Purchases` | `import RevenueCat` |
###### Objective-C
-| Before | After |
-| :-: | :-: |
+
+| Before | After |
+| :------------------: | :-------------------: |
| `@import Purchases;` | `@import RevenueCat;` |
##### 1.1 Update Swift Package Manager dependency (if needed)
Select your target in Xcode, then go to Build Phases, and ensure that your target's `Link Binary with Libraries` section references `RevenueCat`, and remove the reference to `Purchases` if it was still there.
-| Before | After |
-| :-: | :-: |
+| Before | After |
+| :---------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------: |
| [link binary with libraries before](/images/link_binary_with_libraries_before_spm_2d2fe96e46481d9156daa017c10595ac.png) | [link binary with libraries after](/images/link_binary_with_libraries_after_spm_1b11bf2cbd0e465cc67a1d773995b65e.png) |
**Note:**
-Due to an Xcode bug, you might run into a Workspace Integrity error after upgrading, with a message that looks like
-`"Couldn't load project PurchaseTester"`.
+Due to an Xcode bug, you might run into a Workspace Integrity error after upgrading, with a message that looks like
+`"Couldn't load project PurchaseTester"`.
If this happens, you can fix it with the following steps:
+
1. In Xcode, go to Product -> Clean Build Folder
2. Quit and re-open Xcode
@@ -61,8 +66,8 @@ If this happens, you can fix it with the following steps:
In your Podfile, update the reference to the Pod from `Purchases` to `RevenueCat`. Don't forget to run `pod update` after saving the Podfile.
-| Before | After |
-| :-: | :-: |
+| Before | After |
+| :---------------: | :----------------: |
| `pod 'Purchases'` | `pod 'RevenueCat'` |
##### 1.3 Update Carthage Framework (if needed)
@@ -71,28 +76,27 @@ In your Podfile, update the reference to the Pod from `Purchases` to `RevenueCat
Select your target in Xcode, then go to Build Phases, and ensure that your target's `Link Binary with Libraries` section
references `RevenueCat`, and remove the reference to `Purchases` if it was still there.
-Do the same with the Embed Frameworks section.
+Do the same with the Embed Frameworks section.
-| Before | After |
-| :-: | :-: |
+| Before | After |
+| :--------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------: |
| [link binary with libraries before](/images/link_binary_with_libraries_before_carthage_1d5f4091a6f1a1d83bdf9494f09e9065.png) | [link binary with libraries after](/images/link_binary_with_libraries_after_carthage_66365be8f3631be0f52792575fead228.png) |
-| [embed frameworks before](/images/embed_frameworks_before_carthage_87327ac0b343e9090e18fcadf8c05a3c.png) | [embed frameworks after](/images/embed_frameworks_after_carthage_1c6a63d57aaa71103d674cd19f383f7f.png) |
+| [embed frameworks before](/images/embed_frameworks_before_carthage_87327ac0b343e9090e18fcadf8c05a3c.png) | [embed frameworks after](/images/embed_frameworks_after_carthage_1c6a63d57aaa71103d674cd19f383f7f.png) |
###### 1.3.2 Using Platform-specific frameworks
-We highly recommend moving into XCFrameworks, since these have a simpler setup and prevent compatibility issues with
+We highly recommend moving into XCFrameworks, since these have a simpler setup and prevent compatibility issues with
multi-platform setups.
Carthage has a [migration guide to move into XCFrameworks available here](https://github.com/carthage/carthage#migrating-a-project-from-framework-bundles-to-xcframeworks).
-After migrating into XCFrameworks, follow the steps outlined in 1.3.1 to set up the `RevenueCat.xcframework`.
+After migrating into XCFrameworks, follow the steps outlined in 1.3.1 to set up the `RevenueCat.xcframework`.
If you can't move into XCFrameworks, you will still need to update the `Link Binary with Libraries` phase as outlined
in 1.3.1 (only using a `.framework` instead of `.xcframework`).
-After that, update the your `input.xcfilelist` and `output.xcfilelist` for the Run Script phase of Carthage frameworks,
-replacing `Purchases.framework` with `RevenueCat.framework`.
-
+After that, update the your `input.xcfilelist` and `output.xcfilelist` for the Run Script phase of Carthage frameworks,
+replacing `Purchases.framework` with `RevenueCat.framework`.
### 2. Update code references
@@ -104,7 +108,7 @@ If you see any issues or new APIs that fix-its didn't cover, we'd appreciate [bu
#### 2.2 Update references to `Purchases.foo` to `RevenueCat.foo`
-You might run into compilation errors with a message like `Error: `'_' is not a member type of class 'RevenueCat.Purchases'`.
+You might run into compilation errors with a message like `Error: `'\_' is not a member type of class 'RevenueCat.Purchases'`.
The reason is that the class `Purchases` is no longer the parent of classes such as `Offerings`.
You should reference classes directly or as a child of `RevenueCat`, e.g. `RevenueCat.Offerings`
@@ -112,7 +116,7 @@ instead of `Purchases.Offerings`. You can also omit the framework entirely, i.e.
#### 2.3 Import StoreKit (if needed)
-Our V3 SDK automatically imported `StoreKit` whenever you did `import Purchases`. Due to Swift limitations, our
+Our V3 SDK automatically imported `StoreKit` whenever you did `import Purchases`. Due to Swift limitations, our
V4 SDK doesn't do this automatically.
So if you're referencing StoreKit types directly, you might need to add
@@ -121,15 +125,16 @@ So if you're referencing StoreKit types directly, you might need to add
#### 2.4 Update code to use the new types (if needed)
Step 2.1 should automatically help you convert your code into the new types. See the "New Types" section for
-more information on what the new types introduce.
+more information on what the new types introduce.
#### 2.5 Take advantage of our new APIs
We introduced new features for Customer Support, as well as
- [async/await alternatives](https://docs.swift.org/swift-book/LanguageGuide/Concurrency.html) for our APIs.
+[async/await alternatives](https://docs.swift.org/swift-book/LanguageGuide/Concurrency.html) for our APIs.
These are optional, but could help make your code more readable and easy to maintain.
Some additional changes include:
+
- Updated references of `Purchaser` to `Customer` to be more consistent across our platform
- Further abstraction away from `StoreKit` with new types.
@@ -138,12 +143,15 @@ See the "New APIs" section of this guide for more details.
## Known Issues
### ObjC + SPM
-If you expose any Purchases objects from one target to another (see [example project](https://github.com/taquitos/SPMBug) for what this could look like), that second target will not build due to a missing autogenerated header. Currently there is a known bug in SPM whereby Xcode either doesn't pass the RevenueCat ObjC generated interface to SPM, or SPM just doesn't integrate it. You can follow along: [SR-15154](https://bugs.swift.org/browse/SR-15154).
-###### Workaround:
+If you expose any Purchases objects from one target to another (see [example project](https://github.com/taquitos/SPMBug) for what this could look like), that second target will not build due to a missing autogenerated header. Currently there is a known bug in SPM whereby Xcode either doesn't pass the RevenueCat ObjC generated interface to SPM, or SPM just doesn't integrate it. You can follow along: [SR-15154](https://bugs.swift.org/browse/SR-15154).
+
+###### Workaround:
+
You must manually add the autogenerated file we committed to the repository [RevenueCat-Swift.h](https://github.com/RevenueCat/purchases-ios/blob/main/Tests/InstallationTests/CommonFiles/RevenueCat-Swift.h) to your project, and `#import RevenueCat-Swift.h` in your bridging header. You can see how we do this in our [SPMInstallation project](https://github.com/RevenueCat/purchases-ios/tree/main/Tests/InstallationTests/SPMInstallation).
## Automatic Migration
+
When building your project using v4, Xcode should automatically provide one-click fixes methods and types that have been renamed. For the most part, the migration should be doable by just building and applying Xcode's automatic fix-its when they pop up.
If you see any issues or new APIs that fix-its didn't cover, we'd appreciate [bug reports](https://github.com/RevenueCat/purchases-ios/issues/new?assignees=&labels=bug&template=bug_report.md&title=)!
@@ -156,160 +164,166 @@ The class `Purchases` is no longer the parent of classes such as `Offering`. You
To better support `StoreKit 2`, `RevenueCat v4` introduces several new types to encapsulate data from `StoreKit 1` and `StoreKit 2`:
-- ``StoreProduct``: wraps a `StoreKit.SKProduct` or `StoreKit.Product`
-- ``StoreTransaction``: wraps a `StoreKit.SKPaymentTransaction` or `StoreKit.Transaction`
-- ``StoreProductDiscount``: wraps a `StoreKit.SKProductDiscount` or `StoreKit.Product.SubscriptionOffer`
+- `StoreProduct`: wraps a `StoreKit.SKProduct` or `StoreKit.Product`
+- `StoreTransaction`: wraps a `StoreKit.SKPaymentTransaction` or `StoreKit.Transaction`
+- `StoreProductDiscount`: wraps a `StoreKit.SKProductDiscount` or `StoreKit.Product.SubscriptionOffer`
These types replace native StoreKit types in all public API methods that used them.
## Objective-C
+
### Type changes
`@import Purchases` is now `@import RevenueCat`
-| v3 | v4 |
-| ------------ | ------------------------------------- |
-| `RCPurchaserInfo` | `RCCustomerInfo` |
-| `RCTransaction` | `RCStoreTransaction` |
-| `RCTransaction.productId` | `RCStoreTransaction.productIdentifier` |
-| `RCTransaction.revenueCatId` | `RCStoreTransaction.transactionIdentifier` |
-| `RCPackage.product` | `RCPackage.storeProduct` |
+| v3 | v4 |
+| ---------------------------------------------------------- | --------------------------------------------- |
+| `RCPurchaserInfo` | `RCCustomerInfo` |
+| `RCTransaction` | `RCStoreTransaction` |
+| `RCTransaction.productId` | `RCStoreTransaction.productIdentifier` |
+| `RCTransaction.revenueCatId` | `RCStoreTransaction.transactionIdentifier` |
+| `RCPackage.product` | `RCPackage.storeProduct` |
| `(RCPurchasesErrorCode).RCOperationAlreadyInProgressError` | `RCOperationAlreadyInProgressForProductError` |
-| `RCPurchasesErrorDomain` | `RCPurchasesErrorCodeDomain` |
-| `RCBackendError` | REMOVED |
-| `RCErrorUtils` | REMOVED |
-| `RCBackendErrorDomain` | REMOVED |
-| `RCFinishableKey` | REMOVED |
-| `RCReceivePurchaserInfoBlock` | REMOVED |
-| `RCReceiveIntroEligibilityBlock` | REMOVED |
-| `RCReceiveOfferingsBlock` | REMOVED |
-| `RCReceiveProductsBlock` | REMOVED |
-| `RCPurchaseCompletedBlock` | REMOVED |
-| `RCDeferredPromotionalPurchaseBlock` | REMOVED |
-| `RCPaymentDiscountBlock` | REMOVED |
-| `RCPaymentModeNone` | REMOVED |
+| `RCPurchasesErrorDomain` | `RCPurchasesErrorCodeDomain` |
+| `RCBackendError` | REMOVED |
+| `RCErrorUtils` | REMOVED |
+| `RCBackendErrorDomain` | REMOVED |
+| `RCFinishableKey` | REMOVED |
+| `RCReceivePurchaserInfoBlock` | REMOVED |
+| `RCReceiveIntroEligibilityBlock` | REMOVED |
+| `RCReceiveOfferingsBlock` | REMOVED |
+| `RCReceiveProductsBlock` | REMOVED |
+| `RCPurchaseCompletedBlock` | REMOVED |
+| `RCDeferredPromotionalPurchaseBlock` | REMOVED |
+| `RCPaymentDiscountBlock` | REMOVED |
+| `RCPaymentModeNone` | REMOVED |
#### PurchasesDelegate
-| v3 | v4 |
-| ------------ | ------------------------------------- |
+
+| v3 | v4 |
+| ------------------------------------------- | ---------------------------------------- |
| `purchases:didReceiveUpdatedPurchaserInfo:` | `purchases:receivedUpdatedCustomerInfo:` |
### API changes
-| v3 | v4 |
-| ------------ | ------------------------------------- |
-| `purchaserInfoWithCompletion:` | `getCustomerInfoWithCompletion:` |
-| `invalidatePurchaserInfoCache` | `invalidateCustomerInfoCache` |
-| `restoreTransactionsWithCompletion:` | `restorePurchasesWithCompletion:` |
-| `offeringsWithCompletion:` | `getOfferingsWithCompletion:` |
-| `productsWithIdentifiers:completion:` | `getProductsWithIdentifiers:completion:` |
-| `paymentDiscountForProductDiscount:product:completion:` | *REMOVED* - Check eligibility for a discount using `checkPromotionalOfferEligibility:`, then pass the discount directly to `purchasePackage:withDiscount:completion:` or `purchaseProduct:withDiscount:completion:` |
-| `createAlias:` | `logIn:` |
-| `identify:` | `logIn:` |
-| `reset:` | `logOut:` |
+| v3 | v4 |
+| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `purchaserInfoWithCompletion:` | `getCustomerInfoWithCompletion:` |
+| `invalidatePurchaserInfoCache` | `invalidateCustomerInfoCache` |
+| `restoreTransactionsWithCompletion:` | `restorePurchasesWithCompletion:` |
+| `offeringsWithCompletion:` | `getOfferingsWithCompletion:` |
+| `productsWithIdentifiers:completion:` | `getProductsWithIdentifiers:completion:` |
+| `paymentDiscountForProductDiscount:product:completion:` | _REMOVED_ - Check eligibility for a discount using `checkPromotionalOfferEligibility:`, then pass the discount directly to `purchasePackage:withDiscount:completion:` or `purchaseProduct:withDiscount:completion:` |
+| `createAlias:` | `logIn:` |
+| `identify:` | `logIn:` |
+| `reset:` | `logOut:` |
## Swift
+
### Type changes
`import Purchases` is now `import RevenueCat`
-| v3 | v4 |
-| ------------ | ------------------------------------- |
-| `Purchases.Offering` | ``Offering`` |
-| `Purchases.ErrorDomain` | See error handling below |
-| `Purchases.ErrorCode.Code` | See error handling below |
-| `Purchases.Package` | ``Package`` |
-| `Purchases.PurchaserInfo` | `CustomerInfo` |
-| `Purchases.EntitlementInfos` | ``EntitlementInfos`` |
-| `Purchases.Transaction` | ``StoreTransaction`` |
-| `Purchases.Transaction.productId` | `StoreTransaction.productIdentifier` |
-| `Purchases.Transaction.revenueCatId` | `StoreTransaction.transactionIdentifier` |
-| `Purchases.EntitlementInfo` | ``EntitlementInfo`` |
-| `Purchases.PeriodType` | ``PeriodType`` |
-| `Purchases.Store` | ``Store`` |
-| `RCPurchaseOwnershipType` | ``PurchaseOwnershipType`` |
-| `RCAttributionNetwork` | ``AttributionNetwork`` |
-| `RCIntroEligibility` | ``IntroEligibility`` |
-| `RCIntroEligibilityStatus` | ``IntroEligibilityStatus`` |
-| `RCPaymentMode` | ``StoreProductDiscount.PaymentMode`` |
-| `RCPaymentModeNone` | REMOVED |
-| `Purchases.LogLevel` | ``LogLevel`` |
-| `Purchases.Offerings` | ``Offerings`` |
-| `Purchases.PackageType` | ``PackageType`` |
-| `Package.product` | ``Package.storeProduct`` |
-| `Package.product.price`: **NSDecimalNumber** | ``StoreProduct.price``: **Decimal** |
-| `Package.localizedIntroductoryPriceString`: **String** | ``Package.localizedIntroductoryPriceString``: **String?** |
-| `RCDeferredPromotionalPurchaseBlock` | ``DeferredPromotionalPurchaseBlock`` |
-| `Purchases.PurchaseCompletedBlock` | ``PurchaseCompletedBlock`` |
-| `Purchases.ReceivePurchaserInfoBlock` | REMOVED |
-| `Purchases.ReceiveOfferingsBlock` | REMOVED |
-| `Purchases.ReceiveProductsBlock` | REMOVED |
-| `Purchases.PaymentDiscountBlock` | REMOVED |
-| `Purchases.RevenueCatBackendErrorCode` | REMOVED |
-| `Purchases.ErrorCode.operationAlreadyInProgressError` | ``RevenueCat.ErrorCode.operationAlreadyInProgressForProductError`` |
-| `Purchases.ErrorUtils` | REMOVED |
-| `ReadableErrorCodeKey` | REMOVED |
-| `RCFinishableKey` | REMOVED |
+| v3 | v4 |
+| ------------------------------------------------------ | ---------------------------------------------------------------- |
+| `Purchases.Offering` | `Offering` |
+| `Purchases.ErrorDomain` | See error handling below |
+| `Purchases.ErrorCode.Code` | See error handling below |
+| `Purchases.Package` | `Package` |
+| `Purchases.PurchaserInfo` | `CustomerInfo` |
+| `Purchases.EntitlementInfos` | `EntitlementInfos` |
+| `Purchases.Transaction` | `StoreTransaction` |
+| `Purchases.Transaction.productId` | `StoreTransaction.productIdentifier` |
+| `Purchases.Transaction.revenueCatId` | `StoreTransaction.transactionIdentifier` |
+| `Purchases.EntitlementInfo` | `EntitlementInfo` |
+| `Purchases.PeriodType` | `PeriodType` |
+| `Purchases.Store` | `Store` |
+| `RCPurchaseOwnershipType` | `PurchaseOwnershipType` |
+| `RCAttributionNetwork` | `AttributionNetwork` |
+| `RCIntroEligibility` | `IntroEligibility` |
+| `RCIntroEligibilityStatus` | `IntroEligibilityStatus` |
+| `RCPaymentMode` | `StoreProductDiscount.PaymentMode` |
+| `RCPaymentModeNone` | REMOVED |
+| `Purchases.LogLevel` | `LogLevel` |
+| `Purchases.Offerings` | `Offerings` |
+| `Purchases.PackageType` | `PackageType` |
+| `Package.product` | `Package.storeProduct` |
+| `Package.product.price`: **NSDecimalNumber** | `StoreProduct.price`: **Decimal** |
+| `Package.localizedIntroductoryPriceString`: **String** | `Package.localizedIntroductoryPriceString`: **String?** |
+| `RCDeferredPromotionalPurchaseBlock` | `DeferredPromotionalPurchaseBlock` |
+| `Purchases.PurchaseCompletedBlock` | `PurchaseCompletedBlock` |
+| `Purchases.ReceivePurchaserInfoBlock` | REMOVED |
+| `Purchases.ReceiveOfferingsBlock` | REMOVED |
+| `Purchases.ReceiveProductsBlock` | REMOVED |
+| `Purchases.PaymentDiscountBlock` | REMOVED |
+| `Purchases.RevenueCatBackendErrorCode` | REMOVED |
+| `Purchases.ErrorCode.operationAlreadyInProgressError` | `RevenueCat.ErrorCode.operationAlreadyInProgressForProductError` |
+| `Purchases.ErrorUtils` | REMOVED |
+| `ReadableErrorCodeKey` | REMOVED |
+| `RCFinishableKey` | REMOVED |
### API changes
-| v3 | v4 |
-| ------------ | ------------------------------------- |
-| `invalidatePurchaserInfoCache` | `invalidateCustomerInfoCache()` |
-| `logIn(_ appUserId:, _ completion:)` | `logIn(_:completion:)` |
-| `createAlias(_ alias:, _ completion:)` | `logIn(_:completion:)` |
-| `identify(_ appUserID:, _ completion:)` | `logIn(_:completion:)` |
-| `reset(completion:)` | `logOut(completion:)` |
-| `purchaserInfo(_ completion:)` | `getCustomerInfo(completion:)` |
-| `offerings(_ completion:)` | `getOfferings(completion:)` |
-| `products(_ productIdentifiers:, _ completion:)` | `getProducts(_:completion:)` |
-| `purchaseProduct(_ product:, _ completion:)` | `purchase(product:completion:)` |
-| `purchasePackage(_ package:, _ completion:)` | `purchase(package:completion:)` |
-| `restoreTransactions(_ completion:)` | `restorePurchases(completion:)` |
-| `syncPurchases(_ completion:)` | `syncPurchases(completion:)` |
-| `paymentDiscount(for:product:completion:)` | REMOVED - Check eligibility for a discount using `checkPromotionalDiscountEligibility(forProductDiscount:product:)`, then pass the discount directly to `purchase(package:discount:)` or `purchase(product:discount:)` |
-| `purchaseProduct(_:discount:_)` | `purchase(product:discount:completion:)` |
-| `purchasePackage(_:discount:_)` | `purchase(package:discount:completion:)` |
+| v3 | v4 |
+| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `invalidatePurchaserInfoCache` | `invalidateCustomerInfoCache()` |
+| `logIn(_ appUserId:, _ completion:)` | `logIn(_:completion:)` |
+| `createAlias(_ alias:, _ completion:)` | `logIn(_:completion:)` |
+| `identify(_ appUserID:, _ completion:)` | `logIn(_:completion:)` |
+| `reset(completion:)` | `logOut(completion:)` |
+| `purchaserInfo(_ completion:)` | `getCustomerInfo(completion:)` |
+| `offerings(_ completion:)` | `getOfferings(completion:)` |
+| `products(_ productIdentifiers:, _ completion:)` | `getProducts(_:completion:)` |
+| `purchaseProduct(_ product:, _ completion:)` | `purchase(product:completion:)` |
+| `purchasePackage(_ package:, _ completion:)` | `purchase(package:completion:)` |
+| `restoreTransactions(_ completion:)` | `restorePurchases(completion:)` |
+| `syncPurchases(_ completion:)` | `syncPurchases(completion:)` |
+| `paymentDiscount(for:product:completion:)` | REMOVED - Check eligibility for a discount using `checkPromotionalDiscountEligibility(forProductDiscount:product:)`, then pass the discount directly to `purchase(package:discount:)` or `purchase(product:discount:)` |
+| `purchaseProduct(_:discount:_)` | `purchase(product:discount:completion:)` |
+| `purchasePackage(_:discount:_)` | `purchase(package:discount:completion:)` |
#### PurchasesDelegate
-| v3 | v4 |
-| ------------ | ------------------------------------- |
-| `purchases(_ purchases: Purchases, didReceiveUpdated purchaserInfo: PurchaserInfo)` | ``purchases(_:receivedUpdated:)`` |
+
+| v3 | v4 |
+| ----------------------------------------------------------------------------------- | ------------------------------- |
+| `purchases(_ purchases: Purchases, didReceiveUpdated purchaserInfo: PurchaserInfo)` | `purchases(_:receivedUpdated:)` |
### Error handling
Prior to the Swift migration, `Purchases` exposed errors as `NSError`'s, so one could detect errors like this:
-
import content1 from "!!raw-loader!@site/code_blocks/sdk-guides/ios-native-3x-to-4x-migration_1.swift";
-
-
+ type: "swift",
+ content: content1,
+ },
+ ]}
+/>
Starting from Version 4, this becomes much simpler:
import content2 from "!!raw-loader!@site/code_blocks/sdk-guides/ios-native-3x-to-4x-migration_2.swift";
-
+ type: "swift",
+ content: content2,
+ },
+ ]}
+/>
## New APIs
- All applicable methods have an alternative [async/await version](https://docs.swift.org/swift-book/LanguageGuide/Concurrency.html).
-- `showManageSuscriptions(completion:)`: Use this method to show the subscription management for the current user. Depending on where they made the purchase and their OS version, this might take them to the `managementURL`, or open the iOS Subscription Management page.
+- `showManageSuscriptions(completion:)`: Use this method to show the subscription management for the current user. Depending on where they made the purchase and their OS version, this might take them to the `managementURL`, or open the iOS Subscription Management page.
- `beginRefundRequestForCurrentEntitlement`: Use this method to begin a refund request for the purchase that granted the current entitlement.
- `beginRefundRequest(forProduct:)`: Use this method to begin a refund request for a purchase, specifying the product identifier.
- `beginRefundRequest(forEntitlement:)`: Use this method to begin a refund request for a purchase, specifying the entitlement identifier.
## Reporting undocumented issues
-Feel free to file an issue! [New RevenueCat Issue](https://github.com/RevenueCat/purchases-ios/issues/new/).
\ No newline at end of file
+Feel free to file an issue! [New RevenueCat Issue](https://github.com/RevenueCat/purchases-ios/issues/new/).
diff --git a/docs/sdk-guides/ios-native-4x-to-5x-migration.mdx b/docs/sdk-guides/ios-native-4x-to-5x-migration.mdx
index cd616d710..40464d0f9 100644
--- a/docs/sdk-guides/ios-native-4x-to-5x-migration.mdx
+++ b/docs/sdk-guides/ios-native-4x-to-5x-migration.mdx
@@ -13,9 +13,10 @@ When upgrading to v5, you **must** configure your [In-App Purchase Key](/service
Version 5.0 of the RevenueCat SDK enables full StoreKit 2 flow on the SDK and the RevenueCat backend by default. We have been testing StoreKit 2 support in parallel to StoreKit 1 in our backend for a while and we believe it is ready for widespread use.
Here's some of the benefits you get with StoreKit 2:
+
- Better handling of a few specific edge cases which were unfixable with StoreKit 1:
- - No more "Missing receipt" errors in Sandbox that could result in failure restoring purchases or getting trial eligibility status "unknown".
- - No more "The purchased product was missing in the receipt" error that could cause an invalid receipt error when making a purchase.
+ - No more "Missing receipt" errors in Sandbox that could result in failure restoring purchases or getting trial eligibility status "unknown".
+ - No more "The purchased product was missing in the receipt" error that could cause an invalid receipt error when making a purchase.
- Future proofing: StoreKit 1 APIs are being progressively deprecated by Apple, and new features are being added to StoreKit 2.
- Faster processing time: More efficient and performant implementation of receipts validation. We have found that receipts validation can be ~200ms faster comparing to SK1 implementation for p95 of the requests.
@@ -27,12 +28,14 @@ If for any reason you need to always use StoreKit 1, it is possible to switch ba
import content1 from "!!raw-loader!@site/code_blocks/sdk-guides/ios-native-4x-to-5x-migration_1.swift";
-
+ type: "swift",
+ content: content1,
+ },
+ ]}
+/>
### 3rd Party Analytics SDKs
@@ -42,7 +45,7 @@ If you're using the Firebase SDK, you'll need to follow [these instructions](htt
### Observer Mode is now PurchasesAreCompletedBy
-Version 5.0 of the SDK deprecates the term "Observer Mode" (and the APIs where this term was used), and replaces it
+Version 5.0 of the SDK deprecates the term "Observer Mode" (and the APIs where this term was used), and replaces it
with `PurchasesAreCompletedBy` (either RevenueCat or your app).
Version 5.0 of the SDK also introduces support for tracking purchases made directly by your app calling StoreKit 2.
@@ -54,8 +57,8 @@ Add this configuration only if you previously had `observerMode: true` in your S
import content2 from "!!raw-loader!@site/code_blocks/sdk-guides/ios-native-4x-to-5x-migration_2.swift";
import content3 from "!!raw-loader!@site/code_blocks/sdk-guides/ios-native-4x-to-5x-migration_3.swift";
-| Version 4 | Version 5 |
-|------------|------------|
+| Version 4 | Version 5 |
+| ----------------------------------------------------------- | ----------------------------------------------------------- |
| | |
#### ⚠️ Observing Purchases Completed by Your App on macOS
@@ -64,12 +67,14 @@ By default, when purchases are completed by your app using StoreKit 2 on macOS,
import content4 from "!!raw-loader!@site/code_blocks/sdk-guides/ios-native-4x-to-5x-migration_4.swift";
-
+ type: "swift",
+ content: content4,
+ },
+ ]}
+/>
## Trusted Entitlements
@@ -79,6 +84,7 @@ Informational mode logs verification errors and allow you to check `customerInfo
See the [Trusted Entitlements documentation](/customers/trusted-entitlements) for more information.
## Deployment Target
+
The minimum targets have been raised to the following:
- iOS 13.0
@@ -87,8 +93,10 @@ The minimum targets have been raised to the following:
- macOS 10.15
## Release Assets
+
Pre-built `.frameworks` are no longer included in releases, only `.xcframeworks`: https://github.com/RevenueCat/purchases-ios/pull/3582
## Breaking Changes
+
- The scope of the View extension `onChangeOf` is changed from `public` to `internal`
- - This was never intended to be made public and to be used outside of the RevenueCat SDK
\ No newline at end of file
+ - This was never intended to be made public and to be used outside of the RevenueCat SDK
diff --git a/docs/service-credentials/amazon-appstore-credentials.mdx b/docs/service-credentials/amazon-appstore-credentials.mdx
index 2d70bc58d..6d05e9736 100644
--- a/docs/service-credentials/amazon-appstore-credentials.mdx
+++ b/docs/service-credentials/amazon-appstore-credentials.mdx
@@ -5,7 +5,8 @@ slug: amazon-appstore-credentials
excerpt: Getting your Amazon Appstore Shared Secret
hidden: false
---
-The Amazon Shared Secret allows RevenueCat to connect with Amazon on your behalf.
+
+The Amazon Shared Secret allows RevenueCat to connect with Amazon on your behalf.
## Setup
@@ -19,4 +20,4 @@ The Amazon Shared Secret allows RevenueCat to connect with Amazon on your behalf
In your Amazon app settings in the RevenueCat dashboard, enter the key in the configuration section:
-
\ No newline at end of file
+
diff --git a/docs/service-credentials/creating-play-service-credentials.mdx b/docs/service-credentials/creating-play-service-credentials.mdx
index c842c8e3e..26e0e4640 100644
--- a/docs/service-credentials/creating-play-service-credentials.mdx
+++ b/docs/service-credentials/creating-play-service-credentials.mdx
@@ -4,11 +4,15 @@ slug: creating-play-service-credentials
excerpt: Step-by-step guide for creating your Play service credentials
hidden: false
---
+
In order for RevenueCat's servers to communicate with Google on your behalf, you need to provide a set of service credentials. The process for configuring these credentials is a bit complex, but the added level of control improves security by providing RevenueCat with only the access we need.
-
+
-
+
:::info Credentials can take up to 36 hours after being created to be valid
@@ -22,6 +26,7 @@ Note that this setup takes place on both the Google Play Console and the Google
### 1. Enable the Google Developer and Reporting API
To enable the Developer and Reporting APIs for your Google Cloud Project, you’ll want to do the following:
+
1. Go to the [API Console](https://console.developers.google.com/).
2. From the projects list, select a project or create a new one.
3. Go to the [Google Play Android Developer API page](https://console.cloud.google.com/apis/library/androidpublisher.googleapis.com) and the [Google Play Developer Reporting API page](https://console.cloud.google.com/apis/library/playdeveloperreporting.googleapis.com) in Google Cloud Console.
@@ -33,7 +38,6 @@ After enabling the API, you will be redirected to your Google Cloud API page. Fr
You will then be redirected to create your form of credentials which you can follow step 2 for. If you just created your credentials, you may see the “To use this API, you may need credentials” message on your API console, this is because your credentials have not yet been validated. This will be done automatically by Google.
-
### 2. Create a Service Account
- Where: Google Cloud Console
@@ -51,20 +55,20 @@ On the step named '**Grant this service account access to project**', you'll add
Note that searching by name in the filter does not always bring up both roles. You can also find each by scrolling through the list - in the Pub/Sub and Monitoring folders respectively.
-You can skip the optional third step, and select done.
+You can skip the optional third step, and select done.

#### b. Create and download the private key
-In the '**Service Accounts**' section of the Google Cloud Console, select the three dots for the Actions dropdown menu, then Manage Keys.
+In the '**Service Accounts**' section of the Google Cloud Console, select the three dots for the Actions dropdown menu, then Manage Keys.
Select Add Key, then Create new key. On the pop up, make sure JSON is selected, and then create and download the JSON Key. We'll use this in Step 4.

:::warning Constraints on Service Accounts
-If you've created your organization in Google Cloud on or after May 3rd, 2024, there may be some default constraints placed on service account creation and usage.
+If you've created your organization in Google Cloud on or after May 3rd, 2024, there may be some default constraints placed on service account creation and usage.
If you see any errors relating to organization policy constraints `iam.disableServiceAccountCreation` or `iam.disableServiceAccountKeyCreation` when creating your service account or creating your JSON key, these constraints may need to be turned off. You can do so by navigating to your project in Google Cloud Console -> "IAM & Admin" -> "Organization Policies" -> "Disable service account creation" or "Disable service account key creation".
:::
@@ -92,7 +96,6 @@ Select invite user at the bottom of the page, and send the invite. You'll then b

-
### 4. Enter the Credentials JSON in RevenueCat
- Where: RevenueCat Dashboard
@@ -115,16 +118,16 @@ While you’re in your RevenueCat Play Store App settings and waiting for your c
- Where: Google Play Console
You may have done this already, but please ensure that:
+
1. You have uploaded your signed APK or Android App Bundle to Google Play Console
2. You have completed all the steps to approve the release
3. The app is in a Closed or Open testing track and you've added a tester
4. Your Subscriptions are in an 'Active' state
5. Your Google Play Package Name exactly matches the one in RevenueCat
-
## Check the status of your credentials
-With our Google Play credential validation, we will validate every time Google credentials are (re)uploaded or at any time through a click of a button.
+With our Google Play credential validation, we will validate every time Google credentials are (re)uploaded or at any time through a click of a button.

@@ -133,6 +136,7 @@ A summary message will appear with the results of the validation to provide you

## Troubleshooting
+
This guide contains a lot of information and many steps, and it can be all too easy to move too quickly or simply misconfigure something. To help troubleshoot your credentials, you should confirm the following:
#### 1. Confirm checklist
@@ -141,7 +145,7 @@ Let's break down each step by where it needs to take place as you're going throu
#### 2. Credentials are enabled
-When creating your service account for the first time, the account is enabled by default. However, [Google may automatically disable your service account if it detects that the credentials were leaked](https://cloud.google.com/blog/products/identity-security/automatically-disabling-leaked-service-account-keys-what-you-need-to-know), or the account might have accidentally been disabled in the Google Cloud console.
+When creating your service account for the first time, the account is enabled by default. However, [Google may automatically disable your service account if it detects that the credentials were leaked](https://cloud.google.com/blog/products/identity-security/automatically-disabling-leaked-service-account-keys-what-you-need-to-know), or the account might have accidentally been disabled in the Google Cloud console.
To confirm that the service account is enabled, navigate to your [Google Cloud console](https://console.cloud.google.com/iam-admin/serviceaccounts) to check that the entry for your RevenueCat service account shows "Enabled".
@@ -151,7 +155,7 @@ If the account shows as disabled, we do not recommend re-enabling your credentia
#### 3. The JSON file uploaded to RevenueCat is the correct file
-You should confirm that the JSON file uploaded to RevenueCat is the correct file. To double check which file was uploaded, you can select the info icon and check your service account's 'Project ID', 'Private Key ID', and 'Client Email'.
+You should confirm that the JSON file uploaded to RevenueCat is the correct file. To double check which file was uploaded, you can select the info icon and check your service account's 'Project ID', 'Private Key ID', and 'Client Email'.

@@ -159,15 +163,15 @@ You should confirm that the JSON file uploaded to RevenueCat is the correct file
Whenever credentials are not working properly, we recommend re-uploading your credentials. This will help rule out if the incorrect JSON file was uploaded to RevenueCat by you or your collaborator(s).
-### Credential validator troubleshooting
+### Credential validator troubleshooting
Once you've confirmed your credentials are enabled and the correct JSON file as been uploaded into RevenueCat, let's dive deeper into the credential validator's summary message.
-| Permissions: | Why it's not passing: | What to do: |
-| :--------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| subscriptions API | We were unable to use your credentials to receive a response from Google's [GET subscriptions endpoint](https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.subscriptionsv2/get). | Ensure that you have granted the following permissions:
View financial data in [step 3](/service-credentials/creating-play-service-credentials#3-grant-financial-access-to-revenuecat)
Manage orders and subscriptions in [step 3](/service-credentials/creating-play-service-credentials#3-grant-financial-access-to-revenuecat)
Once this is done, try to make a test purchase using a [Sandbox user](/test-and-launch/sandbox/google-play-store) in order to check if the connection to the subscriptions API is working.
You will also want to make sure that you have uploaded your signed APK or Android App Bundle and have completed all the steps to approve the release. |
-| inappproducts API | We were unable to use your credentials to receive a response from Google's [GET inappproducts endpoint](https://developers.google.com/android-publisher/api-ref/rest/v3/inappproducts/get). | Ensure that you have granted the following permission:
View app information and download bulk reports (read-only) in [step 3](/service-credentials/creating-play-service-credentials#3-grant-financial-access-to-revenuecat)
|
-| monetization API | We were unable to use your credentials to receive a response from Google's [LIST monetization endpoint](https://developers.google.com/android-publisher/api-ref/rest/v3/monetization.subscriptions/list). | Ensure that you have granted the following permission:
View financial data in [step 3](/service-credentials/creating-play-service-credentials#3-grant-financial-access-to-revenuecat)
|
+| Permissions: | Why it's not passing: | What to do: |
+| :---------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| subscriptions API | We were unable to use your credentials to receive a response from Google's [GET subscriptions endpoint](https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.subscriptionsv2/get). | Ensure that you have granted the following permissions:
View financial data in [step 3](/service-credentials/creating-play-service-credentials#3-grant-financial-access-to-revenuecat)
Manage orders and subscriptions in [step 3](/service-credentials/creating-play-service-credentials#3-grant-financial-access-to-revenuecat)
Once this is done, try to make a test purchase using a [Sandbox user](/test-and-launch/sandbox/google-play-store) in order to check if the connection to the subscriptions API is working.
You will also want to make sure that you have uploaded your signed APK or Android App Bundle and have completed all the steps to approve the release. |
+| inappproducts API | We were unable to use your credentials to receive a response from Google's [GET inappproducts endpoint](https://developers.google.com/android-publisher/api-ref/rest/v3/inappproducts/get). | Ensure that you have granted the following permission:
View app information and download bulk reports (read-only) in [step 3](/service-credentials/creating-play-service-credentials#3-grant-financial-access-to-revenuecat)
|
+| monetization API | We were unable to use your credentials to receive a response from Google's [LIST monetization endpoint](https://developers.google.com/android-publisher/api-ref/rest/v3/monetization.subscriptions/list). | Ensure that you have granted the following permission:
View financial data in [step 3](/service-credentials/creating-play-service-credentials#3-grant-financial-access-to-revenuecat)
|
After making changes to your Google credentials, it may take 24 hours, up to 36 hours, for the changes to populate throughout Google's servers. For a potential workaround that could help get your credentials validated faster, see the info note under [step 4](/service-credentials/creating-play-service-credentials#4-enter-the-credentials-json-in-revenuecat).
@@ -177,17 +181,17 @@ Below are the most commonly occurring errors when setting up your service creden
#### Dashboard errors
-| Error message: | What to do: |
-| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| 'Your Google Service Account credentials do not have permissions to access the needed Google resources. Refer to [this guide](/service-credentials/creating-play-service-credentials) for more information.' | Confirm that the roles granted to your service account in Google Cloud match: **Pub/Sub Admin** and **Monitoring Viewer**. If you change them or update them at all, make sure that you re-generate your JSON key to add to RevenueCat. |
-| 'The provided Google Service Account credentials JSON is invalid.' | Re-generate the JSON key from Google Cloud and try uploading it to RevenueCat again. If you get the same error, try re-creating your service account. |
-| 'Google Play service account credentials must be set up before using this feature.' | This one is most likely to crop up if trying to perform an action that communicates with Google, such as importing products for Android, before setting up service credentials. |
-| 'Account permissions are invalid for this request.' | Not all RevenueCat collaborators have the same permissions. In order to make changes to an app's configuration (such as creating service credentials), a user must be listed as an 'Admin'. |
-| 'Google Cloud Pub/Sub API must first be enabled. Enable it by visiting your [Google Cloud Platform console](https://console.developers.google.com/apis/library/pubsub.googleapis.com)' | Enable access to the Pub/Sub API on the Google Cloud Console for the same project that you used to set up your service credentials. |
-| 'Your Google service account credentials do not have permissions to access the Google Cloud Pub/Sub API. Refer to [this guide](/service-credentials/creating-play-service-credentials) for more information.' | This points to either the Pub/ Sub API access not being enabled, or the Pub/Sub role that has been added to the service account is not the admin role. Double check that your service account has the correct roles, and if changing them, re-generate the JSON key and re-add it to RevenueCat. |
+| Error message: | What to do: |
+| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| 'Your Google Service Account credentials do not have permissions to access the needed Google resources. Refer to [this guide](/service-credentials/creating-play-service-credentials) for more information.' | Confirm that the roles granted to your service account in Google Cloud match: **Pub/Sub Admin** and **Monitoring Viewer**. If you change them or update them at all, make sure that you re-generate your JSON key to add to RevenueCat. |
+| 'The provided Google Service Account credentials JSON is invalid.' | Re-generate the JSON key from Google Cloud and try uploading it to RevenueCat again. If you get the same error, try re-creating your service account. |
+| 'Google Play service account credentials must be set up before using this feature.' | This one is most likely to crop up if trying to perform an action that communicates with Google, such as importing products for Android, before setting up service credentials. |
+| 'Account permissions are invalid for this request.' | Not all RevenueCat collaborators have the same permissions. In order to make changes to an app's configuration (such as creating service credentials), a user must be listed as an 'Admin'. |
+| 'Google Cloud Pub/Sub API must first be enabled. Enable it by visiting your [Google Cloud Platform console](https://console.developers.google.com/apis/library/pubsub.googleapis.com)' | Enable access to the Pub/Sub API on the Google Cloud Console for the same project that you used to set up your service credentials. |
+| 'Your Google service account credentials do not have permissions to access the Google Cloud Pub/Sub API. Refer to [this guide](/service-credentials/creating-play-service-credentials) for more information.' | This points to either the Pub/ Sub API access not being enabled, or the Pub/Sub role that has been added to the service account is not the admin role. Double check that your service account has the correct roles, and if changing them, re-generate the JSON key and re-add it to RevenueCat. |
#### SDK error
-| Error: | Underlying message: | What to do: |
-| :------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `InvalidCredentialsError` | 'Invalid Play Store credentials.' | Unfortunately, this one is a little vague. Run through the guide again, ensuring that all steps have been followed. If you've already waited for over 36 hours and continue to get this error, try starting over from the beginning. |
+| Error: | Underlying message: | What to do: |
+| :------------------------ | :-------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `InvalidCredentialsError` | 'Invalid Play Store credentials.' | Unfortunately, this one is a little vague. Run through the guide again, ensuring that all steps have been followed. If you've already waited for over 36 hours and continue to get this error, try starting over from the beginning. |
diff --git a/docs/service-credentials/creating-play-service-credentials/google-play-checklists.mdx b/docs/service-credentials/creating-play-service-credentials/google-play-checklists.mdx
index 8c9861e57..fdb97eeff 100644
--- a/docs/service-credentials/creating-play-service-credentials/google-play-checklists.mdx
+++ b/docs/service-credentials/creating-play-service-credentials/google-play-checklists.mdx
@@ -52,7 +52,9 @@ Note that while our [credentials guide](/service-credentials/creating-play-servi
{" "}
@@ -64,7 +66,8 @@ Note that while our [credentials guide](/service-credentials/creating-play-servi
{" "}
### In RevenueCat:
@@ -86,7 +91,8 @@ Note that while our [credentials guide](/service-credentials/creating-play-servi
the RevenueCat dashboard and clicked **'Save Changes'**
---
@@ -122,7 +128,8 @@ Note that while our [credentials guide](/service-credentials/creating-play-servi
### In Google Play: