# App Store subscription tracking

<Aside type="caution" icon="setting" title="Developer assistance needed">
You'll need help from your development team to set up this integration. Please share this guide with them.
</Aside>

## Integration overview

[App Store Server Notifications](https://developer.apple.com/documentation/appstoreservernotifications) is Apple's server-to-server service that sends your backend a real-time message whenever a subscription's status changes.

By connecting App Store Server Notifications to Pushwoosh, you can react to the entire subscription lifecycle, including purchases, renewals, cancellations, billing problems, expirations, and refunds — without building your own backend infrastructure. Whenever a subscription's status changes in a user's App Store account, Apple notifies Pushwoosh, and Pushwoosh fires the matching [`PW_Subscription*`](#tracked-events) event on the user profile.

<Aside type="note">
This integration supports **iOS subscriptions** (App Store Server Notifications V2). To track Android subscriptions, see [Google Play subscription tracking](/product/integrations/google-play-subscription-tracking/).
</Aside>

### Integration type

**Source:** App Store Server Notifications are sent from Apple to Pushwoosh.

### Tracked events

Pushwoosh maps every supported App Store notification to a unified `PW_Subscription*` event set, so you can trigger campaigns on any stage of the subscription lifecycle.

| Event | Fires when |
| ----- | ---------- |
| `PW_SubscriptionStart` | A user buys the subscription for the first time. |
| `PW_SubscriptionRenew` | The subscription auto-renews for a new billing period. |
| `PW_SubscriptionCancel` | A user turns off auto-renewal. The subscription stays active until it expires. |
| `PW_SubscriptionResume` | A user re-enables auto-renewal, or resubscribes before the subscription lapses. |
| `PW_SubscriptionBillingIssue` | A renewal payment fails and the subscription enters Apple's billing retry period. |
| `PW_SubscriptionRecovered` | A previously failed renewal goes through and the subscription is active again. |
| `PW_SubscriptionExpired` | The subscription has fully lapsed and is no longer active. |
| `PW_SubscriptionRefund` | Apple refunds the purchase or revokes access. |

Every event carries the same attributes:

- **productID:** the App Store product identifier of the subscription.
- **expiresAt:** when the current paid period ends, as a Unix timestamp in seconds. Included when Apple provides it.

<details>

<summary>How events map to App Store Server Notifications</summary>

For developers verifying the integration, each Pushwoosh event corresponds to these App Store `notificationType` (and `subtype`) values:

| Pushwoosh event | `notificationType` / `subtype` |
| --------------- | ------------------------------ |
| `PW_SubscriptionStart` | `SUBSCRIBED` / `INITIAL_BUY` |
| `PW_SubscriptionRenew` | `DID_RENEW` |
| `PW_SubscriptionCancel` | `DID_CHANGE_RENEWAL_STATUS` / `AUTO_RENEW_DISABLED` |
| `PW_SubscriptionResume` | `DID_CHANGE_RENEWAL_STATUS` / `AUTO_RENEW_ENABLED`, `SUBSCRIBED` / `RESUBSCRIBE` |
| `PW_SubscriptionBillingIssue` | `DID_FAIL_TO_RENEW` |
| `PW_SubscriptionRecovered` | `DID_RENEW` / `BILLING_RECOVERY` |
| `PW_SubscriptionExpired` | `EXPIRED` |
| `PW_SubscriptionRefund` | `REFUND`, `REVOKE` |

Other notification types, such as price increases, plan changes, on-hold, and consumption requests, are acknowledged but don't post an event.

</details>


### How it works

1. A subscription's status changes in a user's App Store account (a purchase, renewal, cancellation, and so on).
2. Apple sends an App Store Server Notification (V2) to your Pushwoosh notification URL.
3. Pushwoosh decodes the signed payload and reads the `appAccountToken` from the transaction.
4. Pushwoosh looks up the device whose HWID matches that token, finds the user bound to it, and posts the matching `PW_Subscription*` event for that user.

<Aside type="caution" title="Important">
The match between an App Store transaction and a Pushwoosh user relies on the `appAccountToken`. If your app doesn't set this token at purchase time, Pushwoosh receives the notification but **no event is posted**. See [how to set `appAccountToken`](#set-appaccounttoken-to-the-devices-pushwoosh-hwid).
</Aside>

### Use cases

**Win back churning subscribers:** Disabling auto-renewal doesn't end access right away. The subscription stays active until the paid period ends, and that's your window to win the user back. On `PW_SubscriptionCancel`, launch a [Customer Journey](/product/customer-journey/pushwoosh-journey-overview/) with a retention push, an [email](/product/messaging-channels/emails/) about features they'd lose, or an [in-app message](/product/messaging-channels/in-apps/) with a renewal discount before access lapses.

**Onboard new subscribers:** Trigger a welcome series on `PW_SubscriptionStart` to help users get value from their plan early and set the stage for renewal.

**Rescue failed payments:** When `PW_SubscriptionBillingIssue` fires, a renewal payment didn't go through and the subscription is in Apple's retry window. Prompt the user to update their payment method before they lose access, and follow up with `PW_SubscriptionRecovered` to confirm once it's resolved.

**Re-engage lapsed users:** Start a reactivation campaign on `PW_SubscriptionExpired` with a returning-customer offer for subscribers who have fully churned.


## Setting up the integration

### Set `appAccountToken` to the device's Pushwoosh HWID

Pushwoosh identifies the right user from the device's **HWID**, so your app must attach the device's Pushwoosh HWID as the `appAccountToken` when the subscription is purchased through StoreKit.

By default, the Pushwoosh iOS SDK uses the device's `identifierForVendor` (IDFV) as the HWID. IDFV is already a `UUID`, exactly the format Apple requires for `appAccountToken`. Pushwoosh then resolves the user currently bound to that device automatically, so this works whether or not you assign your own User IDs with `setUserId`.

<Tabs>
<TabItem label="StoreKit 2">
```swift
// Attach the device's Pushwoosh HWID (the default IDFV) as the appAccountToken
var options: Set<Product.PurchaseOption> = []
if let hwid = UIDevice.current.identifierForVendor {
    options.insert(.appAccountToken(hwid))
}

let result = try await product.purchase(options: options)
```
</TabItem>
<TabItem label="StoreKit 1">
```swift
// applicationUsername must be a UUID string to populate appAccountToken
let payment = SKMutablePayment(product: product)
payment.applicationUsername = UIDevice.current.identifierForVendor?.uuidString
SKPaymentQueue.default().add(payment)
```
</TabItem>
</Tabs>

<Aside type="caution">
If your app overrides the Pushwoosh HWID (for example, via the [`PushwooshKeychain`](/developer/pushwoosh-sdk/ios-sdk/ios-keychain/) persistent HWID module or a custom value), set `appAccountToken` to that same HWID. The token must match the device's HWID in Pushwoosh, or the event cannot be attributed.
</Aside>

### Find your Pushwoosh Application Code

Open your application in the Pushwoosh Control Panel. Your **Application Code** (format `XXXXX-XXXXX`) is shown below the project name in the sidebar.

You'll need the Application Code to build the notification URL.

### Add the notification URL in App Store Connect

1. In [App Store Connect](https://appstoreconnect.apple.com/), go to **Apps → your app → App Information** (under *General*), and scroll to **App Store Server Notifications**.
2. Select **Version 2** notifications.
3. Set both the **Production Server URL** and the **Sandbox Server URL** to:

```
https://appstore-notifications.pushwoosh.com/appstore/YOUR_APPLICATION_CODE/
```

4. Replace `YOUR_APPLICATION_CODE` with the Application Code from the previous step. Keep the trailing slash.

<Aside type="note">
If your account is hosted in the **US data center**, use `https://appstore-notifications.pushwoosh.us/appstore/YOUR_APPLICATION_CODE/` instead. If you're unsure which data center your account uses, contact your Customer Success Manager or [Pushwoosh Support](https://www.pushwoosh.com/contact-us/).
</Aside>

### Confirm the events in Pushwoosh

Pushwoosh registers each `PW_Subscription*` event in your project the first time it occurs, with the `productID` and `expiresAt` attributes. After a sandbox test, open **Audience → Events** to verify the events appear. They are then ready for segmentation, statistics, and Customer Journeys.

### Build your campaign

Create a [Customer Journey](/product/customer-journey/pushwoosh-journey-overview/) with a [trigger-based entry](/product/customer-journey/journey-elements/entry-elements/trigger-based-entry/) on any `PW_Subscription*` event, for example `PW_SubscriptionCancel` for win-back or `PW_SubscriptionStart` for onboarding, and add the messages you want to send.

## Testing

App Store Server Notifications can be triggered in Apple's **Sandbox** environment. To verify the integration:

1. Make a sandbox subscription purchase with `appAccountToken` set as described above. This fires `PW_SubscriptionStart`.
2. Disable auto-renewal from the device's subscription management screen. This fires `PW_SubscriptionCancel`.
3. In Pushwoosh Control Panel, open the user profile and go to [Events history](/product/audience-data-and-segmentation/user-explorer/#events-history-tab).
4. Confirm that the events appear within a few moments.