Skip to content

6.2.0

Latest

Choose a tag to compare

@EPIKorial EPIKorial released this 08 Oct 14:58
· 1 commit to master since this release

Purchasely iOS SDK 6.2.0

6.2.0 is an additive release. There are no breaking API changes, and an existing integration builds without code changes. Read Behaviour changes if your server reads appAccountToken.

The main feature is Custom Events: your app can send its own business events to Purchasely, measure them, and open a campaign when one fires.

Highlights

📣 Custom Events

Send your own business events to Purchasely:

Purchasely.emit(name: "recipe_viewed", properties: ["recipe_id": 42, "title": "Ratatouille"])
Purchasely.emit(name: "checkout_started")
[Purchasely emitWithName:@"recipe_viewed" properties:@{@"recipe_id": @42}];
  • Declared in the Console. The SDK sends only the event names declared in the Console. Names are matched exactly, case and spaces included, so "Recipe Viewed" and "recipe_viewed" are two different events. An undeclared event is ignored.
  • Properties travel as given. Dates are sent as ISO 8601 strings. A value that cannot be sent, such as NaN or a custom object, is dropped alone, with a warning in the logs. The rest of the event is sent normally.
  • Your user attributes come along. Each event carries your user attributes and the built-in attributes as they were at the moment of the call.
  • New built-in attributes. ply_custom_events_tracked counts the events sent for each name. ply_custom_events_last_tracked holds the time of the last one. Use them to build audiences.
  • Consent is respected. When the user refuses the analytics purpose, the SDK sends no new custom events.
  • Separate from the SDK's own events. Custom events have their own queue and their own retries. They never reach your PLYEventDelegate or event listener. Existing Purchasely events keep their content and their delivery.
  • You can call emit before start().

Trigger a campaign from your own event. Link a campaign to one of your custom events in the Console. When the event fires, the SDK opens the campaign screen. The app launch campaign rules apply: dates, capping, exposure, and the campaigns consent purpose. A custom event never opens the campaigns of a Purchasely event with the same name.

Fire a custom event from a screen. The new track_event screen action sends one of your custom events. The event carries the context of the screen: presentation, placement, audience, A/B test and variant, campaign, and flow and step. Use it to measure a success KPI on a paywall. The action cannot be intercepted and never blocks the actions next to it. A button that tracks an event and then purchases still closes the paywall after the purchase.

🧾 Purchases attributed to the paywall that started them

Every purchase is now linked to the paywall, placement, campaign and A/B test that started it. This holds when the same product is bought twice, for Ask to Buy, and when the purchase completes after the app relaunches. Conversion reporting is more accurate as a result.

Observer mode: signPromotionalOffer has a new variant that returns a purchase context token along with the signature:

Purchasely.signPromotionalOffer(storeProductId: productId,
                                storeOfferId: offerId,
                                purchaseContextToken: nil,
                                success: { signature, token in
    // StoreKit 2: pass `token` as .appAccountToken(token)
    // StoreKit 1: set applicationUsername = token.uuidString.lowercased()
}, failure: { error in })

🎯 Audiences see every active subscription

Audience targeting now sees the user's current active and expired subscriptions on every request. This includes subscriptions bought on the web (Stripe, web-to-app).

🔐 New consent purpose: refundHandling

PLYDataProcessingPurpose.refundHandling lets you record that the user refused to share consumption data with Apple for refund requests. It is not part of .allNonEssentials. revokeDataProcessingConsent(for:) replaces the whole list each time you call it, so pass every refused purpose in the same call.

Behaviour changes

  • appAccountToken / applicationUsername now carry a purchase context token. Before, the SDK put the anonymous user id there. It now puts a new random UUID for each purchase, which Purchasely uses to attribute the purchase. If your server reads appAccountToken in App Store Server Notifications to identify the user, use your own user mapping or Purchasely webhooks instead.
  • Subscriptions whose plan is not in your app catalog are now returned. userSubscriptions() and the web redemption result now include them, for example a web subscription. Before, they were left out. Their plan and product can have an empty vendorId, so handle that case.
  • clearBuiltInAttributes() also clears the cached subscriptions used for audience targeting.
  • Session counts may drop slightly. Concurrent starts no longer create a duplicate session, so some apps will see fewer APP_STARTED events.

Fixes

  • Taps inside a tappable container run only the inner action. Before, a button or plan picker inside a tappable block could also run the block's action, for example opening the purchase sheet for the wrong plan. Dragging a scroll view no longer triggers an action either.
  • Stack backgrounds and borders display on iOS 27. Before, they could be missing.
  • Bold and italic text keeps its size. When a custom font has no bold or italic face, the text now keeps the label's size instead of rendering smaller.
  • No stray backslashes in labels. Labels such as 1. Premier or - 50% no longer show a \ on screen. When a label has two links, each keeps its own URL.
  • synchronize() no longer re-sends the same receipts on every call. This mostly affected non-renewing subscriptions.

Internal improvements (no code changes required)

  • The logging engine and the type-safe placement and campaign identifiers were reworked. A placement or campaign id that cannot be read now logs a warning.
  • More detailed network diagnostics are available to Purchasely.

Full list of the changes: docs.purchasely.com/changelog