> ## Documentation Index
> Fetch the complete documentation index at: https://docs.appstack.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# Using RevenueCat and Superwall together

> Use RevenueCat as your subscription data source and Superwall for paywalls, with Appstack attribution wired into both.

Many teams run **both** subscription platforms at once: RevenueCat as the source of truth for subscription **data**, and Superwall to build and serve **paywalls**. This guide shows how the two fit together with Appstack so attribution flows correctly from install → paywall → subscription.

<CardGroup cols={2}>
  <Card title="RevenueCat" href="/Integrations/revenuecat">
    Subscription **data**: manages entitlements and subscription state, and forwards subscription events with the Appstack ID and attribution params to Appstack.
  </Card>

  <Card title="Superwall" href="/Integrations/superwall">
    **Paywalls**: presents and experiments on paywalls, and can target them by the campaign a user came from using Appstack attribution params.
  </Card>
</CardGroup>

## Who does what

| Responsibility                                    | RevenueCat |         Superwall         |
| :------------------------------------------------ | :--------: | :-----------------------: |
| Presents paywalls                                 |      —     |             ✅             |
| Manages entitlements / subscription state         |      ✅     |             —             |
| Source of subscription events sent to ad networks |      ✅     |             —             |
| Receives the Appstack ID                          |      ✅     |             —             |
| Receives Appstack attribution params              |      ✅     | ✅ (for paywall targeting) |

## How it works together

<Steps>
  <Step title="The Appstack SDK generates the identity">
    On app start, the Appstack SDK produces the Appstack ID and attribution params (campaign, click IDs, device identifiers). Both platforms read from these.
  </Step>

  <Step title="RevenueCat carries the subscription data">
    Call `setAppstackAttributionParams()` after `Purchases.configure` so RevenueCat attaches the Appstack ID and attribution to every subscriber. See [the RevenueCat guide](/Integrations/revenuecat) for the per-platform code. The call returns RevenueCat `offerings`, but in this setup Superwall presents the paywall — so you don't need to use those `offerings` to render one.
  </Step>

  <Step title="Superwall targets and serves the paywall">
    Pass the attribution params via `setUserAttributes(...)` so paywalls can be filtered by where the user came from. You can **skip** `setIntegrationAttributes(...)` (the Appstack ID) here — that only matters when Superwall is your subscription-event source, and RevenueCat is filling that role. See [the Superwall guide](/Integrations/superwall) for the per-platform code.
  </Step>

  <Step title="Appstack stitches it together">
    RevenueCat is the only platform forwarding subscription events to Appstack, so there's no double-counting to manage. Superwall contributes paywall targeting, and Appstack ties the attribution and subscription outcomes back to the acquisition source.
  </Step>
</Steps>

## Wiring both in code

The snippet below configures both platforms from one place, at startup, after the Appstack, RevenueCat, and Superwall SDKs are configured. The Appstack identity is read once, then handed to each platform differently:

* **RevenueCat** gets the attribution params **and** the Appstack ID (under `appstack_id`) — it's your subscription-event source.
* **Superwall** gets **only** the attribution params, as user attributes for paywall targeting. There's no `setIntegrationAttributes(...)` call, because Superwall isn't forwarding events here.

<CodeGroup>
  ```swift Swift theme={null}
  import AdSupport
  // ...
  Purchases.configure(withAPIKey: "public_sdk_key")
  // ...configure Superwall per its docs...

  Task {
      // Read the Appstack identity once
      let attribution = await AppstackAttributionSdk.shared.getAttributionParams() ?? [:]

      // RevenueCat = subscription data source (include the Appstack ID)
      var rcParams = attribution
      if let id = AppstackAttributionSdk.shared.getAppstackId() {
          rcParams["appstack_id"] = id
      }
      Purchases.shared.attribution.setAppstackAttributionParams(rcParams) { offerings, error in
          // Attribution + subscription data now flow through RevenueCat.
          // Superwall presents the paywall, so you can ignore these `offerings`.
      }

      // Superwall = paywalls only (attribution params for targeting; no Appstack ID)
      Superwall.shared.setUserAttributes(attribution)
      Superwall.shared.register(placement: "onboarding_paywall")
  }
  ```

  ```kotlin Kotlin theme={null}
  // ...
  Purchases.configure(this, "public_sdk_key")
  // ...configure Superwall per its docs...

  fun wireAppstack() {
      // Read the Appstack identity once
      val attribution = AppstackAttributionSdk.getAttributionParams()

      // RevenueCat = subscription data source (include the Appstack ID)
      val rcParams = attribution.toMutableMap()
      AppstackAttributionSdk.getAppstackId()?.let { rcParams["appstack_id"] = it }
      Purchases.sharedInstance.setAppstackAttributionParams(
          rcParams,
          object : SyncAttributesAndOfferingsCallback {
              override fun onSuccess(offerings: Offerings) {
                  // Superwall presents the paywall, so you can ignore these `offerings`.
              }
              override fun onError(error: PurchasesError) { /* handle error */ }
          }
      )

      // Superwall = paywalls only (attribution params for targeting; no Appstack ID)
      Superwall.instance.setUserAttributes(attribution)
      Superwall.instance.register("onboarding_paywall")
  }

  // Call wireAppstack() after Appstack, RevenueCat, and Superwall are configured.
  ```

  ```typescript React Native / Expo theme={null}
  // RevenueCat via react-native-purchases, Superwall via expo-superwall
  import { useEffect } from "react";
  import { useUser, usePlacement } from "expo-superwall";

  // RevenueCat = subscription data source. Run once at startup.
  async function configureRevenueCat() {
    Purchases.configure({ apiKey: "public_sdk_key" });

    const attribution = (await AppstackSDK.getAttributionParams()) ?? {};
    const rcParams = { ...attribution };
    const id = await AppstackSDK.getAppstackId();
    if (id != null) {
      rcParams["appstack_id"] = id;
    }
    await Purchases.setAppstackAttributionParams(rcParams);
    // Superwall presents the paywall, so you can ignore the returned offerings.
  }

  // Superwall = paywalls only. Hooks stay at the component's top level.
  function Paywall() {
    const { update } = useUser();
    const { registerPlacement } = usePlacement();

    useEffect(() => {
      (async () => {
        const attribution = (await AppstackSDK.getAttributionParams()) ?? {};
        await update(attribution); // attribution params for targeting; no Appstack ID
        await registerPlacement({ placement: "onboarding_paywall" });
      })();
    }, [update, registerPlacement]);

    // ...render your paywall UI
  }
  ```

  ```dart Flutter theme={null}
  // ...
  await Purchases.configure(PurchasesConfiguration("public_sdk_key"));
  // ...configure Superwall per its docs...

  // Read the Appstack identity once
  final attribution = await AppstackPlugin.getAttributionParams() ?? <String, dynamic>{};

  // RevenueCat = subscription data source (include the Appstack ID)
  final rcParams = Map<String, dynamic>.from(attribution);
  final id = await AppstackPlugin.getAppstackId();
  if (id != null) {
    rcParams['appstack_id'] = id;
  }
  await Purchases.setAppstackAttributionParams(rcParams);
  // Superwall presents the paywall, so you can ignore the returned offerings.

  // Superwall = paywalls only (attribution params for targeting; no Appstack ID)
  await Superwall.shared.setUserAttributes(attribution);
  await Superwall.shared.register('onboarding_paywall');
  ```
</CodeGroup>

## Set up order

<Steps>
  <Step title="Install and verify the Appstack SDK">
    Confirm events flow through the Appstack SDK page before connecting either platform.
  </Step>

  <Step title="Connect RevenueCat">
    Follow the [RevenueCat integration](/Integrations/revenuecat) to wire the SDK call and paste credentials.
  </Step>

  <Step title="Connect Superwall (paywalls only)">
    Follow the [Superwall integration](/Integrations/superwall) to wire only `setUserAttributes`. Skip `setIntegrationAttributes(...)` and the dashboard credential steps.
  </Step>

  <Step title="Validate coverage">
    Confirm the Appstack ID reaches ≥50% of RevenueCat's events so the integration stays active.
  </Step>
</Steps>
