insert-affiliate-react-native-sdk 1.8.0 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/readme.md CHANGED
@@ -1,72 +1,65 @@
1
1
  # InsertAffiliateReactNative SDK
2
2
 
3
- ## Overview
3
+ ![Version](https://img.shields.io/badge/version-1.0.0-brightgreen) ![React Native](https://img.shields.io/badge/React%20Native-0.60%2B-blue) ![Platform](https://img.shields.io/badge/platform-iOS%20%7C%20Android-lightgrey)
4
4
 
5
- The **InsertAffiliateReactNative SDK** is designed for React Native applications, providing seamless integration with the [Insert Affiliate platform](https://insertaffiliate.com). The InsertAffiliateReactNative SDK simplifies affiliate marketing for iOS apps with in-app-purchases, allowing developers to create a seamless user experience for affiliate tracking and monetisation.
5
+ The official React Native SDK for [Insert Affiliate](https://insertaffiliate.com) - track affiliate-driven in-app purchases and reward your partners automatically.
6
6
 
7
- ### Features
7
+ **What does this SDK do?** It connects your React Native app to Insert Affiliate's platform, enabling you to track which affiliates drive subscriptions and automatically pay them commissions when users make in-app purchases.
8
8
 
9
- - **Unique Device ID**: Creates a unique ID to anonymously associate purchases with users for tracking purposes.
10
- - **Affiliate Identifier Management**: Set and retrieve the affiliate identifier based on user-specific links.
11
- - **In-App Purchase (IAP) Initialisation**: Easily reinitialise in-app purchases with the option to validate using an affiliate identifier.
9
+ ## Table of Contents
12
10
 
13
- ## Getting Started
11
+ - [Quick Start (5 Minutes)](#-quick-start-5-minutes)
12
+ - [Essential Setup](#%EF%B8%8F-essential-setup)
13
+ - [1. Initialize the SDK](#1-initialize-the-sdk)
14
+ - [2. Configure In-App Purchase Verification](#2-configure-in-app-purchase-verification)
15
+ - [3. Set Up Deep Linking](#3-set-up-deep-linking)
16
+ - [Verify Your Integration](#-verify-your-integration)
17
+ - [Advanced Features](#-advanced-features)
18
+ - [Troubleshooting](#-troubleshooting)
19
+ - [Support](#-support)
14
20
 
15
- To get started with the InsertAffiliateReactNative SDK:
21
+ ---
22
+
23
+ ## 🚀 Quick Start (5 Minutes)
24
+
25
+ Get up and running with minimal code to validate the SDK works before tackling IAP and deep linking setup.
16
26
 
17
- 1. [Install the SDK](#installation)
18
- 2. [Set up the provider in Index.js and initialize the SDK in App.tsx](#basic-usage)
19
- 3. [Set up in-app purchases (Required)](#in-app-purchase-setup-required)
20
- 4. [Set up deep linking in Index.js (Required)](#deep-link-setup-required)
27
+ ### Prerequisites
21
28
 
22
- ## Installation
29
+ - **React Native 0.60+**
30
+ - **iOS 13.0+** / **Android API 21+**
31
+ - **Company Code** from your [Insert Affiliate dashboard](https://app.insertaffiliate.com/settings)
23
32
 
24
- To integrate the InsertAffiliateReactNative SDK into your app:
33
+ ### Installation
34
+
35
+ **Step 1:** Install the SDK package
25
36
 
26
- 1. Install the NPM package and its required peer dependencies.
27
37
  ```bash
28
38
  npm install insert-affiliate-react-native-sdk
29
39
  ```
30
40
 
31
- 2. Install the required peer dependencies:
41
+ **Step 2:** Install required peer dependencies
42
+
32
43
  ```bash
33
44
  npm install @react-native-async-storage/async-storage @react-native-clipboard/clipboard @react-native-community/netinfo react-native-device-info axios
34
45
  ```
35
46
 
36
- ### Required Dependencies
37
-
38
- The SDK requires the following peer dependencies to function properly:
47
+ **Step 3:** Install iOS pods (iOS only)
39
48
 
40
- - **`@react-native-async-storage/async-storage`** (>= 1.0.0) - For persistent storage of affiliate identifiers and user data
41
- - **`@react-native-clipboard/clipboard`** (>= 1.16.0) - For clipboard-based affiliate link detection (Insert Links feature)
42
- - **`@react-native-community/netinfo`** (>= 11.4.0) - For network connectivity detection and system information collection
43
- - **`react-native-device-info`** (>= 10.0.0) - For device information and system data collection
44
- - **`axios`** (>= 1.0.0) - For API communication with Insert Affiliate services
45
- - **`react`** (>= 16.0.0) - React framework
46
- - **`react-native`** (>= 0.60.0) - React Native framework
47
-
48
- **Note**: These dependencies must be installed in your app for the SDK to work. If any are missing, you'll get runtime errors when the SDK tries to use them.
49
-
50
- ## Architecture Overview
51
-
52
- The SDK uses a clean, two-file architecture:
53
-
54
- - **`index.js`** (Entry Point): Provider wrapper and deep link handling
55
- - **`App.tsx`** (UI Logic): SDK initialization and your app components
56
-
57
- This separation ensures clean code organization and proper initialization timing.
49
+ ```bash
50
+ cd ios && pod install && cd ..
51
+ ```
58
52
 
59
- ## Basic Usage
53
+ ### Your First Integration
60
54
 
61
- Follow the steps below to install the SDK.
55
+ **In `index.js`** - Wrap your app with the provider:
62
56
 
63
- ### Step 1: Entry Point in `Index.js`
64
57
  ```javascript
65
58
  import React from 'react';
66
- import {AppRegistry} from 'react-native';
59
+ import { AppRegistry } from 'react-native';
67
60
  import App from './App';
68
- import {name as appName} from './app.json';
69
- import {DeepLinkIapProvider} from 'insert-affiliate-react-native-sdk';
61
+ import { name as appName } from './app.json';
62
+ import { DeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
70
63
 
71
64
  const RootComponent = () => {
72
65
  return (
@@ -79,433 +72,411 @@ const RootComponent = () => {
79
72
  AppRegistry.registerComponent(appName, () => RootComponent);
80
73
  ```
81
74
 
82
- #### Step 2: SDK initialization in `App.tsx`
83
-
84
- First, wrap your with our provider and call the `initialize` method early in your app's lifecycle:
75
+ **In `App.tsx`** - Initialize the SDK:
85
76
 
86
77
  ```javascript
87
- const Child = () => {
78
+ import React, { useEffect } from 'react';
79
+ import { View, Text } from 'react-native';
80
+ import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
81
+
82
+ const App = () => {
88
83
  const { initialize, isInitialized } = useDeepLinkIapProvider();
89
84
 
90
85
  useEffect(() => {
91
86
  if (!isInitialized) {
92
- initialize("{{ your-company-code }}");
87
+ initialize(
88
+ "YOUR_COMPANY_CODE", // Get from https://app.insertaffiliate.com/settings
89
+ true // Enable verbose logging for setup
90
+ );
93
91
  }
94
92
  }, [initialize, isInitialized]);
95
- }
96
93
 
97
- const App = () => {
98
- return <Child />;
94
+ return (
95
+ <View>
96
+ <Text>My App</Text>
97
+ </View>
98
+ );
99
99
  };
100
+
101
+ export default App;
100
102
  ```
101
- - Replace `{{ your_company_code }}` with the unique company code associated with your Insert Affiliate account. You can find this code in your dashboard under [Settings](http://app.insertaffiliate.com/settings).
102
103
 
103
- ### Verbose Logging (Optional)
104
+ **Expected Console Output:**
104
105
 
105
- By default, the SDK operates silently to avoid interrupting the user experience. However, you can enable verbose logging to see visual confirmation when affiliate attribution is processed. This is particularly useful for debugging during development or TestFlight testing.
106
+ When the SDK initializes successfully, you'll see:
106
107
 
107
- #### Enable Verbose Logging
108
+ ```
109
+ [Insert Affiliate] SDK initialized with company code: YOUR_COMPANY_CODE
110
+ [Insert Affiliate] [VERBOSE] SDK marked as initialized
111
+ ```
108
112
 
109
- ```javascript
110
- const Child = () => {
111
- const { initialize, isInitialized } = useDeepLinkIapProvider();
113
+ **If you see these logs, the SDK is working!** Now proceed to Essential Setup below.
112
114
 
113
- useEffect(() => {
114
- if (!isInitialized) {
115
- // Enable verbose logging (second parameter)
116
- initialize("{{ your-company-code }}", true);
117
- }
118
- }, [initialize, isInitialized]);
119
- }
120
- ```
115
+ **Important:** Disable verbose logging in production by setting the second parameter to `false`.
116
+
117
+ ---
121
118
 
122
- **When verbose logging is enabled, you'll see detailed logs with the `[Insert Affiliate] [VERBOSE]` prefix that show:**
119
+ ## ⚙️ Essential Setup
123
120
 
124
- - **Initialization Process**: SDK startup, company code validation, AsyncStorage operations
125
- - **Data Management**: User ID generation, referrer link storage, company code state management
126
- - **Deep Link / Insert Link Processing**: Input validation, short code detection, API conversion process
127
- - **API Communication**: Request/response details for all server calls
128
- - **Event Tracking**: Event parameters, payload construction, success/failure status
129
- - **Purchase Operations**: Transaction storage, token validation, webhook processing
121
+ Complete these three required steps to start tracking affiliate-driven purchases.
130
122
 
131
- **Example verbose output:**
123
+ ### 1. Initialize the SDK
124
+
125
+ You've already done basic initialization above. Here are additional options:
126
+
127
+ #### Basic Initialization (Recommended for Getting Started)
128
+
129
+ ```javascript
130
+ initialize("YOUR_COMPANY_CODE", true); // verbose logging enabled
132
131
  ```
133
- [Insert Affiliate] [VERBOSE] Starting SDK initialization...
134
- [Insert Affiliate] [VERBOSE] Company code provided: Yes
135
- [Insert Affiliate] [VERBOSE] Verbose logging enabled
136
- [Insert Affiliate] SDK initialized with company code: your-company-code
137
- [Insert Affiliate] [VERBOSE] Company code saved to AsyncStorage
138
- [Insert Affiliate] [VERBOSE] SDK marked as initialized
139
- [Insert Affiliate] [VERBOSE] Loading stored data from AsyncStorage...
140
- [Insert Affiliate] [VERBOSE] User ID found: Yes
141
- [Insert Affiliate] [VERBOSE] Referrer link found: Yes
142
- [Insert Affiliate] [VERBOSE] Company code found: Yes
132
+
133
+ <details>
134
+ <summary><strong>Advanced Initialization Options</strong> (click to expand)</summary>
135
+
136
+ ```javascript
137
+ initialize(
138
+ "YOUR_COMPANY_CODE",
139
+ true, // verboseLogging - Enable for debugging (disable in production)
140
+ true, // insertLinksEnabled - Enable Insert Links (Insert Affiliate's built-in deep linking)
141
+ true, // insertLinksClipboardEnabled - Enable clipboard attribution (triggers permission prompt)
142
+ 604800 // affiliateAttributionActiveTime - 7 days attribution timeout in seconds
143
+ );
143
144
  ```
144
145
 
145
- **Benefits of verbose logging:**
146
- - **Debug Deep Linking Issues**: See exactly what links are being processed and how they're converted
147
- - **Monitor API Communication**: Track all server requests, responses, and error details
148
- - **Identify Storage Problems**: Understand AsyncStorage read/write operations and state sync
149
- - **Performance Insights**: Monitor async operation timing and identify bottlenecks
150
- - **Integration Troubleshooting**: Quickly identify configuration or setup issues
146
+ **Parameters:**
147
+ - `verboseLogging`: Shows detailed logs for debugging (disable in production)
148
+ - `insertLinksEnabled`: Set to `true` if using Insert Links, `false` if using Branch/AppsFlyer
149
+ - `insertLinksClipboardEnabled`: Enables clipboard-based attribution for Insert Links
150
+ - Improves attribution accuracy when deep linking fails
151
+ - iOS will show a permission prompt: "[Your App] would like to paste from [App Name]"
152
+ - `affiliateAttributionActiveTime`: How long affiliate attribution lasts in seconds (omit for no timeout)
153
+
154
+ </details>
155
+
156
+ ---
151
157
 
152
- ⚠️ **Important**: Disable verbose logging in production builds to avoid exposing sensitive debugging information and to optimize performance.
158
+ ### 2. Configure In-App Purchase Verification
153
159
 
154
- ### Insert Link and Clipboard Control (BETA)
155
- We are currently beta testing our in-house deep linking provider, Insert Links, which generates links for use with your affiliates.
160
+ **Insert Affiliate requires a receipt verification method to validate purchases.** Choose **ONE** of the following:
156
161
 
157
- For larger projects where accuracy is critical, we recommend using established third-party deep linking platforms to generate the links you use within Insert Affiliate - such as Appsflyer or Branch.io, as described in the rest of this README.
162
+ | Method | Best For | Setup Time | Complexity |
163
+ |--------|----------|------------|------------|
164
+ | [**RevenueCat**](#option-1-revenuecat-recommended) | Most developers, managed infrastructure | ~10 min | Simple |
165
+ | [**Adapty**](#option-2-adapty) | Paywall A/B testing, analytics | ~10 min | Simple |
166
+ | [**Iaptic**](#option-3-iaptic) | Custom requirements, direct control | ~15 min | Medium |
167
+ | [**App Store Direct**](#option-4-app-store-direct) | No 3rd party fees (iOS) | ~20 min | Medium |
168
+ | [**Google Play Direct**](#option-5-google-play-direct) | No 3rd party fees (Android) | ~20 min | Medium |
158
169
 
159
- If you encounter any issues while using Insert Links, please raise an issue on this GitHub repository or contact us directly at michael@insertaffiliate.com
170
+ <details open>
171
+ <summary><h4>Option 1: RevenueCat (Recommended)</h4></summary>
160
172
 
161
- #### Initialize with Insert Links
173
+ **Step 1: Code Setup**
162
174
 
163
- When using Insert Affiliate's built-in deep link handling (Insert Links), you can enable these features during initialization:
175
+ Complete the [RevenueCat SDK installation](https://www.revenuecat.com/docs/getting-started/installation/reactnative) first, then add to your `App.tsx`:
164
176
 
165
177
  ```javascript
166
- const Child = () => {
167
- const { initialize, isInitialized } = useDeepLinkIapProvider();
178
+ import React, { useEffect } from 'react';
179
+ import Purchases from 'react-native-purchases';
180
+ import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
181
+
182
+ const App = () => {
183
+ const { initialize, isInitialized, setInsertAffiliateIdentifierChangeCallback } = useDeepLinkIapProvider();
168
184
 
169
185
  useEffect(() => {
170
186
  if (!isInitialized) {
171
- initialize(
172
- "{{ your-company-code }}",
173
- false, // Enable for debugging
174
- true, // Enables Insert Links
175
- true, // Enable Insert Links Clipboard access to avoid permission prompt
176
- 604800 // Optional: Attribution timeout in seconds (7 days)
177
- );
187
+ initialize("YOUR_COMPANY_CODE");
178
188
  }
179
189
  }, [initialize, isInitialized]);
180
- }
190
+
191
+ // Set RevenueCat attribute when affiliate identifier changes
192
+ useEffect(() => {
193
+ setInsertAffiliateIdentifierChangeCallback(async (identifier) => {
194
+ if (identifier) {
195
+ await Purchases.setAttributes({ "insert_affiliate": identifier });
196
+ }
197
+ });
198
+
199
+ return () => setInsertAffiliateIdentifierChangeCallback(null);
200
+ }, [setInsertAffiliateIdentifierChangeCallback]);
201
+
202
+ return <YourAppContent />;
203
+ };
181
204
  ```
182
205
 
183
- **When to use `insertLinksEnabled`:**
184
- - Set to `true` (default: `false`) if you are using Insert Affiliate's built-in deep link and universal link handling (Insert Links)
185
- - Set to `false` if you are using an external provider for deep links
206
+ **Step 2: Webhook Setup**
186
207
 
187
- **When to use `insertLinksClipboardEnabled`:**
188
- - Set to `true` (default: `false`) if you are using Insert Affiliate's built-in deep links (Insert Links) **and** would like to improve the effectiveness of our deep links through the clipboard
189
- - **Important caveat**: This will trigger a system prompt asking the user for permission to access the clipboard when the SDK initializes
208
+ 1. In RevenueCat, [create a new webhook](https://www.revenuecat.com/docs/integrations/webhooks)
209
+ 2. Configure webhook settings:
210
+ - **Webhook URL**: `https://api.insertaffiliate.com/v1/api/revenuecat-webhook`
211
+ - **Event Type**: "All events"
212
+ 3. In your [Insert Affiliate dashboard](https://app.insertaffiliate.com/settings):
213
+ - Set **In-App Purchase Verification** to `RevenueCat`
214
+ - Copy the `RevenueCat Webhook Authentication Header` value
215
+ 4. Back in RevenueCat webhook config:
216
+ - Paste the authentication header value into the **Authorization header** field
190
217
 
218
+ **RevenueCat setup complete!** Now skip to [Step 3: Set Up Deep Linking](#3-set-up-deep-linking)
191
219
 
192
- ## In-App Purchase Setup [Required]
193
- Insert Affiliate requires a Receipt Verification platform to validate in-app purchases. You must choose **one** of our supported partners:
194
- - [RevenueCat](https://www.revenuecat.com/)
195
- - [Iaptic](https://www.iaptic.com/account)
196
- - [App Store Direct Integration](#option-3-app-store-direct-integration)
197
- - [Google Play Store Direct Integration](#option-4-google-play-store-direct-integration)
220
+ </details>
198
221
 
199
- ### Option 1: RevenueCat Integration
200
- #### Step 1. Code Setup
201
- First, complete the [RevenueCat SDK installation](https://www.revenuecat.com/docs/getting-started/installation/reactnative). Then modify your `App.tsx`:
222
+ <details>
223
+ <summary><h4>Option 2: Adapty</h4></summary>
202
224
 
203
- ```javascript
204
- import React, {useEffect} from 'react';
205
- import {AppRegistry} from 'react-native';
206
- import App from './App';
207
- import {name as appName} from './app.json';
208
- import {useDeepLinkIapProvider, DeepLinkIapProvider} from 'insert-affiliate-react-native-sdk';
209
-
210
- // ... //
211
- const {
212
- initialize,
213
- isInitialized,
214
- returnInsertAffiliateIdentifier
215
- } = useDeepLinkIapProvider();
216
-
217
- React.useEffect(() => {
218
- const handleAffiliateLogin = async () => {
219
- try {
220
- if (isInitialized) {
221
- const affiliateIdentifier = await returnInsertAffiliateIdentifier();
222
-
223
- if (affiliateIdentifier) {
224
- await Purchases.setAttributes({"insert_affiliate" : affiliateIdentifier});
225
- }
226
- }
227
- } catch (error) {
228
- console.error('Error during affiliate login flow:', error);
229
- }
230
- };
225
+ **Step 1: Install Adapty SDK**
231
226
 
232
- handleAffiliateLogin();
233
- }, [isInitialized, returnInsertAffiliateIdentifier]);
234
- // ... //
227
+ ```bash
228
+ npm install react-native-adapty
229
+ cd ios && pod install && cd ..
235
230
  ```
236
231
 
237
- #### Step 2. Webhook Setup
232
+ Complete the [Adapty SDK installation](https://adapty.io/docs/sdk-installation-reactnative) for any additional platform-specific setup.
238
233
 
239
- 1. Go to RevenueCat and [create a new webhook](https://www.revenuecat.com/docs/integrations/webhooks)
234
+ **Step 2: Code Setup**
240
235
 
241
- 2. Configure the webhook with these settings:
242
- - Webhook URL: `https://api.insertaffiliate.com/v1/api/revenuecat-webhook`
243
- - Authorization header: Use the value from your Insert Affiliate dashboard (you'll get this in step 4)
244
- - Set "Event Type" to "All events"
236
+ ```javascript
237
+ import React, { useEffect } from 'react';
238
+ import { adapty } from 'react-native-adapty';
239
+ import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
245
240
 
246
- 3. In your [Insert Affiliate dashboard settings](https://app.insertaffiliate.com/settings):
247
- - Navigate to the verification settings
248
- - Set the in-app purchase verification method to `RevenueCat`
241
+ const ADAPTY_PUBLIC_SDK_KEY = 'YOUR_ADAPTY_PUBLIC_SDK_KEY'; // From https://app.adapty.io/
249
242
 
250
- 4. Back in your Insert Affiliate dashboard:
251
- - Locate the `RevenueCat Webhook Authentication Header` value
252
- - Copy this value
253
- - Paste it as the Authorization header value in your RevenueCat webhook configuration
243
+ const App = () => {
244
+ const { initialize, isInitialized, setInsertAffiliateIdentifierChangeCallback } = useDeepLinkIapProvider();
254
245
 
246
+ // Initialize both SDKs
247
+ useEffect(() => {
248
+ const initSDKs = async () => {
249
+ // Initialize Adapty
250
+ await adapty.activate(ADAPTY_PUBLIC_SDK_KEY);
255
251
 
256
- ### Option 2: Iaptic Integration
257
- #### 1. Code Setup
258
- First, complete the [Iaptic account setup](https://www.iaptic.com/signup) and code integration.
252
+ // Initialize Insert Affiliate
253
+ if (!isInitialized) {
254
+ initialize("YOUR_COMPANY_CODE");
255
+ }
256
+ };
257
+ initSDKs();
258
+ }, [initialize, isInitialized]);
259
259
 
260
- Then after setting up the in app purchase (IAP) with Iaptic, call Insert Affiliate's ```validatePurchaseWithIapticAPI``` on purchase.
260
+ // Set Adapty attribute when affiliate identifier changes
261
+ useEffect(() => {
262
+ setInsertAffiliateIdentifierChangeCallback(async (identifier) => {
263
+ if (identifier) {
264
+ await adapty.updateProfile({
265
+ codableCustomAttributes: {
266
+ insert_affiliate: identifier,
267
+ },
268
+ });
269
+ }
270
+ });
261
271
 
262
- ```javascript
263
- import React from 'react';
264
- import { ActivityIndicator, Button, StyleSheet, Text, View } from 'react-native';
265
- import { DeepLinkIapProvider, useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
266
- import { useIAP, requestSubscription, withIAPContext, getProducts, getSubscriptions, initConnection } from "react-native-iap";
267
-
268
- const Child = () => {
269
- const {
270
- initialize,
271
- isInitialized,
272
- validatePurchaseWithIapticAPI,
273
- } = useDeepLinkIapProvider();
274
-
275
- const [iapLoading, setIapLoading] = useState(false);
276
- const { currentPurchase, connected } = useIAP();
277
-
278
- // ***...***
279
- // Fetch & Load your subscription/purchases and handling the IAP purchase here as per the Iaptic Documentation...
280
- // ***...***
281
-
282
- // Initialize the Insert Affiliate SDK at the earliest possible moment
283
- useEffect(() => {
284
- if (!isInitialized) {
285
- initialize("{{ your_company_code }}");
286
- }
287
- }, [initialize, isInitialized]);
288
-
289
- // Validate the purchase with Iaptic through Insert Affiliate's SDK for Affiliate Tracking
290
- useEffect(() => {
291
- if (currentPurchase) {
292
- validatePurchaseWithIapticAPI(
293
- currentPurchase,
294
- '{{ your_iaptic_app_id }}',
295
- '{{ your_iaptic_app_name }}',
296
- '{{ your_iaptic_public_key }}',
297
- ).then((isValid: boolean) => {
298
- if (isValid) {
299
- console.log("Purchase validated successfully.");
300
- } else {
301
- console.error("Purchase validation failed.");
302
- }
303
- });
304
- }
305
- }, [currentPurchase, handlePurchaseValidation]);
306
-
307
- return (
308
- <View>
309
- <Button
310
- disabled={iapLoading}
311
- title={`Click to Buy Subscription`}
312
- onPress={() => handleBuySubscription("oneMonthSubscription")}
313
- />
314
- {iapLoading && <ActivityIndicator size={"small"} color={"black"} />}
315
- </View>
316
- );
317
- };
272
+ return () => setInsertAffiliateIdentifierChangeCallback(null);
273
+ }, [setInsertAffiliateIdentifierChangeCallback]);
318
274
 
319
- const App = () => {
320
- return (
321
- <Child />
322
- );
275
+ return <YourAppContent />;
323
276
  };
324
-
325
- export default App;
326
277
  ```
327
- - Replace `{{ your_iaptic_app_id }}` with your **Iaptic App ID**. You can find this [here](https://www.iaptic.com/account).
328
- - Replace `{{ your_iaptic_app_name }}` with your **Iaptic App Name**. You can find this [here](https://www.iaptic.com/account).
329
- - Replace `{{ your_iaptic_public_key }}` with your **Iaptic Public Key**. You can find this [here](https://www.iaptic.com/settings).
330
- - Replace `{{ your_company_code }}` with the unique company code associated with your Insert Affiliate account. You can find this code in your dashboard under [Settings](http://app.insertaffiliate.com/settings).
331
278
 
332
- #### 2. Webhook Setup
333
- 1. Open the [Insert Affiliate settings](https://app.insertaffiliate.com/settings):
334
- - Navigate to the Verification Settings section
335
- - Set the In-App Purchase Verification method to `Iaptic`
336
- - Copy the `Iaptic Webhook URL` and the `Iaptic Webhook Sandbox URL`- you'll need it in the next step.
337
- 2. Go to the [Iaptic Settings](https://www.iaptic.com/settings)
338
- - Paste the copied `Iaptic Webhook URL` into the `Webhook URL` field
339
- - Paste the copied `Iaptic Webhook Sandbox URL` into the `Sandbox Webhook URL` field
340
- - Click **Save Settings**.
341
- 3. Check that you have completed the [Iaptic setup for the App Store Server Notifications](https://www.iaptic.com/documentation/setup/ios-subscription-status-url)
342
- 4. Check that you have completed the [Iaptic setup for the Google Play Notifications URL](https://www.iaptic.com/documentation/setup/connect-with-google-publisher-api)
279
+ **Step 3: Webhook Setup**
343
280
 
344
- ### Option 3: App Store Direct Integration
281
+ 1. In your [Insert Affiliate dashboard](https://app.insertaffiliate.com/settings):
282
+ - Set **In-App Purchase Verification** to `Adapty`
283
+ - Copy the **Adapty Webhook URL**
284
+ - Copy the **Adapty Webhook Authorization Header** value
345
285
 
346
- Our direct App Store integration is currently in beta and currently supports subscriptions only. **Consumables and one-off purchases are not yet supported** due to App Store server-to-server notification limitations.
286
+ 2. In the [Adapty Dashboard](https://app.adapty.io/integrations):
287
+ - Navigate to **Integrations** → **Webhooks**
288
+ - Set **Production URL** to the webhook URL from Insert Affiliate
289
+ - Set **Sandbox URL** to the same webhook URL
290
+ - Paste the authorization header value into **Authorization header value**
291
+ - Enable these options:
292
+ - **Exclude historical events**
293
+ - **Send attribution**
294
+ - **Send trial price**
295
+ - **Send user attributes**
296
+ - Save the configuration
347
297
 
348
- We plan to release support for consumables and one-off purchases soon. In the meantime, you can use a receipt verification platform from the other integration options.
298
+ **Step 4: Verify Integration**
349
299
 
350
- #### Apple App Store Notification Setup
351
- To proceed, visit [our docs](https://docs.insertaffiliate.com/direct-store-purchase-integration#1-apple-app-store-server-notifications) and complete the required setup steps to set up App Store Server to Server Notifications.
300
+ To confirm the affiliate identifier is set correctly:
301
+ 1. Go to [app.adapty.io/profiles/users](https://app.adapty.io/profiles/users)
302
+ 2. Find the test user who made a purchase
303
+ 3. Look for `insert_affiliate` in **Custom attributes** with format: `{SHORT_CODE}-{UUID}`
352
304
 
353
- #### Implementing Purchases
305
+ **Adapty setup complete!** Now skip to [Step 3: Set Up Deep Linking](#3-set-up-deep-linking)
354
306
 
355
- ##### 1. Import Required Modules
307
+ </details>
356
308
 
357
- Ensure you import the necessary dependencies, including `Platform` and `useDeepLinkIapProvider` from the SDK.
309
+ <details>
310
+ <summary><h4>Option 3: Iaptic</h4></summary>
358
311
 
359
- ```javascript
360
- import { Platform } from 'react-native';
361
- import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
362
- import { requestSubscription } from 'react-native-iap';
312
+ **Step 1: Code Setup**
363
313
 
364
- const { returnUserAccountTokenAndStoreExpectedTransaction } = useDeepLinkIapProvider();
365
- ```
314
+ Complete the [Iaptic account setup](https://www.iaptic.com/signup) first, then add to your component:
366
315
 
316
+ ```javascript
317
+ import React, { useEffect, useState } from 'react';
318
+ import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
319
+ import { useIAP } from 'react-native-iap';
367
320
 
368
- ##### 2. Handle the Purchase
369
- When a user initiates a subscription, retrieve the appAccountToken and pass it to the requestSubscription call:
321
+ const App = () => {
322
+ const { initialize, isInitialized, validatePurchaseWithIapticAPI } = useDeepLinkIapProvider();
323
+ const { currentPurchase } = useIAP();
370
324
 
371
- ```javascript
372
- const handleBuySubscription = async (product: SubscriptionAndroid | Subscription) => {
373
- try {
374
- let appAccountToken = null;
375
-
376
- // Step 1: Retrieve the appAccountToken for iOS
377
- if (Platform.OS === 'ios') {
378
- appAccountToken = await returnUserAccountTokenAndStoreExpectedTransaction();
379
- }
380
-
381
- // Step 2: Request the subscription and pass the token for tracking
382
- await requestSubscription({
383
- sku: product?.productId,
384
- ...(appAccountToken ? { applicationUsername: appAccountToken } : {}),
385
- });
325
+ useEffect(() => {
326
+ if (!isInitialized) {
327
+ initialize("YOUR_COMPANY_CODE");
328
+ }
329
+ }, [initialize, isInitialized]);
386
330
 
387
- } catch (error) {
388
- console.error("Error processing subscription:", error);
331
+ // Validate purchases with Iaptic
332
+ useEffect(() => {
333
+ if (currentPurchase) {
334
+ validatePurchaseWithIapticAPI(
335
+ currentPurchase,
336
+ 'YOUR_IAPTIC_APP_ID',
337
+ 'YOUR_IAPTIC_APP_NAME',
338
+ 'YOUR_IAPTIC_PUBLIC_KEY'
339
+ ).then((isValid) => {
340
+ console.log(isValid ? "Purchase validated" : "Validation failed");
341
+ });
389
342
  }
390
- };
343
+ }, [currentPurchase]);
391
344
 
345
+ return <YourAppContent />;
346
+ };
392
347
  ```
393
348
 
349
+ Replace:
350
+ - `YOUR_IAPTIC_APP_ID` with your [Iaptic App ID](https://www.iaptic.com/account)
351
+ - `YOUR_IAPTIC_APP_NAME` with your [Iaptic App Name](https://www.iaptic.com/account)
352
+ - `YOUR_IAPTIC_PUBLIC_KEY` with your [Iaptic Public Key](https://www.iaptic.com/settings)
353
+
354
+ **Step 2: Webhook Setup**
355
+
356
+ 1. Open [Insert Affiliate settings](https://app.insertaffiliate.com/settings):
357
+ - Set the In-App Purchase Verification method to `Iaptic`
358
+ - Copy the `Iaptic Webhook URL` and `Iaptic Webhook Sandbox URL`
359
+ 2. Go to [Iaptic Settings](https://www.iaptic.com/settings):
360
+ - Paste the Webhook URLs into the corresponding fields
361
+ - Click **Save Settings**
362
+ 3. Complete the [Iaptic App Store Server Notifications setup](https://www.iaptic.com/documentation/setup/ios-subscription-status-url)
363
+ 4. Complete the [Iaptic Google Play Notifications setup](https://www.iaptic.com/documentation/setup/connect-with-google-publisher-api)
394
364
 
395
- ### Option 4: Google Play Store Direct Integration
396
- Our direct Google Play Store integration is currently in beta.
365
+ **Iaptic setup complete!** Now proceed to [Step 3: Set Up Deep Linking](#3-set-up-deep-linking)
397
366
 
398
- #### Real Time Developer Notifications (RTDN) Setup
367
+ </details>
399
368
 
400
- Visit [our docs](https://docs.insertaffiliate.com/direct-google-play-store-purchase-integration) and complete the required set up steps for Google Play's Real Time Developer Notifications.
369
+ <details>
370
+ <summary><h4>Option 4: App Store Direct</h4></summary>
401
371
 
402
- #### Implementing Purchases
372
+ **Step 1: Apple App Store Notification Setup**
403
373
 
404
- ##### 1. Import Required Modules
374
+ Visit [our docs](https://docs.insertaffiliate.com/direct-store-purchase-integration#1-apple-app-store-server-notifications) and complete the required App Store Server to Server Notifications setup.
405
375
 
406
- Ensure you import the necessary dependencies, including `Platform` and `useDeepLinkIapProvider` from the SDK.
376
+ **Step 2: Implementing Purchases**
407
377
 
408
378
  ```javascript
409
- import React, {useEffect, useState} from 'react';
410
379
  import { Platform } from 'react-native';
411
- import { DeepLinkIapProvider, useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
412
- import { currentPurchase, requestSubscription } from 'react-native-iap';
413
-
414
- const { storeExpectedStoreTransaction } = useDeepLinkIapProvider();
380
+ import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
381
+ import { requestSubscription } from 'react-native-iap';
415
382
 
416
- useEffect(() => {
417
- if (currentPurchase) {
418
- if (Platform.OS === 'android' && currentPurchase.purchaseToken) {
419
- // Step 1: Store the expected transaction for Google Play purchases
420
- storeExpectedStoreTransaction(
421
- currentPurchase.purchaseToken
422
- );
423
- }
424
- }
425
- }, [currentPurchase, storeExpectedStoreTransaction]);
426
- ```
383
+ const { returnUserAccountTokenAndStoreExpectedTransaction } = useDeepLinkIapProvider();
427
384
 
385
+ const handleBuySubscription = async (product) => {
386
+ try {
387
+ let appAccountToken = null;
428
388
 
389
+ if (Platform.OS === 'ios') {
390
+ appAccountToken = await returnUserAccountTokenAndStoreExpectedTransaction();
391
+ }
429
392
 
430
- ## Deep Link Setup [Required]
393
+ await requestSubscription({
394
+ sku: product.productId,
395
+ ...(appAccountToken ? { applicationUsername: appAccountToken } : {}),
396
+ });
397
+ } catch (error) {
398
+ console.error("Error processing subscription:", error);
399
+ }
400
+ };
401
+ ```
431
402
 
432
- Insert Affiliate requires a Deep Linking platform to create links for your affiliates. Our platform works with **any** deep linking provider. Below are examples for popular providers including Branch.io and AppsFlyer:
433
- 1. **Create a deep link** in your chosen third-party platform and pass it to our dashboard when an affiliate signs up.
434
- 2. **Handle deep link clicks** in your app by passing the clicked link:
435
- ```javascript
436
- await setInsertAffiliateIdentifier(referringLink)
437
- ```
438
- 3. **Integrate with a Receipt Verification platform** by using the result from `setInsertAffiliateIdentifier` to log in or set your application’s username. Examples below include [**Iaptic**](https://github.com/Insert-Affiliate/InsertAffiliateReactNativeSDK?tab=readme-ov-file#example-with-iaptic) and [**RevenueCat**](https://github.com/Insert-Affiliate/InsertAffiliateReactNativeSDK?tab=readme-ov-file#example-with-revenuecat)
403
+ **App Store Direct setup complete!** Now proceed to [Step 3: Set Up Deep Linking](#3-set-up-deep-linking)
439
404
 
405
+ </details>
440
406
 
407
+ <details>
408
+ <summary><h4>Option 5: Google Play Direct</h4></summary>
441
409
 
442
- ### Deep Linking with Insert Links
410
+ **Step 1: RTDN Setup**
443
411
 
444
- Insert Links by Insert Affiliate supports deferred deep linking into your app. This allows you to track affiliate attribution when end users are referred to your app by clicking on one of your affiliates Insert Links.
412
+ Visit [our docs](https://docs.insertaffiliate.com/direct-google-play-store-purchase-integration) and complete the required Real Time Developer Notifications setup.
445
413
 
446
- #### Initial Setup
414
+ **Step 2: Implementing Purchases**
447
415
 
448
- 1. Before you can use Insert Links, you must complete the setup steps in [our docs](https://docs.insertaffiliate.com/insert-links)
416
+ ```javascript
417
+ import React, { useEffect } from 'react';
418
+ import { Platform } from 'react-native';
419
+ import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
420
+ import { useIAP } from 'react-native-iap';
449
421
 
450
- 2. **Initialization** of the Insert Affiliate SDK with Insert Links
422
+ const App = () => {
423
+ const { storeExpectedStoreTransaction } = useDeepLinkIapProvider();
424
+ const { currentPurchase } = useIAP();
451
425
 
452
- You must enable *insertLinksEnabled* when [initialising our SDK](https://github.com/Insert-Affiliate/InsertAffiliateReactNativeSDK?tab=readme-ov-file#initialize-with-insert-links)
426
+ useEffect(() => {
427
+ if (currentPurchase && Platform.OS === 'android' && currentPurchase.purchaseToken) {
428
+ storeExpectedStoreTransaction(currentPurchase.purchaseToken);
429
+ }
430
+ }, [currentPurchase, storeExpectedStoreTransaction]);
453
431
 
454
- **Handle Insert Links** in your React Native app
432
+ return <YourAppContent />;
433
+ };
434
+ ```
455
435
 
456
- The React Native SDK handles deep links in ALL scenarios:
436
+ **Google Play Direct setup complete!** Now proceed to [Step 3: Set Up Deep Linking](#3-set-up-deep-linking)
457
437
 
458
- - **App Not Running (Cold Start)**: When user clicks a deep link and app is not running, the app launches and processes the URL
459
- - **App Running (Warm Start)**: When user clicks a deep link while app is already running, processes the URL immediately
460
- - **App Backgrounded**: When user clicks a deep link while app is backgrounded, brings app to foreground and processes the URL
461
- - **Automatic Processing**: Parses Insert Link URLs and sets affiliate identifiers without additional code
438
+ </details>
462
439
 
463
- 3. **Platform Specific** Setup
440
+ ---
464
441
 
465
- ##### iOS Additional Setup (required)
442
+ ### 3. Set Up Deep Linking
466
443
 
467
- To enable deep linking and universal links on iOS, you need to configure your app's Info.plist and AppDelegate files.
444
+ **Deep linking lets affiliates share unique links that track users to your app.** Choose **ONE** deep linking provider:
468
445
 
469
- **AppDelegate Setup**
446
+ | Provider | Best For | Complexity | Setup Guide |
447
+ |----------|----------|------------|-------------|
448
+ | [**Insert Links**](#option-1-insert-links-simplest) | Simple setup, no 3rd party | Simple | [View](#option-1-insert-links-simplest) |
449
+ | [**Branch.io**](#option-2-branchio) | Robust attribution, deferred deep linking | Medium | [View](#option-2-branchio) |
450
+ | [**AppsFlyer**](#option-3-appsflyer) | Enterprise analytics, comprehensive attribution | Medium | [View](#option-3-appsflyer) |
470
451
 
471
- Update your `ios/YourApp/AppDelegate.mm` (or `AppDelegate.m`) file:
452
+ <details open>
453
+ <summary><h4>Option 1: Insert Links (Simplest)</h4></summary>
472
454
 
473
- ```objc
474
- #import <React/RCTLinkingManager.h>
455
+ Insert Links is Insert Affiliate's built-in deep linking solution - no third-party SDK required.
475
456
 
476
- // Handle URL opening when app is already running (iOS 9+)
477
- - (BOOL)application:(UIApplication *)application
478
- openURL:(NSURL *)url
479
- options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
480
- {
481
- return [RCTLinkingManager application:application openURL:url options:options];
482
- }
457
+ **Prerequisites:**
458
+ - Complete the [Insert Links setup](https://docs.insertaffiliate.com/insert-links) in the Insert Affiliate dashboard
483
459
 
484
- // Handle URL opening (iOS 8 and below - for backward compatibility)
485
- - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
486
- sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
487
- {
488
- return [RCTLinkingManager application:application openURL:url
489
- sourceApplication:sourceApplication annotation:annotation];
490
- }
460
+ **Step 1: Initialize with Insert Links enabled**
491
461
 
492
- // Handle universal links (iOS 9+)
493
- - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
494
- restorationHandler:(void(^)(NSArray * __nullable restorableObjects))restorationHandler
495
- {
496
- return [RCTLinkingManager application:application
497
- continueUserActivity:userActivity
498
- restorationHandler:restorationHandler];
499
- }
462
+ ```javascript
463
+ useEffect(() => {
464
+ if (!isInitialized) {
465
+ initialize(
466
+ "YOUR_COMPANY_CODE",
467
+ true, // verboseLogging
468
+ true, // insertLinksEnabled
469
+ false // insertLinksClipboardEnabled (set true for better attribution, triggers permission)
470
+ );
471
+ }
472
+ }, [initialize, isInitialized]);
500
473
  ```
501
474
 
502
- 4. **Receipt Verification Integration Examples when Using Insert Links**
503
-
504
- The SDK provides a callback mechanism that triggers whenever the affiliate identifier changes. This is perfect for integrating with receipt verification platforms.
475
+ **Step 2: Set up the identifier change callback**
505
476
 
506
- ##### With RevenueCat
477
+ Choose the example that matches your IAP verification platform:
507
478
 
508
- Set up the callback to automatically update RevenueCat when the affiliate identifier changes:
479
+ **With RevenueCat:**
509
480
 
510
481
  ```javascript
511
482
  import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
@@ -515,29 +486,24 @@ const App = () => {
515
486
  const { setInsertAffiliateIdentifierChangeCallback } = useDeepLinkIapProvider();
516
487
 
517
488
  useEffect(() => {
518
- // Set up callback to handle affiliate identifier changes
519
489
  setInsertAffiliateIdentifierChangeCallback(async (identifier) => {
520
490
  if (identifier) {
521
- // Update RevenueCat with the affiliate identifier
522
- await Purchases.setAttributes({"insert_affiliate": identifier});
491
+ await Purchases.setAttributes({ "insert_affiliate": identifier });
523
492
  }
524
493
  });
525
494
 
526
- // Cleanup on unmount
527
- return () => {
528
- setInsertAffiliateIdentifierChangeCallback(null);
529
- };
495
+ return () => setInsertAffiliateIdentifierChangeCallback(null);
530
496
  }, []);
531
497
 
532
498
  return <YourAppContent />;
533
499
  };
534
500
  ```
535
501
 
536
- ##### With Apphud
502
+ **With Adapty:**
537
503
 
538
504
  ```javascript
539
505
  import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
540
- import Apphud from 'react-native-apphud';
506
+ import { adapty } from 'react-native-adapty';
541
507
 
542
508
  const App = () => {
543
509
  const { setInsertAffiliateIdentifierChangeCallback } = useDeepLinkIapProvider();
@@ -545,25 +511,26 @@ const App = () => {
545
511
  useEffect(() => {
546
512
  setInsertAffiliateIdentifierChangeCallback(async (identifier) => {
547
513
  if (identifier) {
548
- // Update Apphud with the affiliate identifier
549
- await Apphud.setUserProperty("insert_affiliate", identifier, false);
514
+ await adapty.updateProfile({
515
+ codableCustomAttributes: {
516
+ insert_affiliate: identifier,
517
+ },
518
+ });
550
519
  }
551
520
  });
552
521
 
553
- return () => {
554
- setInsertAffiliateIdentifierChangeCallback(null);
555
- };
522
+ return () => setInsertAffiliateIdentifierChangeCallback(null);
556
523
  }, []);
557
524
 
558
525
  return <YourAppContent />;
559
526
  };
560
527
  ```
561
528
 
562
- ##### With Iaptic
529
+ **With Apphud:**
563
530
 
564
531
  ```javascript
565
532
  import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
566
- import InAppPurchase from 'react-native-iaptic';
533
+ import Apphud from 'react-native-apphud';
567
534
 
568
535
  const App = () => {
569
536
  const { setInsertAffiliateIdentifierChangeCallback } = useDeepLinkIapProvider();
@@ -571,741 +538,392 @@ const App = () => {
571
538
  useEffect(() => {
572
539
  setInsertAffiliateIdentifierChangeCallback(async (identifier) => {
573
540
  if (identifier) {
574
- // Initialize Iaptic with the affiliate identifier
575
- await InAppPurchase.initialize({
576
- iapProducts: iapProductsArray,
577
- validatorUrlString: "https://validator.iaptic.com/v3/validate?appName={{ your_iaptic_app_name }}&apiKey={{ your_iaptic_app_key_goes_here }}",
578
- applicationUsername: identifier
579
- });
541
+ await Apphud.setUserProperty("insert_affiliate", identifier, false);
580
542
  }
581
543
  });
582
544
 
583
- return () => {
584
- setInsertAffiliateIdentifierChangeCallback(null);
585
- };
545
+ return () => setInsertAffiliateIdentifierChangeCallback(null);
586
546
  }, []);
587
547
 
588
548
  return <YourAppContent />;
589
549
  };
590
550
  ```
591
551
 
552
+ **With Iaptic:**
592
553
 
593
- ### Deep Linking with Branch.io
594
- To set up deep linking with Branch.io, follow these steps:
595
-
596
- 1. Create a deep link in Branch and pass it to our dashboard when an affiliate signs up.
597
- - Example: [Create Affiliate](https://docs.insertaffiliate.com/create-affiliate).
598
- 2. Modify Your Deep Link Handling in `Index.js`
599
- - After setting up your Branch integration, add the following code to your app:
600
-
601
-
602
- #### Example with RevenueCat
603
554
  ```javascript
604
- import {useDeepLinkIapProvider, DeepLinkIapProvider} from 'insert-affiliate-react-native-sdk';
605
-
606
- //...
607
- const DeepLinkHandler = () => {
608
- const {setInsertAffiliateIdentifier} = useDeepLinkIapProvider();
609
-
610
- useEffect(() => {
611
- const branchSubscription = branch.subscribe(async ({error, params}) => {
612
- if (error) {
613
- console.error('Error from Branch:', error);
614
- return;
615
- }
616
-
617
- if (params['+clicked_branch_link']) {
618
- const referringLink = params['~referring_link'];
619
- if (referringLink) {
620
- try {
621
- let insertAffiliateIdentifier = await setInsertAffiliateIdentifier(referringLink);
622
-
623
- if (insertAffiliateIdentifier) {
624
- await Purchases.setAttributes({"insert_affiliate" : insertAffiliateIdentifier});
625
- }
626
-
627
- } catch (err) {
628
- console.error('Error setting affiliate identifier:', err);
629
- }
630
- }
631
- }
632
- });
633
-
634
- return () => {
635
- branchSubscription();
636
- };
637
- }, [setInsertAffiliateIdentifier]);
638
-
639
- return <App />;
640
- };
641
-
642
- const RootComponent = () => {
643
- return (
644
- <DeepLinkIapProvider>
645
- <DeepLinkHandler />
646
- </DeepLinkIapProvider>
647
- );
648
- };
649
-
650
- AppRegistry.registerComponent(appName, () => RootComponent);
651
-
652
- //...
653
- ```
555
+ import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
556
+ import InAppPurchase from 'react-native-iaptic';
654
557
 
655
- #### Example with Iaptic / App Store Direct Integration / Google Play Direct Integration
656
- ```javascript
657
- import branch from 'react-native-branch';
658
- import {useDeepLinkIapProvider, DeepLinkIapProvider} from 'insert-affiliate-react-native-sdk';
659
-
660
- const DeepLinkHandler = () => {
661
- const {setInsertAffiliateIdentifier} = useDeepLinkIapProvider();
662
-
663
- React.useEffect(() => {
664
- const branchSubscription = branch.subscribe(async ({error, params}) => {
665
- if (error) {
666
- console.error('Error from Branch:', error);
667
- return;
668
- }
558
+ const App = () => {
559
+ const { setInsertAffiliateIdentifierChangeCallback } = useDeepLinkIapProvider();
669
560
 
670
- if (params['+clicked_branch_link']) {
671
- const referringLink = params['~referring_link'];
672
- if (referringLink) {
673
- try {
674
- await setInsertAffiliateIdentifier(referringLink);
675
- console.log('Affiliate identifier set successfully.');
676
- } catch (err) {
677
- console.error('Error setting affiliate identifier:', err);
678
- }
679
- }
561
+ useEffect(() => {
562
+ setInsertAffiliateIdentifierChangeCallback(async (identifier) => {
563
+ if (identifier) {
564
+ InAppPurchase.stop();
565
+ InAppPurchase.initialize({
566
+ iapProducts: iapProductsArray,
567
+ validatorUrlString: "https://validator.iaptic.com/v3/validate?appName=YOUR_APP_NAME&apiKey=YOUR_API_KEY",
568
+ applicationUsername: identifier
569
+ });
680
570
  }
681
571
  });
682
572
 
683
- return () => branchSubscription();
684
- }, [setInsertAffiliateIdentifier]);
685
-
686
- return <App />;
687
- };
573
+ return () => setInsertAffiliateIdentifierChangeCallback(null);
574
+ }, []);
688
575
 
689
- const RootComponent = () => {
690
- return (
691
- <DeepLinkIapProvider>
692
- <DeepLinkHandler />
693
- </DeepLinkIapProvider>
694
- );
576
+ return <YourAppContent />;
695
577
  };
696
578
  ```
697
579
 
698
- ### Deep Linking with AppsFlyer
699
- To set up deep linking with AppsFlyer, follow these steps:
700
-
701
- 1. Create a [OneLink](https://support.appsflyer.com/hc/en-us/articles/208874366-Create-a-OneLink-link-for-your-campaigns) in AppsFlyer and pass it to our dashboard when an affiliate signs up.
702
- - Example: [Create Affiliate](https://docs.insertaffiliate.com/create-affiliate).
703
- 2. Initialize AppsFlyer SDK and set up deep link handling in your app.
704
-
705
- #### Platform Setup
706
- Complete the deep linking setup for AppsFlyer by following their official documentation:
707
- - [AppsFlyer Deferred Deep Link Integration Guide](https://dev.appsflyer.com/hc/docs/deeplinkintegrate)
708
-
709
- This covers all platform-specific configurations including:
710
- - iOS: Info.plist configuration, AppDelegate setup, and universal links
711
- - Android: AndroidManifest.xml intent filters, MainActivity setup, and App Links
712
- - Testing and troubleshooting for both platforms
713
-
714
- #### Example with RevenueCat
580
+ **With App Store / Google Play Direct:**
715
581
 
716
582
  ```javascript
717
- import React, { useEffect } from 'react';
718
- import { Platform } from 'react-native';
719
- import appsFlyer from 'react-native-appsflyer';
720
- import { useDeepLinkIapProvider, DeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
721
- import Purchases from 'react-native-purchases';
583
+ import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
722
584
 
723
- const DeepLinkHandler = () => {
724
- const { setInsertAffiliateIdentifier, isInitialized } = useDeepLinkIapProvider();
585
+ const App = () => {
586
+ const { setInsertAffiliateIdentifierChangeCallback } = useDeepLinkIapProvider();
725
587
 
726
588
  useEffect(() => {
727
- if (!isInitialized) return;
728
-
729
- // Initialize AppsFlyer
730
- const initAppsFlyer = async () => {
731
- try {
732
- const initOptions = {
733
- devKey: 'your-appsflyer-dev-key',
734
- isDebug: true,
735
- appId: Platform.OS === 'ios' ? 'your-ios-app-id' : 'your-android-package-name',
736
- };
737
-
738
- await appsFlyer.initSdk(initOptions);
739
- } catch (error) {
740
- console.error('AppsFlyer initialization error:', error);
741
- }
742
- };
743
-
744
- // Handle deep link data
745
- const handleDeepLink = async (deepLinkData) => {
746
- if (deepLinkData && deepLinkData.data) {
747
- let referringLink = deepLinkData.data.link || deepLinkData.data.deep_link_value;
748
-
749
- if (referringLink) {
750
- try {
751
- let insertAffiliateIdentifier = await setInsertAffiliateIdentifier(referringLink);
752
-
753
- if (insertAffiliateIdentifier) {
754
- await Purchases.setAttributes({"insert_affiliate": insertAffiliateIdentifier});
755
- }
756
- } catch (err) {
757
- console.error('Error setting affiliate identifier:', err);
758
- }
759
- }
589
+ setInsertAffiliateIdentifierChangeCallback(async (identifier) => {
590
+ if (identifier) {
591
+ console.log('Affiliate identifier stored:', identifier);
592
+ // Identifier is stored automatically for direct store integration
760
593
  }
761
- };
762
-
763
- // Listen for both deep link types
764
- appsFlyer.onDeepLink(handleDeepLink);
765
- appsFlyer.onAppOpenAttribution(handleDeepLink);
766
-
767
- initAppsFlyer();
768
- }, [setInsertAffiliateIdentifier, isInitialized]);
594
+ });
769
595
 
770
- return <App />;
771
- };
596
+ return () => setInsertAffiliateIdentifierChangeCallback(null);
597
+ }, []);
772
598
 
773
- const RootComponent = () => {
774
- return (
775
- <DeepLinkIapProvider>
776
- <DeepLinkHandler />
777
- </DeepLinkIapProvider>
778
- );
599
+ return <YourAppContent />;
779
600
  };
780
-
781
- AppRegistry.registerComponent(appName, () => RootComponent);
782
601
  ```
783
602
 
784
- #### Example with Iaptic / App Store Direct Integration / Google Play Direct Integration
603
+ **Step 3: iOS Native Setup (Required)**
785
604
 
786
- ```javascript
787
- import React, { useEffect } from 'react';
788
- import { Platform } from 'react-native';
789
- import appsFlyer from 'react-native-appsflyer';
790
- import { useDeepLinkIapProvider, DeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
791
-
792
- const DeepLinkHandler = () => {
793
- const { setInsertAffiliateIdentifier, isInitialized } = useDeepLinkIapProvider();
605
+ Update your `ios/YourApp/AppDelegate.mm`:
794
606
 
795
- useEffect(() => {
796
- if (!isInitialized) return;
797
-
798
- // Initialize AppsFlyer
799
- const initAppsFlyer = async () => {
800
- try {
801
- const initOptions = {
802
- devKey: 'your-appsflyer-dev-key',
803
- isDebug: true,
804
- appId: Platform.OS === 'ios' ? 'your-ios-app-id' : 'your-android-package-name',
805
- };
806
-
807
- await appsFlyer.initSdk(initOptions);
808
- } catch (error) {
809
- console.error('AppsFlyer initialization error:', error);
810
- }
811
- };
607
+ ```objc
608
+ #import <React/RCTLinkingManager.h>
812
609
 
813
- // Handle deep link data
814
- const handleDeepLink = async (deepLinkData) => {
815
- if (deepLinkData && deepLinkData.data) {
816
- let referringLink = deepLinkData.data.link || deepLinkData.data.deep_link_value;
817
-
818
- if (referringLink) {
819
- try {
820
- await setInsertAffiliateIdentifier(referringLink);
821
- } catch (err) {
822
- console.error('Error setting affiliate identifier:', err);
823
- }
824
- }
825
- }
826
- };
610
+ - (BOOL)application:(UIApplication *)application
611
+ openURL:(NSURL *)url
612
+ options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
613
+ {
614
+ return [RCTLinkingManager application:application openURL:url options:options];
615
+ }
827
616
 
828
- // Listen for both deep link types
829
- appsFlyer.onDeepLink(handleDeepLink);
830
- appsFlyer.onAppOpenAttribution(handleDeepLink);
617
+ - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
618
+ restorationHandler:(void(^)(NSArray * __nullable restorableObjects))restorationHandler
619
+ {
620
+ return [RCTLinkingManager application:application
621
+ continueUserActivity:userActivity
622
+ restorationHandler:restorationHandler];
623
+ }
624
+ ```
831
625
 
832
- initAppsFlyer();
833
- }, [setInsertAffiliateIdentifier, isInitialized]);
626
+ **Testing Deep Links:**
834
627
 
835
- return <App />;
836
- };
628
+ ```bash
629
+ # iOS Simulator
630
+ xcrun simctl openurl booted "YOUR_IOS_URL_SCHEME://TEST_SHORT_CODE"
837
631
 
838
- const RootComponent = () => {
839
- return (
840
- <DeepLinkIapProvider>
841
- <DeepLinkHandler />
842
- </DeepLinkIapProvider>
843
- );
844
- };
632
+ # Android Emulator
633
+ adb shell am start -W -a android.intent.action.VIEW -d "YOUR_ANDROID_URL_SCHEME://TEST_SHORT_CODE"
845
634
  ```
846
635
 
847
- ## Additional Features
636
+ **Insert Links setup complete!** Skip to [Verify Your Integration](#-verify-your-integration)
848
637
 
849
- ### 1. Event Tracking (Beta)
638
+ </details>
850
639
 
851
- The **InsertAffiliateReactNative SDK** now includes a beta feature for event tracking. Use event tracking to log key user actions such as signups, purchases, or referrals. This is useful for:
852
- - Understanding user behaviour.
853
- - Measuring the effectiveness of marketing campaigns.
854
- - Incentivising affiliates for designated actions being taken by the end users, rather than just in app purchases (i.e. pay an affilaite for each signup).
640
+ <details>
641
+ <summary><h4>Option 2: Branch.io</h4></summary>
855
642
 
856
- At this stage, we cannot guarantee that this feature is fully resistant to tampering or manipulation.
643
+ Branch.io provides robust attribution and deferred deep linking capabilities.
857
644
 
858
- #### Using `trackEvent`
645
+ **Key Integration Steps:**
646
+ 1. Install and configure [Branch SDK for React Native](https://help.branch.io/developers-hub/docs/react-native)
647
+ 2. Subscribe to Branch deep link events
648
+ 3. Extract `~referring_link` from Branch callback
649
+ 4. Pass to Insert Affiliate SDK using `setInsertAffiliateIdentifier()`
859
650
 
860
- To track an event, use the `trackEvent` function. Make sure to set an affiliate identifier first; otherwise, event tracking won't work. Here's an example:
651
+ **[View complete Branch.io integration guide](docs/deep-linking-branch.md)**
861
652
 
862
- ```javascript
863
- const {
864
- referrerLink,
865
- subscriptions,
866
- iapLoading,
867
- validatePurchaseWithIapticAPI,
868
- userId,
869
- userPurchase,
870
- trackEvent, // Required for trackEvent
871
- } = useDeepLinkIapProvider();
872
-
873
- <Button
874
- title={'track event'}
875
- onPress={() => {
876
- trackEvent('event_name')
877
- .then(() => console.log('Event tracked successfully!'))
878
- }}
879
- />
880
- ```
653
+ Includes full examples for:
654
+ - RevenueCat integration
655
+ - Adapty integration
656
+ - Apphud integration
657
+ - Iaptic integration
658
+ - App Store / Google Play Direct integration
881
659
 
882
- ### 2. Discounts for Users Offer Codes / Dynamic Product IDs
660
+ **After completing Branch setup**, skip to [Verify Your Integration](#-verify-your-integration)
883
661
 
884
- The SDK allows you to apply dynamic modifiers to in-app purchases based on whether the app was installed via an affiliate. These modifiers can be used to swap the default product ID for a discounted or trial-based one - similar to applying an offer code.
662
+ </details>
885
663
 
886
- #### How It Works
664
+ <details>
665
+ <summary><h4>Option 3: AppsFlyer</h4></summary>
887
666
 
888
- When a user clicks an affiliate link or enters a short code linked to an offer (set up in the **Insert Affiliate Dashboard**), the SDK auto-populates the `OfferCode` field with a relevant modifier (e.g., `_oneWeekFree`). You can append this to your base product ID to dynamically display the correct subscription.
667
+ AppsFlyer provides enterprise-grade analytics and comprehensive attribution.
889
668
 
890
- #### Basic Usage
669
+ **Key Integration Steps:**
670
+ 1. Install and configure [AppsFlyer SDK for React Native](https://dev.appsflyer.com/hc/docs/react-native-plugin)
671
+ 2. Create AppsFlyer OneLink in dashboard
672
+ 3. Listen for `onDeepLink`, `onAppOpenAttribution`, and `onInstallConversionData` callbacks
673
+ 4. Pass to Insert Affiliate SDK using `setInsertAffiliateIdentifier()`
891
674
 
892
- ##### 1. Automatic Offer Code Fetching
893
- If an affiliate short code is stored, the SDK automatically fetches and saves the associated offer code modifier.
675
+ **[View complete AppsFlyer integration guide](docs/deep-linking-appsflyer.md)**
894
676
 
895
- ##### 2. Access the Offer Code Modifier
896
- The offer code modifier is available through the context:
677
+ Includes full examples for:
678
+ - RevenueCat integration
679
+ - Adapty integration
680
+ - Apphud integration
681
+ - Iaptic integration
682
+ - Store Direct integration
683
+ - Deferred deep linking setup
897
684
 
898
- ```javascript
899
- const { OfferCode } = useDeepLinkIapProvider();
900
- ```
685
+ **After completing AppsFlyer setup**, proceed to [Verify Your Integration](#-verify-your-integration)
901
686
 
902
- ##### Setup Requirements
687
+ </details>
903
688
 
904
- #### Insert Affiliate Setup Instructions
689
+ ---
905
690
 
906
- 1. Go to your Insert Affiliate dashboard at [app.insertaffiliate.com/affiliates](https://app.insertaffiliate.com/affiliates)
907
- 2. Select the affiliate you want to configure
908
- 3. Click "View" to access the affiliate's settings
909
- 4. Assign an iOS IAP Modifier to the affiliate (e.g., `_oneWeekFree`, `_threeMonthsFree`)
910
- 5. Assign an Android IAP Modifier to the affiliate (e.g., `-oneweekfree`, `-threemonthsfree`)
911
- 5. Save the settings
691
+ ## Verify Your Integration
912
692
 
913
- Once configured, when users click that affiliate's links or enter their short codes, your app will automatically receive the modifier and can load the appropriate discounted product.
693
+ Before going live, verify everything works correctly:
914
694
 
915
- #### App Store Connect Configuration
916
- 1. Create both a base and a promotional product:
917
- - Base product: `oneMonthSubscription`
918
- - Promo product: `oneMonthSubscription_oneWeekFree`
919
- 2. Ensure **both** products are approved and available for sale.
695
+ ### Integration Checklist
920
696
 
921
- #### Google Play Console Configuration
922
- There are multiple ways you can configure your products in Google Play Console:
697
+ - [ ] **SDK Initializes**: Check console for `SDK initialized with company code` log
698
+ - [ ] **Affiliate Identifier Stored**: Click a test affiliate link and verify identifier is stored
699
+ - [ ] **Purchase Tracked**: Make a test purchase and verify transaction appears in Insert Affiliate dashboard
923
700
 
924
- 1. **Multiple Products Approach**: Create both a base and a promotional product:
925
- - Base product: `oneMonthSubscription`
926
- - Promo product: `oneMonthSubscription-oneweekfree`
701
+ ### Testing Commands
927
702
 
928
- 2. **Single Product with Multiple Base Plans**: Create one product with multiple base plans, one with an offer attached
703
+ **Test Deep Link (iOS Simulator):**
929
704
 
930
- 3. **Developer Triggered Offers**: Have one base product and apply the offer through developer-triggered offers
705
+ ```bash
706
+ xcrun simctl openurl booted "https://your-deep-link-url/abc123"
707
+ ```
931
708
 
932
- 4. **Base Product with Intro Offers**: Have one base product that includes an introductory offer
709
+ **Test Deep Link (Android Emulator):**
933
710
 
934
- Any of these approaches are suitable and work with the SDK. The important part is that your product naming follows the pattern where the offer code modifier can be appended to identify the promotional version.
711
+ ```bash
712
+ adb shell am start -W -a android.intent.action.VIEW -d "https://your-deep-link-url/abc123"
713
+ ```
935
714
 
936
- **If using the Multiple Products Approach:**
937
- - Ensure **both** products are activated and available for purchase.
938
- - Generate a release to at least **Internal Testing** to make the products available in your current app build
715
+ **Check Stored Affiliate Identifier:**
939
716
 
940
- **Product Naming Pattern:**
941
- - Follow the pattern: `{baseProductId}{OfferCode}`
942
- - Example: `oneMonthSubscription` + `_oneWeekFree` = `oneMonthSubscription_oneWeekFree`
717
+ ```javascript
718
+ const affiliateId = await returnInsertAffiliateIdentifier();
719
+ console.log('Current affiliate ID:', affiliateId);
720
+ ```
943
721
 
944
- ---
722
+ ### Common Setup Issues
945
723
 
946
- #### RevenueCat Dashboard Configuration
724
+ | Issue | Solution |
725
+ |-------|----------|
726
+ | "Company code is not set" | Ensure `initialize()` is called before any other SDK methods |
727
+ | "No affiliate identifier found" | User must click an affiliate link before making a purchase |
728
+ | Deep link opens browser instead of app | Verify URL schemes in Info.plist (iOS) and AndroidManifest.xml (Android) |
729
+ | Purchase not tracked | Check webhook configuration in IAP verification platform |
947
730
 
948
- #### RevenueCat Dashboard Configuration:
949
- 1. Create separate offerings:
950
- - Base offering: `premium_monthly`
951
- - Modified offering: `premium_monthly_oneWeekFree`
731
+ ---
952
732
 
953
- 2. Add both product IDs under different offerings in RevenueCat.
733
+ ## 🔧 Advanced Features
954
734
 
955
- 3. Ensure modified products follow this naming pattern: {baseProductId}_{cleanOfferCode}. e.g. premium_monthly_oneWeekFree
735
+ <details>
736
+ <summary><h3>Event Tracking (Beta)</h3></summary>
956
737
 
738
+ Track custom events beyond purchases (e.g., signups, referrals) to incentivize affiliates for specific actions.
957
739
 
958
- ### Integration Example
959
740
  ```javascript
960
- import React, { useEffect, useState } from 'react';
961
- import { View, Button, Text } from 'react-native';
962
- import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
963
- import Purchases from 'react-native-purchases';
741
+ const { trackEvent } = useDeepLinkIapProvider();
964
742
 
965
- const PurchaseHandler = () => {
966
- const { OfferCode } = useDeepLinkIapProvider();
967
- const [subscriptions, setSubscriptions] = useState([]);
968
-
969
- const fetchSubscriptions = async () => {
970
- const offerings = await Purchases.getOfferings();
971
- let packagesToUse = [];
743
+ // Track custom event (affiliate identifier must be set first)
744
+ await trackEvent('user_signup');
745
+ ```
972
746
 
973
- if (OfferCode) {
974
-
747
+ **Use Cases:**
748
+ - Pay affiliates for signups instead of purchases
749
+ - Track trial starts, content unlocks, or other conversions
975
750
 
976
- // Construct modified product IDs from base products
977
- const baseProducts = offerings.current.availablePackages;
751
+ </details>
978
752
 
979
- for (const basePackage of baseProducts) {
980
- const baseProductId = basePackage.product.identifier;
981
- const modifiedProductId = `${baseProductId}_${OfferCode}`;
753
+ <details>
754
+ <summary><h3>Short Codes</h3></summary>
982
755
 
983
- // Search all offerings for the modified product
984
- const allOfferings = Object.values(offerings.all);
985
- let foundModified = false;
756
+ Short codes are unique, 3-25 character alphanumeric identifiers that affiliates can share (e.g., "SAVE20" in a TikTok video description).
986
757
 
987
- for (const offering of allOfferings) {
988
- const modifiedPackage = offering.availablePackages.find(pkg =>
989
- pkg.product.identifier === modifiedProductId
990
- );
758
+ **Validate and Store Short Code:**
991
759
 
992
- if (modifiedPackage) {
993
- packagesToUse.push(modifiedPackage);
994
- foundModified = true;
995
- break;
996
- }
997
- }
760
+ ```javascript
761
+ const { setShortCode } = useDeepLinkIapProvider();
762
+
763
+ const handleApplyCode = async (code) => {
764
+ const isValid = await setShortCode(code);
765
+ if (isValid) {
766
+ Alert.alert('Success', 'Affiliate code applied!');
767
+ } else {
768
+ Alert.alert('Error', 'Invalid affiliate code');
769
+ }
770
+ };
771
+ ```
998
772
 
999
- // Fallback to base product if no modified version
1000
- if (!foundModified) {
1001
- packagesToUse.push(basePackage);
1002
- }
1003
- }
1004
- } else {
1005
- packagesToUse = offerings.current.availablePackages;
1006
- }
773
+ **Get Affiliate Details Without Setting:**
1007
774
 
1008
- setSubscriptions(packagesToUse);
1009
- };
775
+ ```javascript
776
+ const { getAffiliateDetails } = useDeepLinkIapProvider();
1010
777
 
1011
- const handlePurchase = async (subscriptionPackage) => {
1012
- try {
1013
- await Purchases.purchasePackage(subscriptionPackage);
1014
- } catch (error) {
1015
- console.error('Purchase failed:', error);
1016
- }
1017
- };
778
+ const details = await getAffiliateDetails('SAVE20');
779
+ if (details) {
780
+ console.log('Affiliate Name:', details.affiliateName);
781
+ console.log('Short Code:', details.affiliateShortCode);
782
+ console.log('Deep Link:', details.deeplinkurl);
783
+ }
784
+ ```
1018
785
 
1019
- useEffect(() => {
1020
- fetchSubscriptions();
1021
- }, [OfferCode]);
786
+ Learn more: [Short Codes Documentation](https://docs.insertaffiliate.com/short-codes)
1022
787
 
1023
- return (
1024
- <View>
1025
- {subscriptions.map((pkg) => (
1026
- <Button
1027
- key={pkg.identifier}
1028
- title={`Buy: ${pkg.product.identifier}`}
1029
- onPress={() => handlePurchase(pkg)}
1030
- />
1031
- ))}
1032
- {OfferCode && (
1033
- <Text>Special offer applied: {OfferCode}</Text>
1034
- )}
1035
- </View>
1036
- );
1037
- };
1038
- ```
1039
- ---
788
+ </details>
1040
789
 
1041
- #### Native Receipt Verification Example
790
+ <details>
791
+ <summary><h3>Dynamic Offer Codes / Discounts</h3></summary>
1042
792
 
1043
- For apps using `react-native-iap` directly:
793
+ Automatically apply discounts or trials when users come from specific affiliates.
1044
794
 
1045
- ```javascript
1046
- import React, { useState, useEffect } from 'react';
1047
- import { View, Text, Button, Platform } from 'react-native';
1048
- import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
1049
- import {
1050
- initConnection,
1051
- getSubscriptions,
1052
- requestSubscription,
1053
- useIAP
1054
- } from 'react-native-iap';
1055
-
1056
- const NativeIAPPurchaseView = () => {
1057
- const { OfferCode, returnUserAccountTokenAndStoreExpectedTransaction } = useDeepLinkIapProvider();
1058
- const [availableProducts, setAvailableProducts] = useState([]);
1059
- const [loading, setLoading] = useState(false);
1060
- const { currentPurchase, connected } = useIAP();
1061
-
1062
- const baseProductIdentifier = "oneMonthSubscription";
1063
-
1064
- // Dynamic product identifier that includes offer code
1065
- const dynamicProductIdentifier = OfferCode
1066
- ? `${baseProductIdentifier}${OfferCode}` // e.g., "oneMonthSubscription_oneWeekFree"
1067
- : baseProductIdentifier;
1068
-
1069
- const fetchProducts = async () => {
1070
- try {
1071
- setLoading(true);
1072
-
1073
- // Try to fetch the dynamic product first
1074
- let productIds = [dynamicProductIdentifier];
1075
-
1076
- // Also include base product as fallback
1077
- if (OfferCode) {
1078
- productIds.push(baseProductIdentifier);
1079
- }
1080
-
1081
- const products = await getSubscriptions({ skus: productIds });
1082
-
1083
- // Prioritize the dynamic product if it exists
1084
- let sortedProducts = products;
1085
- if (OfferCode && products.length > 1) {
1086
- sortedProducts = products.sort((a, b) =>
1087
- a.productId === dynamicProductIdentifier ? -1 : 1
1088
- );
1089
- }
1090
-
1091
- setAvailableProducts(sortedProducts);
1092
- console.log(`Loaded products for: ${productIds.join(', ')}`);
1093
-
1094
- } catch (error) {
1095
- try {
1096
- // Fallback logic
1097
- const baseProducts = await getSubscriptions({ skus: [baseProductIdentifier] });
1098
- setAvailableProducts(baseProducts);
1099
- } catch (fallbackError) {
1100
- console.error('Failed to fetch base products:', fallbackError);
1101
- }
1102
- } finally {
1103
- setLoading(false);
1104
- }
1105
- };
795
+ **How It Works:**
796
+ 1. Configure an offer code modifier in your [Insert Affiliate dashboard](https://app.insertaffiliate.com/affiliates) (e.g., `_oneWeekFree`)
797
+ 2. SDK automatically fetches and stores the modifier when affiliate identifier is set
798
+ 3. Use the modifier to construct dynamic product IDs
1106
799
 
1107
- const handlePurchase = async (productId) => {
1108
- // Implement the purchase handling logic as outlined in the remaining SDK integration steps.
1109
- };
800
+ **Quick Example:**
1110
801
 
1111
- useEffect(() => {
1112
- if (connected) {
1113
- fetchProducts();
1114
- }
1115
- }, [connected, OfferCode]);;
802
+ ```javascript
803
+ const { OfferCode } = useDeepLinkIapProvider();
1116
804
 
1117
- const primaryProduct = availableProducts[0];
805
+ const baseProductId = "oneMonthSubscription";
806
+ const dynamicProductId = OfferCode
807
+ ? `${baseProductId}${OfferCode}` // e.g., "oneMonthSubscription_oneWeekFree"
808
+ : baseProductId;
1118
809
 
1119
- return (
1120
- <View style={{ padding: 20 }}>
1121
- <Text style={{ fontSize: 18, fontWeight: 'bold', marginBottom: 10 }}>
1122
- Premium Subscription
1123
- </Text>
1124
-
1125
- {OfferCode && (
1126
- <View style={{ backgroundColor: '#e3f2fd', padding: 10, marginBottom: 15, borderRadius: 8 }}>
1127
- <Text style={{ color: '#1976d2', fontWeight: 'bold' }}>
1128
- 🎉 Special Offer Applied: {OfferCode}
1129
- </Text>
1130
- </View>
1131
- )}
1132
-
1133
- {loading ? (
1134
- <Text>Loading products...</Text>
1135
- ) : primaryProduct ? (
1136
- <View>
1137
- <Text style={{ fontSize: 16, marginBottom: 5 }}>
1138
- {primaryProduct.title}
1139
- </Text>
1140
- <Text style={{ fontSize: 14, color: '#666', marginBottom: 5 }}>
1141
- Price: {primaryProduct.localizedPrice}
1142
- </Text>
1143
- <Text style={{ fontSize: 12, color: '#999', marginBottom: 15 }}>
1144
- Product ID: {primaryProduct.productId}
1145
- </Text>
1146
-
1147
- <Button
1148
- title={loading ? "Processing..." : "Subscribe Now"}
1149
- onPress={() => handlePurchase(primaryProduct.productId)}
1150
- disabled={loading}
1151
- />
1152
-
1153
- {primaryProduct.productId === dynamicProductIdentifier && OfferCode && (
1154
- <Text style={{ fontSize: 12, color: '#4caf50', marginTop: 10 }}>
1155
- ✓ Promotional pricing applied
1156
- </Text>
1157
- )}
1158
- </View>
1159
- ) : (
1160
- <View>
1161
- <Text style={{ color: '#f44336', marginBottom: 10 }}>
1162
- Product not found: {dynamicProductIdentifier}
1163
- </Text>
1164
- <Button
1165
- title="Retry"
1166
- onPress={fetchProducts}
1167
- />
1168
- </View>
1169
- )}
1170
-
1171
- {availableProducts.length > 1 && (
1172
- <View style={{ marginTop: 20 }}>
1173
- <Text style={{ fontSize: 14, fontWeight: 'bold', marginBottom: 10 }}>
1174
- Other Options:
1175
- </Text>
1176
- {availableProducts.slice(1).map((product) => (
1177
- <Button
1178
- key={product.productId}
1179
- title={`${product.title} - ${product.localizedPrice}`}
1180
- onPress={() => handlePurchase(product.productId)}
1181
- />
1182
- ))}
1183
- </View>
1184
- )}
1185
- </View>
1186
- );
1187
- };
810
+ // Use dynamicProductId when fetching/purchasing products
1188
811
  ```
1189
812
 
1190
- ##### Key Features of Native IAP Integration:
813
+ **[View complete Dynamic Offer Codes guide](docs/dynamic-offer-codes.md)**
1191
814
 
1192
- 1. **Dynamic Product Loading**: Automatically constructs product IDs using the offer code modifier
1193
- 2. **Fallback Strategy**: If the promotional product isn't found, falls back to the base product
1194
- 3. **Visual Feedback**: Shows users when promotional pricing is applied
1195
- 4. **Error Handling**: Graceful handling when products aren't available
815
+ Includes full examples for:
816
+ - App Store Connect and Google Play Console setup
817
+ - RevenueCat integration with dynamic product selection
818
+ - Native react-native-iap integration
819
+ - Testing and troubleshooting
1196
820
 
821
+ </details>
1197
822
 
1198
- ### 3. Short Codes (Beta)
823
+ <details>
824
+ <summary><h3>Attribution Timeout Control</h3></summary>
1199
825
 
1200
- #### What are Short Codes?
826
+ Control how long affiliate attribution remains active after a user clicks a link.
1201
827
 
1202
- Short codes are unique identifiers that affiliates can use to promote products or subscriptions. These codes are ideal for influencers or partners, making them easier to share than long URLs.
828
+ **Set Timeout During Initialization:**
1203
829
 
1204
- **Example Use Case**: An influencer promotes a subscription with the short code "JOIN12345" within their TikTok video's description. When users enter this code within your app during sign-up or before purchase, the app tracks the subscription back to the influencer for commission payouts.
830
+ ```javascript
831
+ // 7-day attribution window (604800 seconds)
832
+ initialize(
833
+ "YOUR_COMPANY_CODE",
834
+ false, // verboseLogging
835
+ false, // insertLinksEnabled
836
+ false, // insertLinksClipboardEnabled
837
+ 604800 // affiliateAttributionActiveTime
838
+ );
839
+ ```
1205
840
 
1206
- For more information, visit the [Insert Affiliate Short Codes Documentation](https://docs.insertaffiliate.com/short-codes).
841
+ **Check Attribution Validity:**
1207
842
 
1208
- #### Setting a Short Code
843
+ ```javascript
844
+ const { isAffiliateAttributionValid, getAffiliateStoredDate } = useDeepLinkIapProvider();
1209
845
 
1210
- Use the `setShortCode` method to associate a short code with an affiliate. This is ideal for scenarios where users enter the code via an input field, pop-up, or similar UI element.
846
+ const isValid = await isAffiliateAttributionValid();
847
+ const storedDate = await getAffiliateStoredDate();
848
+ ```
849
+
850
+ **Common Timeout Values:**
851
+ - 1 day: `86400`
852
+ - 7 days: `604800` (recommended)
853
+ - 30 days: `2592000`
854
+ - No timeout: omit parameter (default)
1211
855
 
1212
- Short codes must meet the following criteria:
1213
- - Between **3-25 characters long**.
1214
- - Contain only **letters, numbers, and underscores** (alphanumeric characters and underscores).
1215
- - Replace {{ user_entered_short_code }} with the short code the user enters through your chosen input method, i.e. an input field / pop up element
856
+ **Bypass Timeout Check:**
1216
857
 
1217
858
  ```javascript
1218
- import {
1219
- DeepLinkIapProvider,
1220
- } from 'insert-affiliate-react-native-sdk';
1221
-
1222
- const {
1223
- setShortCode,
1224
- } = useDeepLinkIapProvider();
1225
-
1226
- <Button
1227
- title={'Set Short Code'}
1228
- onPress={() => setShortCode('JOIN_123')}
1229
- />
859
+ // Get identifier even if attribution has expired
860
+ const rawIdentifier = await returnInsertAffiliateIdentifier(true);
1230
861
  ```
1231
862
 
1232
- ### Attribution Timeout
1233
-
1234
- You can configure how long an affiliate link attribution remains active after being clicked. This allows you to control the attribution window for commissions.
863
+ </details>
1235
864
 
1236
- #### Basic Usage
1237
-
1238
- When initializing the SDK, you can specify the attribution timeout in seconds:
865
+ ---
1239
866
 
1240
- ```javascript
1241
- const Child = () => {
1242
- const { initialize, isInitialized } = useDeepLinkIapProvider();
867
+ ## 🔍 Troubleshooting
1243
868
 
1244
- useEffect(() => {
1245
- if (!isInitialized) {
1246
- // Set attribution timeout to 7 days (7 * 24 * 60 * 60 = 604800 seconds)
1247
- initialize(
1248
- "{{ your-company-code }}",
1249
- false, // verbose logging
1250
- false, // insert links enabled
1251
- false, // insert links clipboard enabled
1252
- 604800 // attribution timeout in seconds
1253
- );
1254
- }
1255
- }, [initialize, isInitialized]);
1256
- }
1257
- ```
869
+ ### Initialization Issues
1258
870
 
1259
- **When to use `affiliateAttributionActiveTime`:**
1260
- - Set to a number in seconds to define how long affiliate attributions remain active
1261
- - Set to `null` or omit to disable attribution timeout (attribution never expires)
1262
- - Common values: 86400 (1 day), 604800 (7 days), 2592000 (30 days)
871
+ **Error:** "Company code is not set"
872
+ - **Cause:** SDK not initialized or `initialize()` called after other SDK methods
873
+ - **Solution:** Call `initialize()` in your main App component's `useEffect` before any other SDK methods
1263
874
 
1264
- #### Common Timeout Values
875
+ ### Deep Linking Issues
1265
876
 
1266
- ```javascript
1267
- // 1 day
1268
- initialize("your-company-code", false, false, false, 86400);
877
+ **Problem:** Deep link opens browser instead of app
878
+ - **Cause:** Missing or incorrect URL scheme configuration
879
+ - **Solution:**
880
+ - iOS: Add URL scheme to Info.plist and configure associated domains
881
+ - Android: Add intent filters to AndroidManifest.xml
1269
882
 
1270
- // 7 days (default for many platforms)
1271
- initialize("your-company-code", false, false, false, 604800);
883
+ **Problem:** "No affiliate identifier found"
884
+ - **Cause:** User hasn't clicked an affiliate link yet
885
+ - **Solution:** Test with simulator/emulator:
886
+ ```bash
887
+ # iOS
888
+ xcrun simctl openurl booted "YOUR_DEEP_LINK_URL"
889
+ # Android
890
+ adb shell am start -W -a android.intent.action.VIEW -d "YOUR_DEEP_LINK_URL"
891
+ ```
1272
892
 
1273
- // 30 days
1274
- initialize("your-company-code", false, false, false, 2592000);
893
+ ### Purchase Tracking Issues
1275
894
 
1276
- // No timeout (attribution never expires)
1277
- initialize("your-company-code", false, false, false); // or pass null/undefined
1278
- ```
895
+ **Problem:** Purchases not appearing in Insert Affiliate dashboard
896
+ - **Cause:** Webhook not configured or affiliate identifier not passed to IAP platform
897
+ - **Solution:**
898
+ - Verify webhook URL and authorization headers are correct
899
+ - For RevenueCat: Confirm `insert_affiliate` attribute is set before purchase
900
+ - Enable verbose logging and check console for errors
1279
901
 
1280
- #### Advanced Usage
902
+ ### Verbose Logging
1281
903
 
1282
- The SDK provides methods to work with attribution timeouts:
904
+ Enable detailed logs during development to diagnose issues:
1283
905
 
1284
906
  ```javascript
1285
- const {
1286
- returnInsertAffiliateIdentifier,
1287
- isAffiliateAttributionValid,
1288
- getAffiliateStoredDate
1289
- } = useDeepLinkIapProvider();
907
+ initialize("YOUR_COMPANY_CODE", true); // second parameter enables verbose logging
908
+ ```
1290
909
 
1291
- // Get affiliate identifier (respects timeout)
1292
- const identifier = await returnInsertAffiliateIdentifier();
910
+ **Important:** Disable verbose logging in production builds.
1293
911
 
1294
- // Get affiliate identifier ignoring timeout
1295
- const rawIdentifier = await returnInsertAffiliateIdentifier(true);
912
+ ### Getting Help
1296
913
 
1297
- // Check if attribution is still valid
1298
- const isValid = await isAffiliateAttributionValid();
914
+ - [Documentation](https://docs.insertaffiliate.com)
915
+ - [Dashboard Support](https://app.insertaffiliate.com/help)
916
+ - [Report Issues](https://github.com/Insert-Affiliate/InsertAffiliateReactNativeSDK/issues)
1299
917
 
1300
- // Get the date when affiliate was first stored
1301
- const storedDate = await getAffiliateStoredDate();
1302
- ```
918
+ ---
1303
919
 
1304
- #### How It Works
920
+ ## 📚 Support
1305
921
 
1306
- 1. **Attribution Storage**: When an affiliate link is clicked and processed, the SDK stores both the affiliate identifier and the current timestamp
1307
- 2. **Timeout Check**: When `returnInsertAffiliateIdentifier()` is called, the SDK checks if the stored attribution is still within the timeout window
1308
- 3. **Expired Attribution**: If the attribution has expired, the method returns `null` instead of the affiliate identifier
1309
- 4. **Bypass Option**: You can bypass the timeout check by passing `true` to `returnInsertAffiliateIdentifier(true)`
922
+ - **Documentation**: [docs.insertaffiliate.com](https://docs.insertaffiliate.com)
923
+ - **Dashboard Support**: [app.insertaffiliate.com/help](https://app.insertaffiliate.com/help)
924
+ - **Issues**: [GitHub Issues](https://github.com/Insert-Affiliate/InsertAffiliateReactNativeSDK/issues)
925
+ - **Company Code**: [Get yours from Settings](https://app.insertaffiliate.com/settings)
926
+
927
+ ---
1310
928
 
1311
- This ensures that affiliates are only credited for purchases made within the specified attribution window, providing fair and accurate commission tracking.
929
+ **Need help getting started?** Check out our [quickstart guide](https://docs.insertaffiliate.com) or [contact support](https://app.insertaffiliate.com/help).