# React Native SDK

> Show the offerwall in your React Native or Expo app on Android and iOS. Your server creates a short, single-use session, and the package opens the offerwall with it, so no key ever ships inside your app.

Source: https://docs.sharklio.com/react-native-sdk

## How it works

1. When the user taps your Earn button, your app asks your own server for a session.
2. Your server calls `POST /v1/session` with your API key and the user’s ID, and passes the token to the app.
3. The app calls `Sharklio.open(token)`. The package opens the offerwall in a native screen.
4. Rewards reach your server through your postback, exactly as with the offerwall link. See [Postbacks](https://docs.sharklio.com/postbacks).

A token works once and for 10 minutes. Create a new one each time the user opens the offerwall. Your API key and your link hash salt stay on your server, so nothing in your app can be used to open another user’s offerwall.

| Platform | Status |
| --- | --- |
| Android | Supported. The package uses the [Android SDK](https://docs.sharklio.com/android-sdk) inside. |
| iOS | Supported. The package uses the [iOS SDK](https://docs.sharklio.com/ios-sdk) inside. Build with Xcode 16 or newer. |
| Expo | Supported in development builds, `npx expo prebuild` and EAS Build. Not in Expo Go, which cannot load native code. |
| Web and other platforms | Not supported. `open` checks the app ID and the token and then reports `UNSUPPORTED`. |

## Install

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. Your Android project needs Kotlin 2.0 or newer, which these versions use by default. It is in the Sharklio npm registry. Add the registry for the `@sharklio` scope to the `.npmrc` file next to your `package.json`:

```
@sharklio:registry=https://sharklio.com/npm/
```

Then install the package and rebuild your app:

```
npm install @sharklio/react-native-offerwall
# or
yarn add @sharklio/react-native-offerwall
# Expo
npx expo install @sharklio/react-native-offerwall
```

npm, Yarn 1 and pnpm read `.npmrc`. With Yarn 2 or newer, add the scope to `.yarnrc.yml` instead:

```
npmScopes:
  sharklio:
    npmRegistryServer: "https://sharklio.com/npm"
```

Prefer a file? Download [sharklio-react-native-offerwall-1.0.0.tgz](https://sharklio.com/downloads/sharklio-react-native-offerwall-1.0.0.tgz) and run `npm install ./sharklio-react-native-offerwall-1.0.0.tgz`.

There is nothing else to set up:

- **Android:** the package adds the Sharklio Maven repository (only for the `com.sharklio` group) and the Android SDK to your Gradle build, the same way React Native adds its own repositories. If your `settings.gradle` sets `repositoriesMode` to `FAIL_ON_PROJECT_REPOS` or `PREFER_SETTINGS`, add `maven { url = uri("https://sharklio.com/maven") }` to the repositories there.
- **iOS:** the package brings the Sharklio iOS SDK with it, and CocoaPods links and embeds it. Run `pod install` in your `ios` folder.

### Expo

Add the config plugin to `app.json`, then run `npx expo prebuild` or start an EAS Build:

```json
{
  "expo": {
    "plugins": ["@sharklio/react-native-offerwall"]
  }
}
```

Expo Go cannot load native code, so the offerwall does not open there: `Sharklio.isSupported` is `false` and `open` reports `UNSUPPORTED`. Use a development build to test.

## Create a session on your server

`POST https://api.sharklio.com/v1/session`

Send the fields as a form or as JSON, with your API key in the `Authorization` header. This is the same request as for the [Android SDK](https://docs.sharklio.com/android-sdk#session).

| Field | Description |
| --- | --- |
| `user_id` (required, string) | The same user ID you receive in postbacks. 1 to 100 characters: letters, numbers, and `. _ @ : + -`. |
| `sub1` to `sub5` (optional, string) | Your own tracking values. They are returned in the postback as `{sub1}` to `{sub5}`. |

Errors: 400 `invalid_user_id`, 401 `invalid_api_key`, 403 `app_not_live` or `user_blocked` (do not show the offerwall), 405 `method_not_allowed`, 429 `rate_limited` (retry after the time in the `Retry-After` header).

## Open the offerwall

Call `init` once with the App ID from the Integration tab. Then open the offerwall with a fresh token from your server.

```
import { Sharklio } from '@sharklio/react-native-offerwall';

Sharklio.init('YOUR_APP_ID');

async function openOfferwall() {
  // Your own endpoint, which creates the session for the signed-in user
  const res = await fetch('https://your-server.example/earn/session', { method: 'POST' });
  const { token } = await res.json();
  Sharklio.open(token);
}
```

`open` never throws for offerwall problems. They arrive as events, see [Events](https://docs.sharklio.com/react-native-sdk#events).

## Branding

The top bar of the offerwall screen shows the Sharklio mark, like the offerwall itself, with your offerwall title and colors from the Design tab of your dashboard. To set the title or color yourself, or to hide the mark, pass options. The color can be any color string React Native understands; transparency is ignored.

```
Sharklio.open(token, {
  title: 'Earn coins',
  toolbarColor: '#004ABB',
  showLogo: false,
});
```

## Events

`Sharklio.addListener` returns a subscription. Remove it when your screen goes away.

```
useEffect(() => {
  const closed = Sharklio.addListener('closed', refreshBalance);
  const failed = Sharklio.addListener('error', (error) => {
    console.warn(`${error.code}: ${error.message}`);
  });
  return () => {
    closed.remove();
    failed.remove();
  };
}, []);
```

| Event | When |
| --- | --- |
| `opened` | The offerwall finished loading its first page. |
| `closed` | The user closed the offerwall. A good moment to load the user’s balance from your server. |
| `error` | The listener receives a `SharklioError` with a `code`: `NOT_INITIALIZED`, `INVALID_APP_ID`, `INVALID_TOKEN`, `TOKEN_EXPIRED_OR_USED`, `NETWORK`, `UNSUPPORTED`, or `UNKNOWN`, the same names the native SDKs use. Create a new session and try again. |

Errors from `init` and `open` arrive right after the call returns, so a listener you add in the same tick still receives them. TypeScript types are included.

## App Store and Google Play privacy

The iOS SDK inside the package has a privacy manifest that lists what the offerwall collects, as described in our [privacy policy](https://sharklio.com/privacy). In App Store Connect, under App Privacy, and in Google Play’s Data safety form, add these data types for your app:

| Data type | Linked to the user | Used for tracking | Purpose |
| --- | --- | --- | --- |
| User ID | Yes | No | App Functionality |
| Device ID | Yes | No | App Functionality |
| Coarse Location | Yes | No | App Functionality |
| Product Interaction | Yes | No | App Functionality |

The user ID is the pseudonymous ID your server sends with the session, the device ID is used for fraud prevention, the coarse location comes from the IP address, and product interaction is the offers a user views, starts, and completes. The SDK does not track users across apps and does not use the advertising identifier. In Google Play’s Data safety form, the same data types are called User IDs, Device or other IDs, Approximate location, and App interactions.

## Security

- Create sessions on your server only. Never put the API key or the link hash salt in your app, because anyone can read an app’s files, including its JavaScript bundle.
- Credit rewards only from the signed postback on your server, never from events in the app. Events can be faked on a user’s device.
- Make sure your own endpoint that returns tokens only does so for the signed-in user.

## Testing

Before you launch, create a session from your server for a test user ID and open it in a development build on an Android phone, an iPhone, or the iOS Simulator. Check that the offerwall opens, that an offer opens in the store or the browser, and that the back and close buttons work. Then send test postbacks from Integration status on the Integration tab of your app to check your server. Test on a normal home or mobile connection: on a VPN or a test device in the cloud, the offerwall shows a block page such as VPN detected instead of offers. See [Testing](https://docs.sharklio.com/testing).

Clicks that come through the package show as `sdk` in the `{integration}` postback macro and in the [Reporting API](https://docs.sharklio.com/reporting-api), and as Mobile SDK in your dashboard, like the Android and iOS SDKs.

## Changelog

**1.0.0**: first release. `Sharklio.init` and `Sharklio.open` with the same checks and error codes as the Android and iOS SDKs, `opened`, `closed` and `error` events, top bar options, a TurboModule for the New Architecture that also works with the old one, the Android SDK 1.1.0 added to Gradle automatically, the iOS SDK 1.0.1 bundled, and an Expo config plugin.

## License

The package is free to use under the Apache License 2.0. The license file is in the package.

## Quick reference

### Install

```
# .npmrc
@sharklio:registry=https://sharklio.com/npm/

npm install @sharklio/react-native-offerwall
```

### Create a session

`POST api.sharklio.com/v1/session`

```bash
curl -X POST "https://api.sharklio.com/v1/session" \
  -H "Authorization: Bearer $SHARKLIO_API_KEY" \
  -d "user_id=user_1234"
```

```php
$ch = curl_init('https://api.sharklio.com/v1/session');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => http_build_query(['user_id' => $userId]),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 10,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);
$token = json_decode(curl_exec($ch), true)['token'] ?? null;
```

```javascript
const res = await fetch('https://api.sharklio.com/v1/session', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SHARKLIO_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ user_id: userId }),
});
const { token } = await res.json();
```

Your API key is in your dashboard under Apps, your app, Integration. Up to 600 requests per minute for each app.

Questions? [partners@sharklio.com](mailto:partners@sharklio.com)
