purchaseUpdatedListener

Fired when a purchase is successful or when a pending purchase is completed.

Duplicate Transaction Replays on iOS

StoreKit can replay the same unfinished transaction through more than one native path during a single connection session. By default, OpenIAP delivers one purchaseUpdated event per iOS transaction ID to purchase-success listeners, while still keeping distinct transactions separate. This prevents entitlement delivery from running twice for the same purchase.

For diagnostics, register the purchase update listener with dedupeTransactionIOS: false. The flag belongs to the purchase update listener only; purchase error listeners do not receive successful StoreKit transactions. Android ignores this iOS-only option.

Listener Setup

swift
let subscription = OpenIapModule.shared.purchaseUpdatedListener(
    { purchase in
        print("Purchase updated: \(purchase.productId)")
    },
    options: nil
)

Registers a listener for successful purchase events.

Opt In to iOS StoreKit Replays

swift
let subscription = OpenIapModule.shared.purchaseUpdatedListener(
    { purchase in
        print("StoreKit replay or first delivery: \(purchase.id)")
    },
    options: PurchaseUpdatedListenerOptions(
        dedupeTransactionIOS: false
    )
)
swift
import OpenIap

let subscription = OpenIapModule.shared.purchaseUpdatedListener { purchase in
    Task {
        print("Purchase updated: \(purchase.productId)")

        // Verify and deliver
        if await verifyPurchaseOnServer(purchase) {
            await deliverProduct(purchase.productId)
            try await OpenIapModule.shared.finishTransaction(
                purchase: purchase,
                isConsumable: false
            )
        }
    }
}

// Cleanup when done
OpenIapModule.shared.removeListener(subscription)

Event Payload

The purchase event delivers a Purchase object containing transaction details.

Purchase Update Flow

  1. Receive Purchase object via listener
  2. Validate receipt with backend service
  3. Deliver purchased content to user
  4. Finish transaction with finishTransaction (handles acknowledgment on both platforms)
  5. Update application state