React Native offerwall SDK. Expo ready, TypeScript included.

Open the Moonetix offerwall as a native screen from React Native or Expo. The package brings the Android and iOS SDKs, works with the New Architecture, and ships its own TypeScript types.

  • 0.77+React Native
  • 53+Expo SDK
  • TSTypes included
React Native SDKVersion 2.0.0
EarnScreen.tsx
import { Moonetix } from '@moonetix/react-native-offerwall';
 
Moonetix.init('YOUR_APP_ID');
 
// When the user taps Earn
Moonetix.open(token);

Go live in four steps.

Copy the code, replace the placeholders with the values from your dashboard under Apps, your app, Integration, and test before you launch.

  1. Install the package

    Add the Moonetix registry for the @moonetix scope, then install the package and rebuild your app. For Expo, add the config plugin and use a development build, because Expo Go cannot load native code.

    Terminal
    # .npmrc, next to package.json
    @moonetix:registry=https://moonetix.com/npm/
     
    npm install @moonetix/react-native-offerwall
    cd ios && pod install
  2. Add a token endpoint to your server

    Your app never holds the API key. When a user taps Earn, your app asks your server for a session, and your server asks Moonetix for a single-use token for that signed-in user. A token works once, for 10 minutes.

    session.php
    <?php
    // POST /api/moonetix/session: a fresh token for the signed-in user
    $user = current_user();
    if (!$user) {
        http_response_code(401);
        exit;
    }
     
    $key = getenv('MOONETIX_API_KEY');
    $ch  = curl_init('https://api.moonetix.com/v1/session');
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => http_build_query(['user_id' => (string)$user->id]),
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 10,
        CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $key],
    ]);
    $data = json_decode((string)curl_exec($ch), true);
    $code = (int)curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
     
    header('Content-Type: application/json');
    if ($code === 201 && !empty($data['token'])) {
        echo json_encode(['token' => $data['token']]);
        exit;
    }
    http_response_code($code === 403 ? 403 : 503);
    echo json_encode(['error' => 'offerwall_unavailable']);
  3. Open the offerwall

    Call init once with the App ID from your dashboard, then open with a fresh token. addListener returns a subscription, so remove it when your screen goes away.

    EarnScreen.tsx
    import { Moonetix } from '@moonetix/react-native-offerwall';
     
    Moonetix.init('YOUR_APP_ID');
     
    useEffect(() => {
      const closed = Moonetix.addListener('closed', refreshBalance);
      const failed = Moonetix.addListener('error', (error) => {
        console.warn(`${error.code}: ${error.message}`);
      });
      return () => {
        closed.remove();
        failed.remove();
      };
    }, []);
     
    async function openOfferwall() {
      const url = 'https://your-server.example/api/moonetix/session';
      const res = await fetch(url, { method: 'POST' });
      const { token } = await res.json();
      Moonetix.open(token);
    }
  4. Credit rewards with the postback

    Every reward reaches your server as a signed postback. Check the hash, add the reward once per transaction ID, and take it back if a later postback reverses it. Failed postbacks are retried up to 5 times.

    Postback macros and retries

    Dashboard, Postback tab
    https://yoursite.com/postback?user={user_id}&tx={transaction_id}&status={status}&reward={reward}&hash={hash}
9:41
Earn coins12,450 Coins
EarnMy offers
  • Castle MergeReach level 10+1,500
  • FitTrackStart a free trial+2,000
  • Word RushPlay 3 days in a row+450
  • Budget PalSet up your first budget+800
Reward creditedCastle Merge · +1,500 Coins
Native screen
Postback 200 OK

What your users see

A native screen over your app, with your title and colors, your currency, and every reward confirmed by a postback.

What the package handles for you

  • Native SDKs included

    Android Gradle and iOS CocoaPods are wired up for you. Run pod install and rebuild.

  • Expo config plugin

    Add one line to app.json, then prebuild or start an EAS Build.

  • TypeScript types

    Typed init, open, events, and error codes, the same names the native SDKs use.

  • Offers open in the right place

    Store offers open in Google Play or the App Store, so installs are tracked correctly.

  • No key in your bundle

    Your JavaScript bundle holds only the App ID. Sessions come from your server and work once.

  • No advertising ID

    The SDK does not use the advertising identifier and does not track users across apps.

Test it, then launch.

Everything you need to check before real users see your offerwall, with the tools built into your dashboard.

  1. Open as a test user

    In Integration status on the Integration tab, open your offerwall as the user owner-test. Test visits are not counted as users.

  2. Run it on a real device

    Build for Android or iOS and open the offerwall from your Earn button with a fresh token each time.

  3. Send a test postback

    Choose the user, status, and payout, and see exactly what your server answered, with the response code and time. Test transaction IDs start with test_.

  4. Test from a normal connection

    VPNs, proxies, Tor, and cloud networks are blocked, so test on home Wi-Fi or mobile data, in a country where offers run.

Launch checklist

0 of 11 ready

Common errors, fixed fast.

What you might see while you integrate the React Native SDK, what causes it, and the fix.

  • INVALID_APP_ID

    The value passed to init is not the App ID. Passing the API key here is the most common mistake.

    FixCopy the 24-character App ID again from the Integration tab.

  • INVALID_TOKEN

    The app passed something other than the token, or a token created with the API key of another app.

    FixPass only the token field, which starts with sst_, and use the App ID and API key of the same app.

  • TOKEN_EXPIRED_OR_USED

    The token is older than 10 minutes or was already used, for example kept from an earlier tap.

    FixCreate a new token for every open, right when the user taps Earn.

  • NOT_INITIALIZED

    open was called before init.

    FixCall Moonetix.init once when your app starts.

  • UNSUPPORTED on a phone

    The native part is not in the build, for example in Expo Go or before a rebuild.

    FixBuild the app again or use an Expo development build. A Metro reload does not add native code.

  • Gradle cannot find com.moonetix

    Your settings.gradle does not let projects add repositories.

    FixAdd the Moonetix Maven repository to settings.gradle.

  • 403 from /v1/session

    app_not_live means the app is paused or your account is not active. user_blocked means we blocked this user.

    FixDo not show the offerwall. For app_not_live, check your notifications.

  • VPN or Proxy detected

    The device is on a VPN, a proxy, or a cloud network, where offers cannot be tracked.

    FixTest on a normal home or mobile connection, in a country where offers run.

  • Postback log shows 403 or 404

    Your script rejected the postback, or the URL is wrong.

    FixOpen the URL from the log in a browser and check your hash code.

  • Postback log shows a timeout

    Your script takes longer than 6 seconds to answer.

    FixAnswer with 200 first, and run slow work in the background.

  • Postback log shows 301 or 302

    Your URL redirects, for example from http to https.

    FixUse the final URL. Postbacks do not follow redirects.

At a glance

React Native
0.77 or newer, New Architecture supported
Expo
SDK 53 or newer, with a development build
Package
@moonetix/react-native-offerwall 2.0.0 from moonetix.com/npm
Android
Kotlin 2.0 or newer, the default in these versions
Language
TypeScript and JavaScript
Price
Free for approved publishers

Other integrations

React Native questions

What developers ask before they add the React Native SDK.

Stuck on something? Contact us

Which React Native and Expo versions are supported?

React Native 0.77 or newer, or Expo SDK 53 or newer. The package works with the New Architecture and, on React Native 0.77 to 0.81, with the old architecture too.

Does it work in Expo Go?

No. Expo Go cannot load native code, so Moonetix.isSupported is false there. Add the config plugin and test with a development build or an EAS Build.

Is the package on the public npm registry?

It is in the Moonetix npm registry. Add @moonetix:registry=https://moonetix.com/npm/ to your .npmrc, or the npmScopes entry for Yarn 2 and newer, then install it as usual.

Are TypeScript types included?

Yes. Types for init, open, events, and error codes ship with the package.

How do I reward users?

Your server receives a signed postback for every reward and credits the user once per transaction ID. App events can be faked on a device, so use them only to refresh your UI.

Where does my API key go?

Only on your server. Your app holds the App ID, and your server creates a single-use session token for the signed-in user.

Turn your traffic into earnings.

Create a free publisher account and earn from every offer your users complete on your website, app, game, or community.

Worldwide targeting
More
Log in