If Superwall shows purchases but conversions are not tracked, or RevenueCat entitlements are out of sync, the cause is usually the purchase controller wiring or subscription status reporting. Here is how to fix it.
This problem shows up in a few related ways: a user purchases from a Superwall paywall but the conversion does not appear in Superwall's metrics, or the purchase succeeds but the user is not marked entitled so the paywall keeps appearing, or RevenueCat records the subscription while Superwall does not reflect it, or vice versa. All of these stem from the same underlying question, which is who owns the purchase and who tells whom about its result. Superwall can either complete purchases itself through StoreKit or defer to a purchase controller you provide, and when you pair it with RevenueCat as your entitlement source of truth, the two systems must exchange information correctly for conversions and entitlements to stay in sync. Before changing anything, pin down exactly which direction is failing. Is the purchase itself completing? Does RevenueCat show the entitlement? Does Superwall show the conversion and the entitled status? Answering those three questions separately turns a vague not-tracking complaint into a specific broken link, because the fix for a purchase that never reaches RevenueCat is different from the fix for an entitlement that never propagates back to Superwall. Writing down the answer to each of those three questions for a single reproduced purchase is the fastest way to localize the fault, because the failure almost always sits at exactly one of the handoffs between the three systems.
In the recommended Superwall plus RevenueCat setup, RevenueCat is the source of truth for entitlements and receipt validation, while Superwall owns paywall presentation and experiments. To make that work you supply a PurchaseController to Superwall at configuration time. When a user taps buy on a Superwall paywall, Superwall calls your purchase controller instead of purchasing directly; inside it you perform the purchase through RevenueCat's Purchases SDK, and then you report the resulting subscription status back to Superwall by setting its subscription status from RevenueCat's customer info. You also implement restore in the controller, again routing through RevenueCat. Separately, you keep Superwall's subscription status updated whenever RevenueCat's customer info changes, for example by observing RevenueCat's updates and pushing the current entitlement state into Superwall. If any link in this chain is missing, purchases and entitlements diverge: purchases might complete in RevenueCat but Superwall never learns the user is entitled, or Superwall might think purchasing failed and never record a conversion. Understanding this intended flow is the key to diagnosing which specific handoff is broken, so map your actual implementation against it before editing code. RevenueCat also publishes an official Superwall integration guide, and it is worth following its exact recommended wiring rather than improvising, because the two SDKs have a supported pattern for exchanging status that avoids most of these divergence bugs.
If purchases are not tracked or entitlements do not update, first confirm your PurchaseController is actually installed and its methods are being called. It must be passed to Superwall.configure at startup; if you added the controller but did not supply it in the configure call, Superwall will keep purchasing directly and your RevenueCat routing never runs. Add logging inside each controller method, purchase and restore, to confirm Superwall is invoking them when the user taps a paywall button. If those logs never fire, the controller is not wired in. If they fire but nothing reaches RevenueCat, the purchase call inside the controller is failing or misconfigured. Confirm that within the purchase method you call RevenueCat's purchase API with the correct product or package and that you handle its result, and that after a successful purchase you report the outcome back to Superwall so it can record the conversion and update presentation. A controller that purchases through RevenueCat but never reports status back to Superwall is a classic cause of the paywall reappearing after a successful purchase, because Superwall was never told the user is now entitled. When you add the logging, log both entry and the final reported status in each method, so you can see not just that the controller ran but what conclusion it reached and handed back, which is usually where the break actually is.
The link that most often breaks is reporting entitlement status back to Superwall. Superwall gates paywalls on what it believes the user's subscription status is, so if RevenueCat grants an entitlement but you never push that into Superwall, the user stays marked as free and keeps seeing paywalls, and conversions may not attribute correctly. Ensure that after any purchase or restore, and whenever RevenueCat's customer info updates, you translate RevenueCat's active entitlements into Superwall's subscription status and set it. Observe RevenueCat's customer info updates so that changes originating outside your app, such as a renewal, an expiration, or a purchase on another device, propagate into Superwall too, not just purchases made through the paywall. Watch for stale or cached status: pushing a value captured before the purchase completed, or failing to update on expiration, both cause divergence. Test the full cycle with a sandbox account: purchase, confirm RevenueCat shows the entitlement, confirm Superwall now treats the user as entitled and skips the paywall, then let the sandbox subscription expire and confirm the status reverts. Correct, timely status reporting is the linchpin of keeping the two systems in sync. The most reliable pattern is to route every status update through a single function that reads RevenueCat's current customer info and sets Superwall's status from it, then call that one function from both the purchase result and the customer-info listener, so there is exactly one place where the translation happens and no code path can forget to run it.
Conversions and entitlements can also fail to line up when the two systems disagree about who the user is. Superwall generates an anonymous identifier by default and can be told your user ID via identify, and RevenueCat similarly has its own app user ID. If your app identifies the user in one system but not the other, or uses different identifiers, a purchase attributed to one identity in RevenueCat may not map cleanly to the Superwall identity that saw the paywall, muddying conversion attribution and cross-device entitlement. Align identity deliberately: when a user logs in, identify them in both Superwall and RevenueCat with consistent identifiers, and on logout reset both so a new user is not conflated with the previous one. This matters especially for users across multiple devices or reinstalls, where anonymous identities would otherwise fragment. Mismatched or missing identification is a subtle cause because purchases still succeed and entitlements still exist somewhere; they simply do not attach to the identity Superwall is tracking for conversions. If your metrics show purchases happening but conversions not attributing to the expected users, review how and when you call identify and reset in each SDK and make them consistent. A useful rule is to treat identify and reset as a paired operation performed on both SDKs together at exactly the same lifecycle moments, so the two systems can never drift into using different identities for the same person.
Sometimes conversions do not track because the purchase itself is not really completing the way you think. Confirm that the products on the paywall map to the same products RevenueCat and App Store Connect know about, since a product that loads visually but is misconfigured can produce a purchase that does not resolve into an entitlement. Ensure the products are attached to the correct entitlement in RevenueCat, because RevenueCat only marks a user entitled when a purchased product is linked to an entitlement; a product with no entitlement mapping will complete a purchase without granting access, which looks exactly like a tracking failure. Test the whole path end to end in sandbox: present the paywall, purchase, and verify in order that StoreKit completed the transaction, RevenueCat recorded it against the right entitlement, your status reporting pushed the entitlement into Superwall, and Superwall both recorded the conversion and stopped showing the paywall. Checking each stage in sequence isolates the break. If everything works in sandbox but production metrics still look off, allow for reporting delays and verify your production RevenueCat configuration and webhooks, since a sandbox-only test cannot exercise every production integration path. The unmapped-entitlement case is especially deceptive because every visible step appears to succeed: the purchase sheet completes, money moves in sandbox, and only the entitlement quietly fails to appear, so make confirming the product-to-entitlement mapping in RevenueCat an explicit step rather than an assumption.
Because this integration spans three systems, StoreKit, RevenueCat, and Superwall, it is fragile at the seams and benefits from deliberate maintenance. Keep a single, well-documented place in your code where the purchase controller lives and where RevenueCat customer info is translated into Superwall subscription status, so the handoff logic is not scattered and easy to break. Add logging or analytics at each handoff, the controller invocation, the RevenueCat purchase result, and the status report to Superwall, so that if conversions drift you can see which link failed rather than guessing. After any SDK upgrade to either RevenueCat or Superwall, re-test the full purchase, restore, and expiration cycle in sandbox, because either vendor can change how status is reported. Keep identity handling consistent by identifying and resetting both SDKs together at login and logout. Finally, respect the division of responsibility: RevenueCat owns entitlements and receipt validation, Superwall owns presentation and conversion measurement, and Apple owns the transaction and the products. Most sync bugs are not inside any one tool but in the wiring between them, so instrumenting and documenting that wiring is the most reliable way to keep conversions tracking and entitlements in sync over time. A short runbook that lists the expected sequence of events for a successful purchase, and the log line each system should emit at each step, turns future debugging from an open-ended hunt into a quick comparison against a known-good trace.
Usually because the purchase completed in RevenueCat but the entitlement status was never reported back to Superwall, so Superwall still considers the user free. After a purchase or restore, translate RevenueCat's active entitlements into Superwall's subscription status and set it, and observe RevenueCat updates so later changes propagate too.
Supply a PurchaseController to Superwall at configure time. When the user buys, Superwall calls your controller, you purchase through RevenueCat's SDK, then report the resulting entitlement status back to Superwall. RevenueCat is the source of truth for entitlements; Superwall owns presentation and conversion tracking.
Confirm the controller is actually passed to Superwall.configure. If you created it but did not supply it in the configure call, Superwall keeps purchasing directly and your RevenueCat routing never runs. Add logging inside the controller's purchase and restore methods to verify Superwall invokes them.
Yes. If you identify the user in one SDK but not the other, or use different identifiers, purchases in RevenueCat may not map to the Superwall identity that saw the paywall, muddying attribution and cross-device entitlement. Identify and reset both Superwall and RevenueCat consistently at login and logout.
Often the purchased product is not linked to an entitlement in RevenueCat, so RevenueCat completes the transaction without granting access. Confirm each product is mapped to the correct entitlement in RevenueCat, then verify that entitlement is reported back to Superwall as the user's subscription status.
Allow for reporting delays and verify your production RevenueCat configuration, including any webhooks and server integrations that sandbox testing does not fully exercise. Also re-check that identity is aligned in production and that status reporting runs for renewals and expirations, not just purchases made through the paywall.