Skip to main content
React & React NativeUpdated Jun 2

Step 4: React Native (WebView)

There is no native AppLixir module for React Native. You run the HTML5 SDK inside a WebView (react-native-webview). This works well — but only if the WebView has a real web origin.

The one rule: load a real https:// URL

The single most common reason ads do not fill in React Native is loading the SDK from inline HTML (source={{ html: "…" }}) or a local file. That gives the page the origin "null", which breaks the two things the SDK depends on:

  1. Consent. The TCF/GPP consent manager communicates over postMessage. With a null origin you get Failed to execute 'postMessage' … Invalid target origin 'null' and no consent string is ever produced.
  2. Demand. The ad server matches the request to your registered domain via the referrer. A null origin matches nothing, so the request returns AdError 303: No Ads VAST response — an empty fill.

Fix: host your ad page on the same https:// domain you registered with AppLixir (the one in your ads.txt) and point the WebView at it with source={{ uri }}.

The pattern

Host a small page on your domain (for example https://yourgame.com/rewarded) that loads the SDK and posts a message back to React Native when the user earns the reward. Then render it in a WebView.

1. The hosted page

Served from https://yourgame.com/rewarded:

<!doctype html>
<html>
<head>
<script src="https://cdn.applixir.com/applixir.app.v6.1.0.js" async></script>
</head>
<body>
<div id="applixir-ad-container"></div>
<button id="watch">Watch ad</button>
<script>
function send(msg) {
if (window.ReactNativeWebView) {
window.ReactNativeWebView.postMessage(JSON.stringify(msg));
}
}
document.getElementById("watch").addEventListener("click", () => {
initializeAndOpenPlayer({
apiKey: "YOUR-API-KEY",
injectionElementId: "applixir-ad-container",
adStatusCallbackFn: (status) => {
if (status.type === "complete") send({ type: "reward" });
else if (["skipped", "manuallyEnded", "allAdsCompleted"].includes(status.type)) {
send({ type: "closed", reason: status.type });
}
},
adErrorCallbackFn: (error) => send({ type: "error", data: error.getError().data }),
});
});
</script>
</body>
</html>

2. The React Native screen

import { WebView } from "react-native-webview";

export function RewardedAd({ onReward }) {
return (
<WebView
// ✅ A real https origin — consent and demand both work.
source={{ uri: "https://yourgame.com/rewarded" }}
// ❌ Never: source={{ html: "<html>…</html>" }} → origin "null" → no fill.

javaScriptEnabled
domStorageEnabled
thirdPartyCookiesEnabled // Android: needed for consent + ad serving
sharedCookiesEnabled // iOS: share the app cookie store
allowsInlineMediaPlayback // iOS: play the video inline, not fullscreen-only
mediaPlaybackRequiresUserAction={false}
originWhitelist={["https://*"]}
mixedContentMode="always" // Android
onMessage={(event) => {
const msg = JSON.parse(event.nativeEvent.data);
if (msg.type === "reward") onReward?.();
if (msg.type === "error") console.warn("AppLixir error:", msg.data);
}}
/>
);
}

WebView props that matter

PropPlatformWhy
source={{ uri }}bothReal origin — the whole integration depends on this
javaScriptEnabledbothThe SDK is JavaScript
domStorageEnabledAndroidConsent + frequency state use storage
thirdPartyCookiesEnabledAndroidConsent handshake and ad serving need cookies
sharedCookiesEnablediOSReuse the app's cookie store (WKWebView)
allowsInlineMediaPlaybackiOSWithout it, video is forced fullscreen
mediaPlaybackRequiresUserAction={false}bothThe user already tapped to open the player
mixedContentMode="always"AndroidAvoid blocking sub-resources

Checklist

  • WebView loads a registered https:// domain via source={{ uri }} — not inline HTML, not file://.
  • That domain serves your ads.txt (see Step 6).
  • JavaScript, DOM storage, and cookies are all enabled (table above).
  • The ad is triggered by a tap inside the WebView, not auto-played on load.
  • The persistent reward is granted from the server-side web callback (see Step 5); the reward message is optimistic UI only.

If you still see Invalid target origin 'null' or AdError 303 after this, the WebView is not actually loading from your https domain — re-check that you are using source={{ uri }} and not an inline-HTML or bundled file.

Next: Callbacks & rewards.