Skip to main content

Background

Get set up with the Helium SDK for React Native. Reach out over your Helium slack channel or email founders@tryhelium.com for any questions.

Installation

Find your API key here
Install the SDK using your preferred package manager:
npx expo install expo-helium
We support Expo 49+ but recommend using Helium with Expo 53 and up. If you’re on an older version and having issues, ping us - we’ve got experience with all kinds of versioning, upgrade, and custom build plugin work.
The Older Expo / Bare SDK supports iOS only.The Expo 52+ SDK supports both iOS and Android.

Configuration

Follow these steps to integrate the SDK.

Initialization

Initialize Helium by calling initialize() early in your app’s lifecycle, typically in your root component.
If you are using RevenueCat, follow the example in the next section.
import { initialize } from 'expo-helium';

function App() {
  const asyncHeliumInit = async () => {
    await initialize({
      apiKey: '<your-helium-api-key>',
      // Fallback bundle is highly recommended. See Fallbacks section of this page.
      // fallbackBundle: require('./assets/fallback-bundle-xxxx-xx-xx.json'),
    });
  };

  useEffect(() => {
    void asyncHeliumInit();
  }, []);
}

Use RevenueCat with Helium

If you haven’t already, make sure to install RevenueCat (for non-Expo see here).
import { initialize } from 'expo-helium';
import { createRevenueCatPurchaseConfig } from "expo-helium/src/revenuecat";

const asyncHeliumInit = async () => {
  await initialize({
    apiKey: '<your-helium-api-key>',
    purchaseConfig: createRevenueCatPurchaseConfig(
      // (optional) Set if you want Helium to initialize RevenueCat for you.
      // Otherwise initialize RevenueCat (`Purchases.configure()`) before initializing Helium
      { apiKey: 'revenue_cat_api_key' }
    ),
    // Fallback bundle is highly recommended. See Fallbacks section of this page.
    // fallbackBundle: require('./assets/fallback-bundle-xxxx-xx-xx.json'),
    revenueCatAppUserId: await Purchases.getAppUserID()
  });
};

useEffect(() => {
  void asyncHeliumInit();
}, []);

Custom Purchase Config

To use your own purchase logic, pass in a custom purchase config to initialize.
import { createCustomPurchaseConfig } from 'expo-helium';

// In your initialize call:
purchaseConfig: createCustomPurchaseConfig({
  makePurchaseIOS: async (productId) => {
    // Your purchase logic here
    // Return a HeliumTransactionStatus
    return { status: 'purchased' };
  },
  makePurchaseAndroid: async (productId) => {
    // Your purchase logic here
    // Return a HeliumTransactionStatus
    return { status: 'purchased' };
  },
  restorePurchases: async () => {
    // Your restore logic here
    return true;
  }
}),
type HeliumTransactionStatus =
  'purchased' | 'failed' | 'cancelled' | 'pending' | 'restored';

Custom User ID and Custom User Traits

You can pass in a custom user ID and custom user traits if desired to initialize:
// (Optional) Custom user id, e.g. your amplitude analytics user id.
customUserId: '<your-custom-user-id>',
// (Optional) Custom user traits
customUserTraits: {
  "example_trait": "example_value",
},

Presenting Paywalls

You must have a trigger and workflow configured in the dashboard in order to show a paywall.
Use the presentUpsell method to present a paywall. presentUpsell takes in PresentUpsellParams:
PresentUpsellParams
method
import { presentUpsell } from 'expo-helium';

function YourComponent() {
  const handlePremiumPress = () => {
    presentUpsell({
      triggerName: 'premium_feature_press',
      onFallback: () => {
        // Implement logic to open a default paywall or display error dialog
        console.log('[Helium] onFallback called!');
      }
    });
  };

  return (
    <Button title="Try Premium" onPress={handlePremiumPress} />
  );
}

PaywallEventHandlers

You can pass in paywall event handlers to listen for specific paywall events. (See the next section Helium Events for a way to handle global events).
eventHandlers: {
  onOpen: (event) => {
    console.log(`${event.type}`)
  },
  onClose: (event) => {
    console.log(`${event.type}`)
  },
  onPurchaseSucceeded: (event) => {
    console.log(`${event.type}`)
  },
  onDismissed: (event) => {
    console.log(`${event.type}`)
  },
  onOpenFailed: (event) => {
    console.log(`${event.type}`)
  },
  onCustomPaywallAction: (event) => {
    console.log(`${event.type}`)
  },
  onAnyEvent: (event) => {
    // A handler for all paywall-related events.
    // Note that if you have other handlers (i.e. onOpen) set up,
    // both that handler AND this one will fire during paywall open.
  },
},
You should now be able to see Helium paywalls in your app! Well done! 🎉

Helium Events

Listen for all Helium Events by implementing onHeliumPaywallEvent and passing it to initialize:
onHeliumPaywallEvent: (event) => {
  switch (event.type) {
    case 'paywallOpen':
      break;
    case 'purchaseSucceeded':
      // Handle successful purchase
      break;
    // handle other events as desired
  }
},

Checking Subscription Status & Entitlements

If you use an external payment processor like Stripe, Helium’s entitlement helpers may not be reliable. We recommend implementing your own entitlement checking in that case. If you use Stripe with RevenueCat, we recommend using RevenueCat’s entitlement APIs instead.
Use these methods to check current user subscription status.
/**
 * Checks if the user has any active subscription (including non-renewable)
 */
export const hasAnyActiveSubscription = async (): Promise<boolean>;

/**
 * Checks if the user has any entitlement
 */
export const hasAnyEntitlement = async (): Promise<boolean>;

/**
 * Checks if the user has an active entitlement for any product attached to the paywall that will show for provided trigger.
 * @param trigger The trigger name to check entitlement for
 * @returns Promise resolving to true if entitled, false if not, or undefined if not known (i.e. the paywall is not downloaded yet)
 */
export const hasEntitlementForPaywall = async (trigger: string): Promise<boolean | undefined>;

Example Usage

Check entitlements before showing paywalls to avoid showing a paywall to a user who should not see it.
presentUpsell({
  triggerName: 'my_paywall',
  dontShowIfAlreadyEntitled: true
});

Fallbacks

There are currently two ways you can handle a “fallback” situation in the rare case that a paywall fails to download or an invalid trigger is provided. You can also do both. Better to be prepared!

1. Use the onFallback function

You can pass this in when you call presentUpsell and handle however you want. Provide a fallback bundle as described in this guide.
Update your fallback bundle whenever you make changes to your paywall for maximum reliability.

Loading Budgets

If a paywall has not completed downloading when you attempt to present it, a loading state can show. By default, Helium will show this loading state as needed (a shimmer view for up to 7 seconds). You can configure or turn off this loading budget. If the budget expires before the paywall is ready, a fallback paywall will show if available otherwise the loading state will hide and onFallback will be called.
const paywallLoadingConfig: HeliumPaywallLoadingConfig = {
  useLoadingState: true,
  loadingBudget: 4,
};

await initialize({
  apiKey: "helium-api-key",
  fallbackBundle: require('./assets/fallback-bundle-xxxx-xx-xx.json'),
  paywallLoadingConfig: paywallLoadingConfig, // << pass to initialize
});

Advanced

Reset Helium entirely so you can call initialize again. Only for advanced use cases.
import { resetHelium } from 'expo-helium';

await resetHelium();

Additional Considerations

Expo Development Build

Please note that the Helium SDK uses native code, so you must create a development build. A common command to run for this is:
npx expo run:ios # or npx expo run:ios --device

Troubleshooting

Check if the Helium SDK is installed

[ -d "node_modules/expo-helium" ] && echo "✅ expo-helium package found in node_modules" || echo "❌ expo-helium package NOT found in node_modules"
If the package is not found, install it again:
npx expo install expo-helium

Check if Helium is properly installed

To verify that the Helium pod is correctly installed in your project, run:
grep -E "Helium" ios/Podfile.lock > /dev/null && echo "✅ Helium found in ios/Podfile.lock" || echo "❌ Helium not found in ios/Podfile.lock" && grep -E "HeliumPaywallSdk" ios/Podfile.lock > /dev/null && echo "✅ HeliumPaywallSdk found in ios/Podfile.lock" || echo "❌ HeliumPaywallSdk not found in ios/Podfile.lock"
If not found, try these commands:
# regenerate the ios (and android) directories
npx expo prebuild --clean

# run a development build
npx expo run:ios # or npx expo run:ios --device