@adshift/react-native-plugin
v1.0.0
Published
AdShift SDK for React Native - Mobile Attribution, Event Tracking, SKAdNetwork 4.0+, Deep Linking and GDPR/TCF 2.2 Compliance
Readme
AdShift React Native Plugin
Official AdShift SDK for React Native. This plugin wraps the native iOS SDK and Android SDK, providing a unified TypeScript API for React Native apps.
Enable mobile attribution, in-app event tracking, SKAdNetwork 4.0+ integration, deep linking, and GDPR/TCF 2.2 compliance in your React Native apps.
📚 Table of Contents
- Features
- Requirements
- Installation
- Quick Start
- API Reference
- Platform-Specific Setup
- TypeScript Support
- Example App
- Troubleshooting
- Support
Features
- ✅ Install Attribution — Accurate install tracking across platforms
- ✅ In-App Event Tracking — Track user actions and conversions with 30+ predefined events
- ✅ SKAdNetwork 4.0+ — Full support for iOS privacy-preserving attribution
- ✅ Deep Linking — Direct and deferred deep link support with unified API
- ✅ GDPR/DMA Compliance — Manual consent and TCF 2.2 automatic collection
- ✅ Offline Mode — Events are cached and sent when connectivity returns
- ✅ New Architecture — Built for React Native 0.82+ with Turbo Modules
- ✅ TypeScript First — Full type definitions with IntelliSense support
- ✅ Cross-Platform — Single API for iOS and Android
Requirements
| Platform | Minimum Version | |----------|-----------------| | React Native | 0.82.0+ (New Architecture) | | iOS | 15.0+ | | Android | API 21+ (Android 5.0) | | Node.js | 18+ | | TypeScript | 5.0+ (recommended) |
⚠️ Note: This plugin requires React Native's New Architecture (Turbo Modules). Old Architecture (Bridge) is not supported.
Installation
Using npm
npm install @adshift/react-native-pluginUsing yarn
yarn add @adshift/react-native-pluginiOS Setup (CocoaPods)
After installing the npm package:
cd ios && pod installAndroid Setup
No additional setup required — the plugin auto-links with React Native.
Quick Start
1. Initialize the SDK
⚠️ Important: iOS and Android apps have different API keys. Get both from your AdShift dashboard.
import { Platform } from 'react-native';
import { Adshift } from '@adshift/react-native-plugin';
// API keys are different for iOS and Android
const API_KEYS = {
ios: 'YOUR_IOS_API_KEY',
android: 'YOUR_ANDROID_API_KEY',
};
// Initialize in your app's entry point (App.tsx or index.js)
Adshift.initialize({
apiKey: Platform.select({
ios: API_KEYS.ios,
android: API_KEYS.android,
default: API_KEYS.android,
})!,
isDebug: __DEV__, // Enable debug logs in development
});2. Start Tracking
// Start the SDK (typically after user consent or app launch)
const result = await Adshift.start();
if (result.success) {
console.log('AdShift started successfully');
}3. Track Events
import { Adshift, AdshiftEventType } from '@adshift/react-native-plugin';
// Track a simple event
await Adshift.trackEvent(AdshiftEventType.LOGIN);
// Track event with parameters
await Adshift.trackEvent(AdshiftEventType.ADD_TO_CART, {
product_id: 'SKU123',
price: 29.99,
quantity: 1,
});
// Track purchase (for SKAdNetwork conversion value)
await Adshift.trackPurchase({
productId: 'premium_subscription',
revenue: 9.99,
currency: 'USD',
transactionId: 'TXN_12345',
});4. Handle Deep Links
import { useEffect, useRef } from 'react';
import { Adshift } from '@adshift/react-native-plugin';
import type { DeepLinkSubscription } from '@adshift/react-native-plugin';
function App() {
const subscriptionRef = useRef<DeepLinkSubscription | null>(null);
useEffect(() => {
// Listen for deep links (direct and deferred)
subscriptionRef.current = Adshift.onDeepLink((deepLink) => {
if (deepLink.status === 'found') {
console.log('Deep link URL:', deepLink.deepLink);
console.log('Is deferred:', deepLink.isDeferred);
// Navigate based on deepLink.deepLinkValue or deepLink.params
}
});
return () => {
subscriptionRef.current?.remove();
};
}, []);
return <YourApp />;
}API Reference
SDK Lifecycle
Adshift.initialize(config)
Configure the SDK. Call this before any other SDK method.
⚠️ Note: iOS and Android apps require separate API keys from the AdShift dashboard.
import { Platform } from 'react-native';
import type { AdshiftConfig } from '@adshift/react-native-plugin';
const config: AdshiftConfig = {
apiKey: Platform.OS === 'ios' ? 'IOS_KEY' : 'ANDROID_KEY', // Required - platform-specific!
isDebug: true, // Optional: Enable debug logs
appOpenDebounceMs: 10000, // Optional: Debounce for app_open events (ms)
// iOS only
disableSKAN: false, // Optional: Disable SKAdNetwork
waitForATTBeforeStart: true, // Optional: Wait for ATT before install event
attTimeoutMs: 30000, // Optional: ATT timeout (ms)
// Android only
collectOaid: false, // Optional: Collect OAID (China devices)
};
Adshift.initialize(config);Adshift.start()
Start the SDK and begin tracking. Returns a promise with the result.
const result = await Adshift.start();
// result: { success: boolean, message?: string }Adshift.stop()
Stop the SDK. Events will not be tracked until start() is called again.
Adshift.stop();Adshift.isStarted()
Check if the SDK is currently running.
const isRunning = Adshift.isStarted(); // booleanEvent Tracking
Adshift.trackEvent(eventName, values?)
Track an in-app event with optional parameters.
// Simple event
await Adshift.trackEvent(AdshiftEventType.LOGIN);
// Event with parameters
await Adshift.trackEvent(AdshiftEventType.SEARCH, {
search_term: 'running shoes',
results_count: 42,
});
// Custom event
await Adshift.trackEvent('custom_button_click', {
button_name: 'checkout',
});Adshift.trackPurchase(params)
Track a purchase event. Use this for accurate SKAdNetwork conversion value calculation.
await Adshift.trackPurchase({
productId: 'com.app.premium',
revenue: 9.99, // Use 'revenue' for SKAN CV calculation
currency: 'USD',
transactionId: 'txn_123',
});💡 Tip: Use
revenue(notprice) for accurate SKAdNetwork attribution.
Predefined Event Types
import { AdshiftEventType } from '@adshift/react-native-plugin';
// Available events
AdshiftEventType.LOGIN
AdshiftEventType.PURCHASE
AdshiftEventType.ADD_TO_CART
AdshiftEventType.ADD_TO_WISHLIST
AdshiftEventType.COMPLETE_REGISTRATION
AdshiftEventType.INITIATED_CHECKOUT
AdshiftEventType.ADD_PAYMENT_INFO
AdshiftEventType.SUBSCRIBE
AdshiftEventType.START_TRIAL
AdshiftEventType.LEVEL_ACHIEVED
AdshiftEventType.ACHIEVEMENT_UNLOCKED
AdshiftEventType.TUTORIAL_COMPLETION
AdshiftEventType.CONTENT_VIEW
AdshiftEventType.LIST_VIEW
AdshiftEventType.SEARCH
AdshiftEventType.RATE
AdshiftEventType.SHARE
AdshiftEventType.INVITE
AdshiftEventType.RE_ENGAGE
AdshiftEventType.UPDATE
AdshiftEventType.OPENED_FROM_PUSH_NOTIFICATION
AdshiftEventType.AD_CLICK
AdshiftEventType.AD_VIEW
AdshiftEventType.SPENT_CREDITS
AdshiftEventType.TRAVEL_BOOKING
AdshiftEventType.LOCATION_CHANGED
AdshiftEventType.LOCATION_COORDINATES
AdshiftEventType.ORDER_ID
AdshiftEventType.CUSTOMER_SEGMENTConsent Management
Manual Consent (GDPR/DMA)
import { AdshiftConsent } from '@adshift/react-native-plugin';
// For GDPR users — grant all consent
Adshift.setConsentData(
AdshiftConsent.forGDPRUser({
hasConsentForDataUsage: true,
hasConsentForAdsPersonalization: true,
hasConsentForAdStorage: true,
})
);
// For GDPR users — deny consent
Adshift.setConsentData(
AdshiftConsent.forGDPRUser({
hasConsentForDataUsage: false,
hasConsentForAdsPersonalization: false,
hasConsentForAdStorage: false,
})
);
// For non-GDPR users (e.g., US users without state privacy laws)
Adshift.setConsentData(AdshiftConsent.forNonGDPRUser());TCF 2.2 Automatic Collection
If you use a CMP (Consent Management Platform) that stores IAB TCF data:
// Enable TCF collection BEFORE calling start()
Adshift.enableTCFDataCollection(true);
// Start SDK after CMP dialog completes
await Adshift.start();
// Refresh consent after user changes preferences
const snapshot = await Adshift.refreshConsent();
console.log('Consent source:', snapshot.source);
console.log('Has consent:', snapshot.hasConsent);Consent Snapshot Response
interface ConsentSnapshot {
source: 'manual' | 'tcf' | 'gpp' | 'none';
gdprApplies?: number;
tcStringPresent: boolean;
adUserDataEnabled?: boolean;
adPersonalizationEnabled?: boolean;
adStorageEnabled?: boolean;
appliedAtMillis: number;
hasConsent: boolean; // Convenience field
}Deep Linking
Listen for Deep Links
Subscribe to deep link events for both direct and deferred deep links:
import { Adshift, AdshiftDeepLinkStatus } from '@adshift/react-native-plugin';
import type { DeepLinkSubscription, AdshiftDeepLink } from '@adshift/react-native-plugin';
const subscription: DeepLinkSubscription = Adshift.onDeepLink((deepLink: AdshiftDeepLink) => {
switch (deepLink.status) {
case AdshiftDeepLinkStatus.FOUND:
console.log('URL:', deepLink.deepLink);
console.log('Value:', deepLink.deepLinkValue);
console.log('Is Deferred:', deepLink.isDeferred);
console.log('Params:', deepLink.params);
// Navigate to appropriate screen
break;
case AdshiftDeepLinkStatus.NOT_FOUND:
// No deep link available
break;
case AdshiftDeepLinkStatus.ERROR:
console.error('Deep link error:', deepLink.errorMessage);
break;
}
});
// Clean up when done
subscription.remove();Handle Incoming URLs
When your app receives a URL (e.g., from Linking API):
import { Linking } from 'react-native';
// Handle URL when app is already open
Linking.addEventListener('url', async ({ url }) => {
const result = await Adshift.handleDeepLink(url);
console.log('Deep link result:', result);
});
// Handle URL that launched the app
const initialUrl = await Linking.getInitialURL();
if (initialUrl) {
await Adshift.handleDeepLink(initialUrl);
}Deep Link Response
interface AdshiftDeepLink {
status: 'found' | 'notFound' | 'error';
deepLink?: string; // Full URL
deepLinkValue?: string; // Routing value (e.g., 'product/123')
deepLinkSub1?: string; // Sub-parameter 1
deepLinkSub2?: string; // Sub-parameter 2
deepLinkSub3?: string; // Sub-parameter 3
deepLinkSub4?: string; // Sub-parameter 4
deepLinkSub5?: string; // Sub-parameter 5
params?: Record<string, string>; // All query parameters
isDeferred: boolean; // true if from deferred flow
errorMessage?: string; // Error description
}Configuration
Set Customer User ID
Associate events with your own user identifier:
Adshift.setCustomerUserId('user_12345');💡 Tip: Set CUID before
start()to associate it with the install event.
Debug Mode
Adshift.setDebugEnabled(true);App Open Debounce
Control how often app_open events are sent when the app returns from background:
// Only send app_open if user was away for 30+ seconds
Adshift.setAppOpenDebounceMs(30000);
// Send app_open every time (no debounce)
Adshift.setAppOpenDebounceMs(0);Get SDK Info
const info = Adshift.getInfo();
console.log(info.platform); // 'ios' or 'android'
console.log(info.version); // Plugin versionPlatform-Specific Setup
iOS Setup
1. Update Podfile
Ensure your iOS deployment target is 15.0+:
# ios/Podfile
platform :ios, '15.0'Then run:
cd ios && pod install2. Add App Tracking Transparency (Recommended)
To request IDFA permission, add to Info.plist:
<key>NSUserTrackingUsageDescription</key>
<string>This app uses tracking to provide personalized ads and measure ad effectiveness.</string>Then configure SDK to wait for ATT:
Adshift.initialize({
apiKey: 'YOUR_API_KEY',
waitForATTBeforeStart: true,
attTimeoutMs: 30000, // 30 seconds
});3. Configure SKAdNetwork Postback
Add to Info.plist to receive direct SKAN postbacks:
<key>NSAdvertisingAttributionReportEndpoint</key>
<string>https://adshift-skadnetwork.com</string>4. Configure Universal Links (Deep Linking)
- Add Associated Domains capability in Xcode
- Add your domain:
applinks:yourapp.rightlink.me - Configure
apple-app-site-associationon your server
For custom URL schemes, add to Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>yourapp</string>
</array>
</dict>
</array>Android Setup
1. Update build.gradle
Ensure minimum SDK is 21+:
// android/app/build.gradle
android {
defaultConfig {
minSdkVersion 21
}
}2. Permissions
These permissions are included in the SDK manifest automatically:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />To remove AD_ID permission (for COPPA compliance):
<uses-permission android:name="com.google.android.gms.permission.AD_ID"
tools:node="remove" />3. Configure App Links (Deep Linking)
Add intent filter to AndroidManifest.xml:
<activity android:name=".MainActivity">
<!-- Existing intent filters... -->
<!-- App Links for deep linking -->
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="yourapp.rightlink.me" />
</intent-filter>
<!-- Custom URL Scheme -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="yourapp" android:host="open" />
</intent-filter>
</activity>4. ProGuard Rules (if using code shrinking)
Add to proguard-rules.pro:
# AdShift SDK
-keep class com.adshift.sdk.** { *; }
-keep interface com.adshift.sdk.** { *; }TypeScript Support
This plugin is written in TypeScript and provides full type definitions out of the box.
Importing Types
import {
Adshift,
AdshiftEventType,
AdshiftConsent,
AdshiftDeepLinkStatus,
} from '@adshift/react-native-plugin';
import type {
AdshiftConfig,
AdshiftDeepLink,
StartResult,
EventValues,
PurchaseParams,
DeepLinkSubscription,
DeepLinkCallback,
} from '@adshift/react-native-plugin';Type Definitions
// Configuration
interface AdshiftConfig {
apiKey: string;
isDebug?: boolean;
appOpenDebounceMs?: number;
// iOS only
disableSKAN?: boolean;
waitForATTBeforeStart?: boolean;
attTimeoutMs?: number;
// Android only
collectOaid?: boolean;
}
// Event values
type EventValues = Record<string, string | number | boolean>;
// Purchase parameters
interface PurchaseParams {
productId: string;
revenue: number;
currency: string;
transactionId: string;
}
// Start result
interface StartResult {
success: boolean;
message?: string;
}
// Deep link callback
type DeepLinkCallback = (deepLink: AdshiftDeepLink) => void;
// Subscription handle
interface DeepLinkSubscription {
remove: () => void;
}Example App
The plugin includes a comprehensive example app demonstrating all features:
cd example
yarn install
cd ios && pod install && cd ..
# Run on iOS
yarn ios
# Run on Android
yarn androidThe example app includes:
- SDK initialization and lifecycle management
- All event types with parameter examples
- Consent management UI (GDPR/TCF)
- Deep link testing
- Live event log console
Troubleshooting
iOS Issues
"Module 'AdshiftSDK' not found"
cd ios
pod deintegrate
pod installATT Dialog Not Showing
- Ensure
NSUserTrackingUsageDescriptionis inInfo.plist - Set
waitForATTBeforeStart: truein config - Test on physical device (simulator may not show ATT)
Deep Links Not Working
- Verify Associated Domains capability is enabled
- Check
apple-app-site-associationfile is accessible - Test with:
xcrun simctl openurl booted "yourapp://open?test=1"
Android Issues
Build Fails with Dependency Conflicts
Add to android/build.gradle:
allprojects {
configurations.all {
resolutionStrategy {
force 'com.google.android.gms:play-services-ads-identifier:18.0.1'
}
}
}Deep Links Not Working
- Verify intent-filter in
AndroidManifest.xml - Check App Links verification:
adb shell pm get-app-links your.package.name - Test with:
adb shell am start -W -a android.intent.action.VIEW -d "yourapp://open?test=1"
General Issues
Events Not Sending
- Check
Adshift.isStarted()returnstrue - Enable debug mode:
Adshift.setDebugEnabled(true) - Check network connectivity
- Verify API key is correct
TypeScript Errors
Ensure you're using TypeScript 5.0+ and have the latest types:
yarn add @adshift/react-native-plugin@latestSupport
- 📖 Documentation: https://dev.adshift.com/docs/react-native-sdk
- 🐛 Issues: https://github.com/AdShift/react_native_plugin/issues
- 📧 Email: [email protected]
License
This SDK is proprietary software. See LICENSE for details.
© 2024-2026 AdShift. All rights reserved.
