React Native SDK
Native ads, interstitial ads, and rewarded ads for React Native apps.
New to Simula?
Head to Getting Started first to create your publisher account, get your API key, and set up your first ad unit. Then come back here to integrate the SDK.
Installation
npm install @simula/ads-react-native
# or
yarn add @simula/ads-react-nativeRequires React >= 16.8.0 and React Native >= 0.60.0.
Provider Setup
Wrap your application with SimulaProvider to initialize the SDK:
import { SimulaProvider } from '@simula/ads-react-native';
function App() {
return (
<SimulaProvider
apiKey="YOUR_API_KEY"
primaryUserID="hashed_user_id"
devMode={false}
>
{/* Your application components */}
</SimulaProvider>
);
}Provider Props
| Prop | Type | Default | Description |
|---|---|---|---|
apiKey | string | required | Your Simula API key |
devMode | boolean | false | Enables development mode — always fills, no billing, excluded from ML targeting, and enables debug console logging. Set to false before shipping |
primaryUserID | string | — | Hashed user ID for better ad targeting |
privacy | SimulaPrivacyConfig | — | Granular consent configuration. See Privacy |
telemetryEnabled | boolean | true | Enables SDK performance and error telemetry |
adContext | SimulaAdContext | — | Contextual targeting signals attached to every native ad request |
initializeOnMount | boolean | true | Initializes the native SDK and opens a session as soon as the provider mounts. Set to false to control timing with SimulaAds.initialize() |
Imperative Initialization
For cases where the provider pattern doesn't fit:
import { SimulaAds } from '@simula/ads-react-native';
await SimulaAds.initialize({
apiKey: 'YOUR_API_KEY',
devMode: false,
primaryUserID: 'hashed_user_id',
});
const isReady = await SimulaAds.isInitialized();Updating the User ID
Update the primary user identifier at runtime after login or logout:
SimulaAds.updatePrimaryUserID('new_hashed_id'); // after login
SimulaAds.updatePrimaryUserID(null); // after logoutDev mode
Set devMode to true during development. Every ad request returns a test ad (always fills), no impressions are billed, test traffic is excluded from Simula's ML targeting models, and debug logs are printed to the console. Set to false before releasing to production.
Components
| Component | Description | Guide |
|---|---|---|
NativeAd | Inline native ad card for feeds | NativeAd |
SimulaInterstitialAd | Full-screen interstitial ad (imperative) | InterstitialAd |
useInterstitialAd | Interstitial ad hook | InterstitialAd |
SimulaRewardedAd | Rewarded ad with play-to-earn gate (imperative) | RewardedAd |
useRewardedAd | Rewarded ad hook | RewardedAd |
CharacterSelector | Pre-built character discovery UI | CharacterSelector |
Privacy
The SDK automatically reads IAB CMP consent values from device storage — no setup is required for most apps. This entire section is optional. Only configure privacy manually if you need to override the auto-read values or manage consent outside a CMP.
Control consent at runtime with the SimulaPrivacy API. Explicit configuration takes precedence.
import { SimulaPrivacy } from '@simula/ads-react-native';
// Replace all consent signals
SimulaPrivacy.apply({
tcString: '...',
gdprApplies: true,
coppaApplies: false,
enableAdvertisingId: true,
});
// Merge a partial update
SimulaPrivacy.update({ tcString: '...' });
// Clear specific signals (fall back to auto-read IAB values)
SimulaPrivacy.clearConsent({ tcString: true, gdprApplies: true });
// iOS: Prompt for App Tracking Transparency
const status = await SimulaPrivacy.requestTrackingAuthorization();
// "authorized" | "denied" | "restricted" | "not_determined" (iOS)
// "unavailable" (Android)SimulaPrivacyConfig
| Field | Type | Default | Description |
|---|---|---|---|
tcString | string | — | IAB TCF v2.2 consent string |
uspString | string | — | IAB US Privacy (CCPA), e.g. "1YNN" |
gppString | string | — | IAB Global Privacy Platform string |
gppSid | string | — | GPP section IDs, comma-separated |
gdprApplies | boolean | — | Whether GDPR applies |
tcfPurpose1Consent | boolean | — | Explicit TCF Purpose 1 (storage) consent |
coppaApplies | boolean | false | Child-directed treatment (COPPA) |
enableAdvertisingId | boolean | false | Opt-in for IDFA/GAID collection |
Ad Context
Pass contextual targeting signals via adContext to improve native ad relevance. The more context you provide, the better the ad targeting.
SimulaAdContext
| Field | Type | Description |
|---|---|---|
searchTerm | string | Current search or query term in the feed |
tags | string[] | Content tags (backend keeps at most 10) |
category | string | Feed category |
title | string | Title of the surrounding feed item |
description | string | Description of the surrounding feed item |
userProfile | string | Opaque user-profile signal |
userEmail | string | User email, if available |
customContext | Record<string, unknown> | Arbitrary JSON key-values |
nsfw | boolean | Whether surrounding content is NSFW. Default false |
All fields are optional. The customContext field accepts nested objects, arrays, strings, numbers, and booleans — use it for platform-specific data like recently interacted characters.
import { SimulaProvider } from '@simula/ads-react-native';
function App({ user }) {
const adContext = {
category: 'ai-chat',
customContext: {
recentCharacters: [
{ id: 'reze-01', name: 'Reze', description: 'The Bomb Devil from Chainsaw Man' },
{ id: 'power-02', name: 'Power', description: 'The Blood Fiend from Chainsaw Man' },
],
preferredGenre: 'anime',
},
};
return (
<SimulaProvider
apiKey="YOUR_API_KEY"
primaryUserID={hashedUserId}
adContext={adContext}
>
<MainScreen />
</SimulaProvider>
);
}Update context at runtime when the user navigates to a new feed or chat:
import { SimulaAds } from '@simula/ads-react-native';
SimulaAds.updateContext({
category: 'ai-chat',
customContext: {
recentCharacters: [
{ id: 'reze-01', name: 'Reze', description: 'The Bomb Devil from Chainsaw Man' },
],
},
});
// Clear context
SimulaAds.updateContext(null);updateContext is a full replacement
Calling updateContext replaces the entire context — it does not merge with the previous value. Omitted fields are removed. Pass the complete context every time.
Error Handling
All ad errors are reported as a SimulaAdError object:
interface SimulaAdError {
code: string; // stable error code from the table below
message: string; // human-readable description
retryInSeconds?: number; // seconds until load() unblocks (duplicate_request only)
}Error Codes
| Code | Description |
|---|---|
not_initialized | SDK not initialized |
no_session | Session creation failed |
no_fill | No ad available for this placement |
not_ready | show() called before ad finished loading |
stale | Loaded ad expired (1-hour limit) |
duplicate_request | load() called while a request is in flight. retryInSeconds field indicates when to retry |
already_showing | show() called while an ad is already on screen |
no_presentation_context | No Activity/window available to present the ad |
network | Network connectivity error |
ad_unit_not_found | Ad unit ID is not registered for this app (check the publisher dashboard) |
unsupported_platform | Platform not supported (iOS only) |
verification_failed | Reward verification failed (rewarded ads only) |
AdValue
Revenue data surfaced on PAID events and NativeAd.onPaid. All figures are serve-time estimates derived from the backend floor CPM.
interface AdValue {
valueMicros: number;
currencyCode: string;
precisionType: AdValuePrecision;
expectedCpm: number;
expectedRevenue: number;
}| Field | Type | Description |
|---|---|---|
valueMicros | number | Per-impression revenue in micros (5000 = $0.005) |
currencyCode | string | ISO-4217 currency code, e.g. "USD" |
precisionType | AdValuePrecision | Estimate quality — currently always "ESTIMATED" |
expectedCpm | number | Estimated CPM (valueMicros / 1_000) |
expectedRevenue | number | Estimated per-impression revenue (valueMicros / 1_000_000) |
