Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
title: "How do I migrate to Superwall from another provider?"
description: "Guide for migrating from Adapty, Qonversion, Glassfy, or other subscription SDKs to Superwall"
---

# How do I migrate to Superwall from another subscription provider?

If you're currently using a subscription management provider like Adapty, Qonversion, Glassfy, or another SDK and want to migrate to Superwall, here's what you need to know.

## Will My Existing Subscribers Keep Their Access?

**Yes.** Superwall reads subscription status directly from the device's App Store (iOS) or Google Play (Android) records. This means:

- Existing subscribers are automatically recognized when you switch SDKs
- No manual migration of subscription data is required
- Users won't experience any interruption to their access

When a user opens your app with the new Superwall SDK, their active subscriptions are detected automatically, regardless of which SDK was used to originally make the purchase.

## What Gets Migrated Automatically

| Data | Migrated? |
|------|-----------|
| Active subscription status | ✅ Yes - read directly from the device |
| Entitlement access | ✅ Yes - based on active subscriptions |
| Cross-device sync (same Apple ID/Google account) | ✅ Yes |

## What Does NOT Migrate

| Data | Migrated? |
|------|-----------|
| Historical analytics and metrics | ❌ No |
| Paywall designs and configurations | ❌ No - must be recreated in Superwall |
| A/B test history and experiment data | ❌ No |
| Custom user attributes from previous SDK | ❌ No - must be re-set via Superwall SDK |

## Migration Steps

1. Remove your current subscription SDK from your project
2. Follow the [Superwall installation guide](/docs/getting-started-with-our-sdks) for your platform

## Troubleshooting

### Subscription status not detected

If an existing subscriber isn't being recognized:

1. Have them tap "Restore Purchases" on any paywall
2. Ensure they're signed into the same App Store/Google Play account used for the original purchase
3. Check that the subscription hasn't expired
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
title: "Why does my user show active subscription but no data in the dashboard?"
description: "Understanding why a user may have an active subscription on device but no entitlements, Apple events, or webhooks in the Superwall dashboard"
---

## Understanding How Superwall Tracks Subscriptions

Superwall uses two different sources of truth for subscription data:

### 1. On-Device Subscription Status (SDK)

The SDK determines subscription status by reading the **local Apple receipt** directly from StoreKit. This receipt is tied to the user's **Apple ID**, not their Superwall user ID.

If there's a valid subscription receipt on the device, the SDK will report `subscriptionStatus = active`, regardless of which Superwall user ID is currently active.

### 2. Dashboard Attribution (Server-Side)

The dashboard displays subscription data (entitlements, Apple server events, webhooks, receipts) that is attributed to a specific **Superwall user ID**. This attribution happens at the time of purchase. Whichever user ID was active when the transaction occurred is the one that gets linked to the subscription data.

## The Most Common Cause

When you see an active subscription on device but nothing in the dashboard, it almost always means:

**The subscription was purchased under a different Superwall user ID than the one you're currently looking at.**

This can happen when a user:

- Reinstalls the app (generates a new anonymous user ID)
- Logs out and back in (may generate a new user ID depending on your implementation)
- Switches accounts
- Had their identity reset for any reason

The subscription remains valid because Apple validates it against the user's Apple ID. But all the purchase events, webhooks, and server notifications are attributed to the **original** user ID that was active at purchase time.

## Example Scenario

1. User installs your app and gets assigned anonymous user ID `abc-123`
2. User purchases a subscription. All events are attributed to `abc-123`
3. User deletes and reinstalls the app
4. User gets assigned a new anonymous user ID `xyz-789`
5. The subscription is still valid (same Apple ID), so the SDK shows `active`
6. But the dashboard shows nothing for `xyz-789` because the subscription belongs to `abc-123`

## How to Verify This

If you suspect this is happening:

1. Check the "Customer Info" section in the dashboard for the user. If it shows subscription status as active but no entitlements, this confirms the SDK is reading a valid receipt
2. The subscription data exists, it's just linked to a different user ID
3. If you have access to your server logs or Apple's App Store Connect, you can try to find the original transaction and trace it back to the original user ID

## How to Prevent This

To maintain consistent attribution across user sessions:

- Call `Superwall.shared.identify(userId:)` with a stable user ID from your own authentication system as early as possible, ideally before any purchases occur
- Use the same user ID consistently across reinstalls and devices
- If your app supports account creation, identify users immediately after they sign up or log in

## Key Takeaways

- **Active subscription + no dashboard data = purchased under a different user ID**
- The subscription is valid and working correctly
- This is expected behavior, not a Superwall bug
- The SDK uses the Apple receipt (tied to Apple ID) for access control
- The dashboard uses attribution data (tied to Superwall user ID) for reporting
- These are intentionally separate to ensure users never lose access to their purchases
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
---
title: "Why is my paywall not updating after publishing?"
description: "Troubleshoot why users may still see an outdated paywall after you've made and published updates in the Superwall dashboard"
---

## Quick Checklist

Before diving into detailed troubleshooting, verify these common causes:

- [ ] Have you **published** the paywall after making changes?
- [ ] Is the user **assigned to a different paywall** in an A/B test?
- [ ] Are you using **conditional visibility** (e.g., `hasIntroductoryOffer`) that shows different content?
- [ ] Has the user's **trial eligibility** changed, showing a different UI state?

---

## Step 1: Verify the Paywall is Published

Changes made in the paywall editor are saved locally but not live until published.

**To check:**
1. Open the paywall in the editor
2. Look for the **Publish** button in the top-right
3. If it's clickable, your changes haven't been published yet

**Note:** Publishing a paywall doesn't automatically update users who have already been assigned to it in an experiment.

---

## Step 2: Check Campaign and Experiment Setup

### Multiple Paywalls in a Campaign

If your campaign has multiple paywalls (an A/B test), users are randomly assigned to one variant. The user seeing an "outdated" paywall may simply be assigned to a different variant than the one you updated.

**To check:**
1. Go to **Campaigns** → Select your campaign
2. Look at the **Paywalls** tab for the relevant audience
3. Verify which paywalls are active and their distribution percentages

### Sticky Assignments

**Important:** Superwall assignments are "sticky." Once a user is assigned to a paywall variant, they continue seeing that same paywall regardless of:
- Changes you make to presentation percentages
- Updates you publish to other paywalls
- App reinstalls or calling `Superwall.reset()`

This is by design. It ensures experiment integrity and allows you to keep existing users on an old pricing while testing new pricing with new users.

---

## Step 3: Check Conditional Visibility and Dynamic Values

Paywalls often use **dynamic values** to show different content based on conditions. The most common scenario is **trial eligibility**.

### Trial Eligibility (`products.hasIntroductoryOffer`)

If your paywall has components with visibility controlled by `products.hasIntroductoryOffer`:
- **True:** User is eligible for a free trial/intro offer
- **False:** User has already used their trial (or the product has no trial)

**Common issue:** Apple App Store reviewers often test with accounts that have already used trials, so `hasIntroductoryOffer` is `false` for them, showing different UI than you expect.

**To check in the editor:**
1. Open your paywall in the editor
2. Click **Variables** in the floating toolbar
3. Toggle `products.hasIntroductoryOffer` between true/false
4. Observe which components appear/disappear

### Other Dynamic Conditions

Check if any components have visibility rules based on:
- Selected product index
- Device type
- User attributes
- Custom parameters

Look for components that have the **gear icon** indicating dynamic values are set.

---

## Step 4: Verify Products Are Correctly Configured

### Product Approval Status

Products must be approved in App Store Connect before they can be properly displayed:
- Products in "Waiting for Review" may not load correctly
- Sandbox testing uses different product states than production

**To check:**
1. Go to App Store Connect → Your App → Subscriptions
2. Verify all products show "Ready to Submit" or "Approved"

### Product Assignment on Paywall

Ensure the correct products are assigned to your paywall:
1. Open the paywall in the editor
2. Check the **Products** section on the left sidebar
3. Verify the intended products are selected as Primary, Secondary, etc.

---

## Step 5: Understand Caching Behavior

### Server-Side Caching

Superwall's static configuration is cached by CDN for up to **1 hour**. After publishing changes:
- New users get the update immediately (fresh cache)
- Existing users may see cached content for up to 1 hour

### Device-Side Caching

If your paywall has **Cache on Device** enabled in settings:
- The SDK stores the paywall locally for faster presentation
- Reinstalling the app clears this cache
- `Superwall.reset()` clears on-device data but NOT server-side assignments

---

## Step 6: Testing Checklist

When testing paywall updates, follow this process:

### For Fresh Testing
1. Wait a few minutes for cache propagation
2. Use a **new user ID** or test account
3. Delete and reinstall the app
4. Trigger the placement that shows the paywall

### For App Store Review
1. Remember reviewers may not be eligible for trials (trial already used)
2. Test your paywall with `hasIntroductoryOffer = false` in the editor
3. Ensure all UI states look correct for non-trial-eligible users

---

## Common Scenarios and Solutions

| Scenario | Likely Cause | Solution |
|----------|--------------|----------|
| User sees old paywall copy | Sticky assignment to old variant | Wait for new users or use new test account |
| User sees different products | Assigned to different A/B variant | Check which variant user is assigned to |
| Trial text showing when user isn't eligible | `hasIntroductoryOffer` conditional visibility | Check dynamic values on text components |
| Non-trial text showing for trial-eligible user | Same as above, inverted | Verify conditional logic in editor |
| Changes not visible after publishing | CDN cache or device cache | Wait up to 1 hour, or reinstall app |
| App Store reviewer sees wrong content | Reviewer's trial eligibility differs | Design for both trial/non-trial states |

---

## Related Documentation

- [Publishing Paywalls](https://superwall.com/docs/dashboard/dashboard-creating-paywalls/paywall-editor-publishing)
- [A/B Testing and Experiments](https://superwall.com/docs/campaigns/campaigns-starting-an-experiment)
- [Dynamic Values](https://superwall.com/docs/dashboard/dashboard-creating-paywalls/paywall-editor-dynamic-values)
- [Variables Reference](https://superwall.com/docs/dashboard/dashboard-creating-paywalls/paywall-editor-variables)
- [Campaign Audiences](https://superwall.com/docs/campaigns/campaigns-audience)