React Native SDK
@notpixel/react-native forwards calls to your chosen AI provider and selects
contextual ads in parallel. It returns the provider reply with an optional
sponsored block and a structured ad for native rendering.
Installation
Choose direct installation and configure the client in code, or use the optional English assistant. Both paths work with new and existing accounts; SDK usage does not require CLI login.
Direct installation
For local processing (the default) in a React Native CLI app:
npm install @notpixel/react-native @notpixel/react-native-embedding-local
cd ios && pod installFor Expo, use npx expo install with these package names and rebuild your native
app. Local embeddings are unavailable in Expo Go. Use React Native’s New
Architecture. Local examples below import from @notpixel/react-native/local.
For remote processing, install only @notpixel/react-native (using expo install
inside Expo projects) and configure the base client explicitly:
import Ads from '@notpixel/react-native';
const ads = new Ads({
publisherId: 'YOUR_PUBLISHER_ID',
embeddingMode: 'remote',
});A fresh remote installation has no local inference addon or model download.
Optional assisted installation
npx notpixel@latest installRun inside your existing app. The assistant detects React Native/Expo, offers
login or account creation, asks local/remote, installs the needed packages and
generates notpixel.ts. You can then import ads from that generated file.
See the installation guide for pnpm, Yarn and Bun.
Preview test ads
Set testMode: true on the client and use getAd({ input }) to preview an
eligible ad from the NotPixel API with your publisher ID. The native card shows
the test disclosure and disables its CTA and tracking. See Test Mode.
Provider bypass
import Ads from '@notpixel/react-native/local';
const ads = new Ads({
publisherId: 'YOUR_PUBLISHER_ID',
model: 'openai/YOUR_MODEL',
apiKeys: { openai: userProvidedKey },
});
const result = await ads.offer({ input: 'How can I optimize SQL?' });Credentials are supplied at runtime. For credentials kept on your server, pass
your existing authenticated providerFetch. It receives the original provider
URL and request options and returns the provider response, preserving incremental
SSE. Keep permanent secrets out of app bundles.
for await (const chunk of ads.stream({ input, signal: controller.signal })) {
if (chunk.type === 'text') appendText(chunk.content ?? '');
if (chunk.type === 'ad') setAd(chunk.ad);
}Text streams immediately, followed by an optional ad. Ad failures preserve the
provider response. Existing provider prefixes and respond({ input, llm }) are
also supported.
Native presentation
import { AdCard, NotPixelProvider } from '@notpixel/react-native/react';
<NotPixelProvider client={ads}>
{ad ? <AdCard ad={ad} isVisible={screenIsFocused} /> : null}
</NotPixelProvider>AdCard and AdBanner include disclosure, CTA navigation, tracking, hide/report
actions and light/dark styling. Supply screen focus and list viewability through
isVisible when screens stay mounted or rows are recycled.
Impressions are confirmed after half the measured area remains in the window for one second while the app is active. The confirmation settles a pending commercial impression once. Reports preserve their draft on failure and hide the ad after confirmed submission.
Render the structured ad separately from provider text to avoid showing the same
sponsored block twice. Custom renderers can use ads.tracker.impression, .click,
.conversion and .feedback. useAd({ input, requestId, enabled }) provides
standalone selection with ad, loading, error and refetch.
Native placements and app verification
In Publisher → Settings → Domains & apps, register the iOS Bundle ID or Android Application ID, then create a placement under that app. Configure App Attest on iOS with the production entitlement, or link your Play Integrity Cloud project and enter the Play app signing certificate and dedicated service account on Android. Use a signed build on a real device to complete app verification.
For Expo, install the native modules with
npx expo install @expo/app-integrity expo-crypto expo-secure-store and rebuild
the app. The adapter is opt-in and the rest of the SDK works independently of it.
import * as AppIntegrity from '@expo/app-integrity';
import * as Crypto from 'expo-crypto';
import * as SecureStore from 'expo-secure-store';
import { Platform } from 'react-native';
import Ads, { createExpoIntegrityAdapter } from '@notpixel/react-native/local';
const propertyId = 'YOUR_PROPERTY_ID';
const ads = new Ads({
publisherId: 'YOUR_PUBLISHER_ID',
native: {
propertyId,
integrity: createExpoIntegrityAdapter({
propertyId,
platform: Platform.OS === 'ios' ? 'ios' : 'android',
appIntegrity: AppIntegrity,
storage: SecureStore,
async hashChallenge(challenge) {
const digest = await Crypto.digestStringAsync(Crypto.CryptoDigestAlgorithm.SHA256, challenge, {
encoding: Crypto.CryptoEncoding.BASE64,
});
return digest.replaceAll('+', '-').replaceAll('/', '_').replace(/=+$/, '');
},
}),
},
});Run await ads.verifyNativeApp(code) once from the signed app with the code
generated in the panel, then refresh the property status. Warm up with
ads.prepareNativeDelivery() before the first request and handle any error
without interrupting the app. Use ads.getAd({ input, requestId, placement })
or pass the same fields to useAd. In commercial delivery the card confirms
the pending opportunity before enabling the tracked CTA. Custom renderers
can call ads.confirmNativeImpression(opportunityId) after qualifying
visibility. Use explicit test mode on devices without attestation.
Privacy and initialization
With local processing, only vectors reach the NotPixel ad API; embedding failures never trigger a text fallback. Explicit remote processing sends sanitized context to NotPixel and its Cloudflare inference infrastructure. Your chosen LLM provider receives the original prompt independently of this setting.
Initial local loading downloads approximately 35 MB of verified model/tokenizer assets, then caches them on the device. Preload the model before the first opportunity:
await ads.embedding.preload();The default ad budget is three seconds, including model loading. Change it with
adTimeoutMs. Missing ads do not interrupt the provider response.
See the React Native example for a demo without credentials or paid calls.