insert-affiliate-react-native-sdk 1.9.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/dist/DeepLinkIapProvider.js +117 -15
- package/docs/deep-linking-appsflyer.md +364 -0
- package/docs/deep-linking-branch.md +330 -0
- package/docs/dynamic-offer-codes.md +369 -0
- package/package.json +1 -1
- package/readme.md +592 -1073
- package/src/DeepLinkIapProvider.tsx +146 -24
package/readme.md
CHANGED
|
@@ -1,72 +1,65 @@
|
|
|
1
1
|
# InsertAffiliateReactNative SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
  
|
|
4
4
|
|
|
5
|
-
The
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
The SDK requires the following peer dependencies to function properly:
|
|
47
|
+
**Step 3:** Install iOS pods (iOS only)
|
|
39
48
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
53
|
+
### Your First Integration
|
|
60
54
|
|
|
61
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
98
|
-
|
|
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
|
-
|
|
104
|
+
**Expected Console Output:**
|
|
104
105
|
|
|
105
|
-
|
|
106
|
+
When the SDK initializes successfully, you'll see:
|
|
106
107
|
|
|
107
|
-
|
|
108
|
+
```
|
|
109
|
+
[Insert Affiliate] SDK initialized with company code: YOUR_COMPANY_CODE
|
|
110
|
+
[Insert Affiliate] [VERBOSE] SDK marked as initialized
|
|
111
|
+
```
|
|
108
112
|
|
|
109
|
-
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}, [initialize, isInitialized]);
|
|
119
|
-
}
|
|
120
|
-
```
|
|
115
|
+
**Important:** Disable verbose logging in production by setting the second parameter to `false`.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## ⚙️ Essential Setup
|
|
121
120
|
|
|
122
|
-
|
|
121
|
+
Complete these three required steps to start tracking affiliate-driven purchases.
|
|
123
122
|
|
|
124
|
-
|
|
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
|
|
123
|
+
### 1. Initialize the SDK
|
|
130
124
|
|
|
131
|
-
|
|
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
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
**
|
|
146
|
-
-
|
|
147
|
-
-
|
|
148
|
-
-
|
|
149
|
-
-
|
|
150
|
-
-
|
|
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>
|
|
151
155
|
|
|
152
|
-
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### 2. Configure In-App Purchase Verification
|
|
153
159
|
|
|
154
|
-
|
|
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
|
-
|
|
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
|
-
|
|
170
|
+
<details open>
|
|
171
|
+
<summary><h4>Option 1: RevenueCat (Recommended)</h4></summary>
|
|
160
172
|
|
|
161
|
-
|
|
173
|
+
**Step 1: Code Setup**
|
|
162
174
|
|
|
163
|
-
|
|
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
|
-
|
|
167
|
-
|
|
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
|
-
**
|
|
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
|
-
|
|
188
|
-
|
|
189
|
-
- **
|
|
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
|
-
|
|
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
|
-
|
|
200
|
-
|
|
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
|
-
|
|
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
|
-
|
|
233
|
-
|
|
234
|
-
|
|
227
|
+
```bash
|
|
228
|
+
npm install react-native-adapty
|
|
229
|
+
cd ios && pod install && cd ..
|
|
235
230
|
```
|
|
236
231
|
|
|
237
|
-
|
|
232
|
+
Complete the [Adapty SDK installation](https://adapty.io/docs/sdk-installation-reactnative) for any additional platform-specific setup.
|
|
238
233
|
|
|
239
|
-
|
|
234
|
+
**Step 2: Code Setup**
|
|
240
235
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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
|
-
|
|
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
|
-
|
|
251
|
-
|
|
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
|
-
|
|
257
|
-
|
|
258
|
-
|
|
252
|
+
// Initialize Insert Affiliate
|
|
253
|
+
if (!isInitialized) {
|
|
254
|
+
initialize("YOUR_COMPANY_CODE");
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
initSDKs();
|
|
258
|
+
}, [initialize, isInitialized]);
|
|
259
259
|
|
|
260
|
-
|
|
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
|
-
|
|
263
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
298
|
+
**Step 4: Verify Integration**
|
|
349
299
|
|
|
350
|
-
|
|
351
|
-
|
|
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
|
-
|
|
305
|
+
**Adapty setup complete!** Now skip to [Step 3: Set Up Deep Linking](#3-set-up-deep-linking)
|
|
354
306
|
|
|
355
|
-
|
|
307
|
+
</details>
|
|
356
308
|
|
|
357
|
-
|
|
309
|
+
<details>
|
|
310
|
+
<summary><h4>Option 3: Iaptic</h4></summary>
|
|
358
311
|
|
|
359
|
-
|
|
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
|
-
|
|
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
|
-
|
|
369
|
-
|
|
321
|
+
const App = () => {
|
|
322
|
+
const { initialize, isInitialized, validatePurchaseWithIapticAPI } = useDeepLinkIapProvider();
|
|
323
|
+
const { currentPurchase } = useIAP();
|
|
370
324
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
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
|
-
|
|
388
|
-
|
|
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)
|
|
394
353
|
|
|
395
|
-
|
|
396
|
-
Our direct Google Play Store integration is currently in beta.
|
|
354
|
+
**Step 2: Webhook Setup**
|
|
397
355
|
|
|
398
|
-
|
|
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)
|
|
399
364
|
|
|
400
|
-
|
|
365
|
+
**Iaptic setup complete!** Now proceed to [Step 3: Set Up Deep Linking](#3-set-up-deep-linking)
|
|
401
366
|
|
|
402
|
-
|
|
367
|
+
</details>
|
|
403
368
|
|
|
404
|
-
|
|
369
|
+
<details>
|
|
370
|
+
<summary><h4>Option 4: App Store Direct</h4></summary>
|
|
405
371
|
|
|
406
|
-
|
|
372
|
+
**Step 1: Apple App Store Notification Setup**
|
|
373
|
+
|
|
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.
|
|
375
|
+
|
|
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 {
|
|
412
|
-
import {
|
|
413
|
-
|
|
414
|
-
const { storeExpectedStoreTransaction } = useDeepLinkIapProvider();
|
|
380
|
+
import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
|
|
381
|
+
import { requestSubscription } from 'react-native-iap';
|
|
415
382
|
|
|
416
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
410
|
+
**Step 1: RTDN Setup**
|
|
443
411
|
|
|
444
|
-
|
|
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
|
-
|
|
414
|
+
**Step 2: Implementing Purchases**
|
|
447
415
|
|
|
448
|
-
|
|
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
|
-
|
|
422
|
+
const App = () => {
|
|
423
|
+
const { storeExpectedStoreTransaction } = useDeepLinkIapProvider();
|
|
424
|
+
const { currentPurchase } = useIAP();
|
|
451
425
|
|
|
452
|
-
|
|
426
|
+
useEffect(() => {
|
|
427
|
+
if (currentPurchase && Platform.OS === 'android' && currentPurchase.purchaseToken) {
|
|
428
|
+
storeExpectedStoreTransaction(currentPurchase.purchaseToken);
|
|
429
|
+
}
|
|
430
|
+
}, [currentPurchase, storeExpectedStoreTransaction]);
|
|
453
431
|
|
|
454
|
-
|
|
432
|
+
return <YourAppContent />;
|
|
433
|
+
};
|
|
434
|
+
```
|
|
455
435
|
|
|
456
|
-
|
|
436
|
+
**Google Play Direct setup complete!** Now proceed to [Step 3: Set Up Deep Linking](#3-set-up-deep-linking)
|
|
457
437
|
|
|
458
|
-
|
|
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
|
-
|
|
440
|
+
---
|
|
464
441
|
|
|
465
|
-
|
|
442
|
+
### 3. Set Up Deep Linking
|
|
466
443
|
|
|
467
|
-
|
|
444
|
+
**Deep linking lets affiliates share unique links that track users to your app.** Choose **ONE** deep linking provider:
|
|
468
445
|
|
|
469
|
-
|
|
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
|
-
|
|
452
|
+
<details open>
|
|
453
|
+
<summary><h4>Option 1: Insert Links (Simplest)</h4></summary>
|
|
472
454
|
|
|
473
|
-
|
|
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
|
-
|
|
477
|
-
- (
|
|
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
|
-
|
|
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
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
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
|
-
|
|
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
|
-
|
|
477
|
+
Choose the example that matches your IAP verification platform:
|
|
507
478
|
|
|
508
|
-
|
|
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
|
-
|
|
522
|
-
await Purchases.setAttributes({"insert_affiliate": identifier});
|
|
491
|
+
await Purchases.setAttributes({ "insert_affiliate": identifier });
|
|
523
492
|
}
|
|
524
493
|
});
|
|
525
494
|
|
|
526
|
-
|
|
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
|
-
|
|
502
|
+
**With Adapty:**
|
|
537
503
|
|
|
538
504
|
```javascript
|
|
539
505
|
import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
|
|
540
|
-
import
|
|
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
|
-
|
|
549
|
-
|
|
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
|
-
|
|
529
|
+
**With Apphud:**
|
|
563
530
|
|
|
564
531
|
```javascript
|
|
565
532
|
import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
|
|
566
|
-
import
|
|
533
|
+
import Apphud from 'react-native-apphud';
|
|
567
534
|
|
|
568
535
|
const App = () => {
|
|
569
536
|
const { setInsertAffiliateIdentifierChangeCallback } = useDeepLinkIapProvider();
|
|
@@ -571,840 +538,392 @@ const App = () => {
|
|
|
571
538
|
useEffect(() => {
|
|
572
539
|
setInsertAffiliateIdentifierChangeCallback(async (identifier) => {
|
|
573
540
|
if (identifier) {
|
|
574
|
-
|
|
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
|
|
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
|
-
|
|
656
|
-
|
|
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
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
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 () =>
|
|
684
|
-
}, [
|
|
685
|
-
|
|
686
|
-
return <App />;
|
|
687
|
-
};
|
|
573
|
+
return () => setInsertAffiliateIdentifierChangeCallback(null);
|
|
574
|
+
}, []);
|
|
688
575
|
|
|
689
|
-
|
|
690
|
-
return (
|
|
691
|
-
<DeepLinkIapProvider>
|
|
692
|
-
<DeepLinkHandler />
|
|
693
|
-
</DeepLinkIapProvider>
|
|
694
|
-
);
|
|
576
|
+
return <YourAppContent />;
|
|
695
577
|
};
|
|
696
578
|
```
|
|
697
579
|
|
|
698
|
-
|
|
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
|
|
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
|
|
724
|
-
const {
|
|
585
|
+
const App = () => {
|
|
586
|
+
const { setInsertAffiliateIdentifierChangeCallback } = useDeepLinkIapProvider();
|
|
725
587
|
|
|
726
588
|
useEffect(() => {
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
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
|
-
appsFlyer.onInstallConversionData(handleDeepLink);
|
|
767
|
-
|
|
768
|
-
initAppsFlyer();
|
|
769
|
-
}, [setInsertAffiliateIdentifier, isInitialized]);
|
|
594
|
+
});
|
|
770
595
|
|
|
771
|
-
|
|
772
|
-
};
|
|
596
|
+
return () => setInsertAffiliateIdentifierChangeCallback(null);
|
|
597
|
+
}, []);
|
|
773
598
|
|
|
774
|
-
|
|
775
|
-
return (
|
|
776
|
-
<DeepLinkIapProvider>
|
|
777
|
-
<DeepLinkHandler />
|
|
778
|
-
</DeepLinkIapProvider>
|
|
779
|
-
);
|
|
599
|
+
return <YourAppContent />;
|
|
780
600
|
};
|
|
781
|
-
|
|
782
|
-
AppRegistry.registerComponent(appName, () => RootComponent);
|
|
783
601
|
```
|
|
784
602
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
```javascript
|
|
788
|
-
import React, { useEffect } from 'react';
|
|
789
|
-
import { Platform } from 'react-native';
|
|
790
|
-
import appsFlyer from 'react-native-appsflyer';
|
|
791
|
-
import { useDeepLinkIapProvider, DeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
|
|
792
|
-
|
|
793
|
-
const DeepLinkHandler = () => {
|
|
794
|
-
const { setInsertAffiliateIdentifier, isInitialized } = useDeepLinkIapProvider();
|
|
795
|
-
|
|
796
|
-
useEffect(() => {
|
|
797
|
-
if (!isInitialized) return;
|
|
798
|
-
|
|
799
|
-
// Initialize AppsFlyer
|
|
800
|
-
const initAppsFlyer = async () => {
|
|
801
|
-
try {
|
|
802
|
-
const initOptions = {
|
|
803
|
-
devKey: 'your-appsflyer-dev-key',
|
|
804
|
-
isDebug: true,
|
|
805
|
-
appId: Platform.OS === 'ios' ? 'your-ios-app-id' : 'your-android-package-name',
|
|
806
|
-
};
|
|
807
|
-
|
|
808
|
-
await appsFlyer.initSdk(initOptions);
|
|
809
|
-
} catch (error) {
|
|
810
|
-
console.error('AppsFlyer initialization error:', error);
|
|
811
|
-
}
|
|
812
|
-
};
|
|
813
|
-
|
|
814
|
-
// Handle deep link data
|
|
815
|
-
const handleDeepLink = async (deepLinkData) => {
|
|
816
|
-
if (deepLinkData && deepLinkData.data) {
|
|
817
|
-
let referringLink = deepLinkData.data.link || deepLinkData.data.deep_link_value;
|
|
818
|
-
|
|
819
|
-
if (referringLink) {
|
|
820
|
-
try {
|
|
821
|
-
await setInsertAffiliateIdentifier(referringLink);
|
|
822
|
-
} catch (err) {
|
|
823
|
-
console.error('Error setting affiliate identifier:', err);
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
};
|
|
603
|
+
**Step 3: iOS Native Setup (Required)**
|
|
828
604
|
|
|
829
|
-
|
|
830
|
-
appsFlyer.onDeepLink(handleDeepLink);
|
|
831
|
-
appsFlyer.onAppOpenAttribution(handleDeepLink);
|
|
832
|
-
appsFlyer.onInstallConversionData(handleDeepLink);
|
|
605
|
+
Update your `ios/YourApp/AppDelegate.mm`:
|
|
833
606
|
|
|
834
|
-
|
|
835
|
-
|
|
607
|
+
```objc
|
|
608
|
+
#import <React/RCTLinkingManager.h>
|
|
836
609
|
|
|
837
|
-
|
|
838
|
-
|
|
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
|
+
}
|
|
839
616
|
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
}
|
|
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
|
+
}
|
|
847
624
|
```
|
|
848
625
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
### 1. Event Tracking (Beta)
|
|
626
|
+
**Testing Deep Links:**
|
|
852
627
|
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
- 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).
|
|
857
|
-
|
|
858
|
-
At this stage, we cannot guarantee that this feature is fully resistant to tampering or manipulation.
|
|
859
|
-
|
|
860
|
-
#### Using `trackEvent`
|
|
861
|
-
|
|
862
|
-
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:
|
|
628
|
+
```bash
|
|
629
|
+
# iOS Simulator
|
|
630
|
+
xcrun simctl openurl booted "YOUR_IOS_URL_SCHEME://TEST_SHORT_CODE"
|
|
863
631
|
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
referrerLink,
|
|
867
|
-
subscriptions,
|
|
868
|
-
iapLoading,
|
|
869
|
-
validatePurchaseWithIapticAPI,
|
|
870
|
-
userId,
|
|
871
|
-
userPurchase,
|
|
872
|
-
trackEvent, // Required for trackEvent
|
|
873
|
-
} = useDeepLinkIapProvider();
|
|
874
|
-
|
|
875
|
-
<Button
|
|
876
|
-
title={'track event'}
|
|
877
|
-
onPress={() => {
|
|
878
|
-
trackEvent('event_name')
|
|
879
|
-
.then(() => console.log('Event tracked successfully!'))
|
|
880
|
-
}}
|
|
881
|
-
/>
|
|
632
|
+
# Android Emulator
|
|
633
|
+
adb shell am start -W -a android.intent.action.VIEW -d "YOUR_ANDROID_URL_SCHEME://TEST_SHORT_CODE"
|
|
882
634
|
```
|
|
883
635
|
|
|
884
|
-
|
|
636
|
+
**Insert Links setup complete!** Skip to [Verify Your Integration](#-verify-your-integration)
|
|
885
637
|
|
|
886
|
-
|
|
638
|
+
</details>
|
|
887
639
|
|
|
888
|
-
|
|
640
|
+
<details>
|
|
641
|
+
<summary><h4>Option 2: Branch.io</h4></summary>
|
|
889
642
|
|
|
890
|
-
|
|
643
|
+
Branch.io provides robust attribution and deferred deep linking capabilities.
|
|
891
644
|
|
|
892
|
-
|
|
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()`
|
|
893
650
|
|
|
894
|
-
|
|
895
|
-
If an affiliate short code is stored, the SDK automatically fetches and saves the associated offer code modifier.
|
|
651
|
+
**[View complete Branch.io integration guide](docs/deep-linking-branch.md)**
|
|
896
652
|
|
|
897
|
-
|
|
898
|
-
|
|
653
|
+
Includes full examples for:
|
|
654
|
+
- RevenueCat integration
|
|
655
|
+
- Adapty integration
|
|
656
|
+
- Apphud integration
|
|
657
|
+
- Iaptic integration
|
|
658
|
+
- App Store / Google Play Direct integration
|
|
899
659
|
|
|
900
|
-
|
|
901
|
-
const { OfferCode } = useDeepLinkIapProvider();
|
|
902
|
-
```
|
|
660
|
+
**After completing Branch setup**, skip to [Verify Your Integration](#-verify-your-integration)
|
|
903
661
|
|
|
904
|
-
|
|
662
|
+
</details>
|
|
905
663
|
|
|
906
|
-
|
|
664
|
+
<details>
|
|
665
|
+
<summary><h4>Option 3: AppsFlyer</h4></summary>
|
|
907
666
|
|
|
908
|
-
|
|
909
|
-
2. Select the affiliate you want to configure
|
|
910
|
-
3. Click "View" to access the affiliate's settings
|
|
911
|
-
4. Assign an iOS IAP Modifier to the affiliate (e.g., `_oneWeekFree`, `_threeMonthsFree`)
|
|
912
|
-
5. Assign an Android IAP Modifier to the affiliate (e.g., `-oneweekfree`, `-threemonthsfree`)
|
|
913
|
-
5. Save the settings
|
|
667
|
+
AppsFlyer provides enterprise-grade analytics and comprehensive attribution.
|
|
914
668
|
|
|
915
|
-
|
|
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()`
|
|
916
674
|
|
|
917
|
-
|
|
918
|
-
1. Create both a base and a promotional product:
|
|
919
|
-
- Base product: `oneMonthSubscription`
|
|
920
|
-
- Promo product: `oneMonthSubscription_oneWeekFree`
|
|
921
|
-
2. Ensure **both** products are approved and available for sale.
|
|
675
|
+
**[View complete AppsFlyer integration guide](docs/deep-linking-appsflyer.md)**
|
|
922
676
|
|
|
923
|
-
|
|
924
|
-
|
|
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
|
|
925
684
|
|
|
926
|
-
|
|
927
|
-
- Base product: `oneMonthSubscription`
|
|
928
|
-
- Promo product: `oneMonthSubscription-oneweekfree`
|
|
685
|
+
**After completing AppsFlyer setup**, proceed to [Verify Your Integration](#-verify-your-integration)
|
|
929
686
|
|
|
930
|
-
|
|
687
|
+
</details>
|
|
931
688
|
|
|
932
|
-
|
|
689
|
+
---
|
|
933
690
|
|
|
934
|
-
|
|
691
|
+
## ✅ Verify Your Integration
|
|
935
692
|
|
|
936
|
-
|
|
693
|
+
Before going live, verify everything works correctly:
|
|
937
694
|
|
|
938
|
-
|
|
939
|
-
- Ensure **both** products are activated and available for purchase.
|
|
940
|
-
- Generate a release to at least **Internal Testing** to make the products available in your current app build
|
|
695
|
+
### Integration Checklist
|
|
941
696
|
|
|
942
|
-
**
|
|
943
|
-
-
|
|
944
|
-
-
|
|
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
|
|
945
700
|
|
|
946
|
-
|
|
701
|
+
### Testing Commands
|
|
947
702
|
|
|
948
|
-
|
|
703
|
+
**Test Deep Link (iOS Simulator):**
|
|
949
704
|
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
- Modified offering: `premium_monthly_oneWeekFree`
|
|
705
|
+
```bash
|
|
706
|
+
xcrun simctl openurl booted "https://your-deep-link-url/abc123"
|
|
707
|
+
```
|
|
954
708
|
|
|
955
|
-
|
|
709
|
+
**Test Deep Link (Android Emulator):**
|
|
956
710
|
|
|
957
|
-
|
|
711
|
+
```bash
|
|
712
|
+
adb shell am start -W -a android.intent.action.VIEW -d "https://your-deep-link-url/abc123"
|
|
713
|
+
```
|
|
958
714
|
|
|
715
|
+
**Check Stored Affiliate Identifier:**
|
|
959
716
|
|
|
960
|
-
### Integration Example
|
|
961
717
|
```javascript
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
import Purchases from 'react-native-purchases';
|
|
966
|
-
|
|
967
|
-
const PurchaseHandler = () => {
|
|
968
|
-
const { OfferCode } = useDeepLinkIapProvider();
|
|
969
|
-
const [subscriptions, setSubscriptions] = useState([]);
|
|
970
|
-
|
|
971
|
-
const fetchSubscriptions = async () => {
|
|
972
|
-
const offerings = await Purchases.getOfferings();
|
|
973
|
-
let packagesToUse = [];
|
|
974
|
-
|
|
975
|
-
if (OfferCode) {
|
|
976
|
-
|
|
718
|
+
const affiliateId = await returnInsertAffiliateIdentifier();
|
|
719
|
+
console.log('Current affiliate ID:', affiliateId);
|
|
720
|
+
```
|
|
977
721
|
|
|
978
|
-
|
|
979
|
-
const baseProducts = offerings.current.availablePackages;
|
|
722
|
+
### Common Setup Issues
|
|
980
723
|
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
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 |
|
|
984
730
|
|
|
985
|
-
|
|
986
|
-
const allOfferings = Object.values(offerings.all);
|
|
987
|
-
let foundModified = false;
|
|
731
|
+
---
|
|
988
732
|
|
|
989
|
-
|
|
990
|
-
const modifiedPackage = offering.availablePackages.find(pkg =>
|
|
991
|
-
pkg.product.identifier === modifiedProductId
|
|
992
|
-
);
|
|
733
|
+
## 🔧 Advanced Features
|
|
993
734
|
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
foundModified = true;
|
|
997
|
-
break;
|
|
998
|
-
}
|
|
999
|
-
}
|
|
735
|
+
<details>
|
|
736
|
+
<summary><h3>Event Tracking (Beta)</h3></summary>
|
|
1000
737
|
|
|
1001
|
-
|
|
1002
|
-
if (!foundModified) {
|
|
1003
|
-
packagesToUse.push(basePackage);
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
} else {
|
|
1007
|
-
packagesToUse = offerings.current.availablePackages;
|
|
1008
|
-
}
|
|
738
|
+
Track custom events beyond purchases (e.g., signups, referrals) to incentivize affiliates for specific actions.
|
|
1009
739
|
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
const handlePurchase = async (subscriptionPackage) => {
|
|
1014
|
-
try {
|
|
1015
|
-
await Purchases.purchasePackage(subscriptionPackage);
|
|
1016
|
-
} catch (error) {
|
|
1017
|
-
console.error('Purchase failed:', error);
|
|
1018
|
-
}
|
|
1019
|
-
};
|
|
1020
|
-
|
|
1021
|
-
useEffect(() => {
|
|
1022
|
-
fetchSubscriptions();
|
|
1023
|
-
}, [OfferCode]);
|
|
740
|
+
```javascript
|
|
741
|
+
const { trackEvent } = useDeepLinkIapProvider();
|
|
1024
742
|
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
{subscriptions.map((pkg) => (
|
|
1028
|
-
<Button
|
|
1029
|
-
key={pkg.identifier}
|
|
1030
|
-
title={`Buy: ${pkg.product.identifier}`}
|
|
1031
|
-
onPress={() => handlePurchase(pkg)}
|
|
1032
|
-
/>
|
|
1033
|
-
))}
|
|
1034
|
-
{OfferCode && (
|
|
1035
|
-
<Text>Special offer applied: {OfferCode}</Text>
|
|
1036
|
-
)}
|
|
1037
|
-
</View>
|
|
1038
|
-
);
|
|
1039
|
-
};
|
|
743
|
+
// Track custom event (affiliate identifier must be set first)
|
|
744
|
+
await trackEvent('user_signup');
|
|
1040
745
|
```
|
|
1041
|
-
---
|
|
1042
746
|
|
|
1043
|
-
|
|
747
|
+
**Use Cases:**
|
|
748
|
+
- Pay affiliates for signups instead of purchases
|
|
749
|
+
- Track trial starts, content unlocks, or other conversions
|
|
1044
750
|
|
|
1045
|
-
|
|
751
|
+
</details>
|
|
1046
752
|
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
import { View, Text, Button, Platform } from 'react-native';
|
|
1050
|
-
import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
|
|
1051
|
-
import {
|
|
1052
|
-
initConnection,
|
|
1053
|
-
getSubscriptions,
|
|
1054
|
-
requestSubscription,
|
|
1055
|
-
useIAP
|
|
1056
|
-
} from 'react-native-iap';
|
|
1057
|
-
|
|
1058
|
-
const NativeIAPPurchaseView = () => {
|
|
1059
|
-
const { OfferCode, returnUserAccountTokenAndStoreExpectedTransaction } = useDeepLinkIapProvider();
|
|
1060
|
-
const [availableProducts, setAvailableProducts] = useState([]);
|
|
1061
|
-
const [loading, setLoading] = useState(false);
|
|
1062
|
-
const { currentPurchase, connected } = useIAP();
|
|
1063
|
-
|
|
1064
|
-
const baseProductIdentifier = "oneMonthSubscription";
|
|
1065
|
-
|
|
1066
|
-
// Dynamic product identifier that includes offer code
|
|
1067
|
-
const dynamicProductIdentifier = OfferCode
|
|
1068
|
-
? `${baseProductIdentifier}${OfferCode}` // e.g., "oneMonthSubscription_oneWeekFree"
|
|
1069
|
-
: baseProductIdentifier;
|
|
1070
|
-
|
|
1071
|
-
const fetchProducts = async () => {
|
|
1072
|
-
try {
|
|
1073
|
-
setLoading(true);
|
|
1074
|
-
|
|
1075
|
-
// Try to fetch the dynamic product first
|
|
1076
|
-
let productIds = [dynamicProductIdentifier];
|
|
1077
|
-
|
|
1078
|
-
// Also include base product as fallback
|
|
1079
|
-
if (OfferCode) {
|
|
1080
|
-
productIds.push(baseProductIdentifier);
|
|
1081
|
-
}
|
|
1082
|
-
|
|
1083
|
-
const products = await getSubscriptions({ skus: productIds });
|
|
1084
|
-
|
|
1085
|
-
// Prioritize the dynamic product if it exists
|
|
1086
|
-
let sortedProducts = products;
|
|
1087
|
-
if (OfferCode && products.length > 1) {
|
|
1088
|
-
sortedProducts = products.sort((a, b) =>
|
|
1089
|
-
a.productId === dynamicProductIdentifier ? -1 : 1
|
|
1090
|
-
);
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
setAvailableProducts(sortedProducts);
|
|
1094
|
-
console.log(`Loaded products for: ${productIds.join(', ')}`);
|
|
1095
|
-
|
|
1096
|
-
} catch (error) {
|
|
1097
|
-
try {
|
|
1098
|
-
// Fallback logic
|
|
1099
|
-
const baseProducts = await getSubscriptions({ skus: [baseProductIdentifier] });
|
|
1100
|
-
setAvailableProducts(baseProducts);
|
|
1101
|
-
} catch (fallbackError) {
|
|
1102
|
-
console.error('Failed to fetch base products:', fallbackError);
|
|
1103
|
-
}
|
|
1104
|
-
} finally {
|
|
1105
|
-
setLoading(false);
|
|
1106
|
-
}
|
|
1107
|
-
};
|
|
753
|
+
<details>
|
|
754
|
+
<summary><h3>Short Codes</h3></summary>
|
|
1108
755
|
|
|
1109
|
-
|
|
1110
|
-
// Implement the purchase handling logic as outlined in the remaining SDK integration steps.
|
|
1111
|
-
};
|
|
756
|
+
Short codes are unique, 3-25 character alphanumeric identifiers that affiliates can share (e.g., "SAVE20" in a TikTok video description).
|
|
1112
757
|
|
|
1113
|
-
|
|
1114
|
-
if (connected) {
|
|
1115
|
-
fetchProducts();
|
|
1116
|
-
}
|
|
1117
|
-
}, [connected, OfferCode]);;
|
|
1118
|
-
|
|
1119
|
-
const primaryProduct = availableProducts[0];
|
|
758
|
+
**Validate and Store Short Code:**
|
|
1120
759
|
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
</Text>
|
|
1132
|
-
</View>
|
|
1133
|
-
)}
|
|
1134
|
-
|
|
1135
|
-
{loading ? (
|
|
1136
|
-
<Text>Loading products...</Text>
|
|
1137
|
-
) : primaryProduct ? (
|
|
1138
|
-
<View>
|
|
1139
|
-
<Text style={{ fontSize: 16, marginBottom: 5 }}>
|
|
1140
|
-
{primaryProduct.title}
|
|
1141
|
-
</Text>
|
|
1142
|
-
<Text style={{ fontSize: 14, color: '#666', marginBottom: 5 }}>
|
|
1143
|
-
Price: {primaryProduct.localizedPrice}
|
|
1144
|
-
</Text>
|
|
1145
|
-
<Text style={{ fontSize: 12, color: '#999', marginBottom: 15 }}>
|
|
1146
|
-
Product ID: {primaryProduct.productId}
|
|
1147
|
-
</Text>
|
|
1148
|
-
|
|
1149
|
-
<Button
|
|
1150
|
-
title={loading ? "Processing..." : "Subscribe Now"}
|
|
1151
|
-
onPress={() => handlePurchase(primaryProduct.productId)}
|
|
1152
|
-
disabled={loading}
|
|
1153
|
-
/>
|
|
1154
|
-
|
|
1155
|
-
{primaryProduct.productId === dynamicProductIdentifier && OfferCode && (
|
|
1156
|
-
<Text style={{ fontSize: 12, color: '#4caf50', marginTop: 10 }}>
|
|
1157
|
-
✓ Promotional pricing applied
|
|
1158
|
-
</Text>
|
|
1159
|
-
)}
|
|
1160
|
-
</View>
|
|
1161
|
-
) : (
|
|
1162
|
-
<View>
|
|
1163
|
-
<Text style={{ color: '#f44336', marginBottom: 10 }}>
|
|
1164
|
-
Product not found: {dynamicProductIdentifier}
|
|
1165
|
-
</Text>
|
|
1166
|
-
<Button
|
|
1167
|
-
title="Retry"
|
|
1168
|
-
onPress={fetchProducts}
|
|
1169
|
-
/>
|
|
1170
|
-
</View>
|
|
1171
|
-
)}
|
|
1172
|
-
|
|
1173
|
-
{availableProducts.length > 1 && (
|
|
1174
|
-
<View style={{ marginTop: 20 }}>
|
|
1175
|
-
<Text style={{ fontSize: 14, fontWeight: 'bold', marginBottom: 10 }}>
|
|
1176
|
-
Other Options:
|
|
1177
|
-
</Text>
|
|
1178
|
-
{availableProducts.slice(1).map((product) => (
|
|
1179
|
-
<Button
|
|
1180
|
-
key={product.productId}
|
|
1181
|
-
title={`${product.title} - ${product.localizedPrice}`}
|
|
1182
|
-
onPress={() => handlePurchase(product.productId)}
|
|
1183
|
-
/>
|
|
1184
|
-
))}
|
|
1185
|
-
</View>
|
|
1186
|
-
)}
|
|
1187
|
-
</View>
|
|
1188
|
-
);
|
|
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
|
+
}
|
|
1189
770
|
};
|
|
1190
771
|
```
|
|
1191
772
|
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
1. **Dynamic Product Loading**: Automatically constructs product IDs using the offer code modifier
|
|
1195
|
-
2. **Fallback Strategy**: If the promotional product isn't found, falls back to the base product
|
|
1196
|
-
3. **Visual Feedback**: Shows users when promotional pricing is applied
|
|
1197
|
-
4. **Error Handling**: Graceful handling when products aren't available
|
|
1198
|
-
|
|
773
|
+
**Get Affiliate Details Without Setting:**
|
|
1199
774
|
|
|
1200
|
-
|
|
775
|
+
```javascript
|
|
776
|
+
const { getAffiliateDetails } = useDeepLinkIapProvider();
|
|
1201
777
|
|
|
1202
|
-
|
|
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
|
+
```
|
|
1203
785
|
|
|
1204
|
-
|
|
786
|
+
Learn more: [Short Codes Documentation](https://docs.insertaffiliate.com/short-codes)
|
|
1205
787
|
|
|
1206
|
-
|
|
788
|
+
</details>
|
|
1207
789
|
|
|
1208
|
-
|
|
790
|
+
<details>
|
|
791
|
+
<summary><h3>Dynamic Offer Codes / Discounts</h3></summary>
|
|
1209
792
|
|
|
1210
|
-
|
|
793
|
+
Automatically apply discounts or trials when users come from specific affiliates.
|
|
1211
794
|
|
|
1212
|
-
|
|
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
|
|
1213
799
|
|
|
1214
|
-
|
|
1215
|
-
- Between **3-25 characters long**.
|
|
1216
|
-
- Contain only **letters, numbers, and underscores** (alphanumeric characters and underscores).
|
|
1217
|
-
- 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
|
|
800
|
+
**Quick Example:**
|
|
1218
801
|
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
- Returns `false` if the short code does not exist or validation failed
|
|
802
|
+
```javascript
|
|
803
|
+
const { OfferCode } = useDeepLinkIapProvider();
|
|
1222
804
|
|
|
1223
|
-
|
|
805
|
+
const baseProductId = "oneMonthSubscription";
|
|
806
|
+
const dynamicProductId = OfferCode
|
|
807
|
+
? `${baseProductId}${OfferCode}` // e.g., "oneMonthSubscription_oneWeekFree"
|
|
808
|
+
: baseProductId;
|
|
1224
809
|
|
|
1225
|
-
|
|
1226
|
-
import {
|
|
1227
|
-
DeepLinkIapProvider,
|
|
1228
|
-
} from 'insert-affiliate-react-native-sdk';
|
|
1229
|
-
|
|
1230
|
-
const {
|
|
1231
|
-
setShortCode,
|
|
1232
|
-
} = useDeepLinkIapProvider();
|
|
1233
|
-
|
|
1234
|
-
// Basic usage (without validation feedback)
|
|
1235
|
-
<Button
|
|
1236
|
-
title={'Set Short Code'}
|
|
1237
|
-
onPress={() => setShortCode('JOIN_123')}
|
|
1238
|
-
/>
|
|
1239
|
-
|
|
1240
|
-
// Recommended usage with validation feedback
|
|
1241
|
-
<Button
|
|
1242
|
-
title={'Set Short Code'}
|
|
1243
|
-
onPress={async () => {
|
|
1244
|
-
const isValid = await setShortCode('JOIN_123');
|
|
1245
|
-
if (isValid) {
|
|
1246
|
-
// Show success message to user
|
|
1247
|
-
Alert.alert('Success', 'Affiliate code applied successfully!');
|
|
1248
|
-
} else {
|
|
1249
|
-
// Show error message to user
|
|
1250
|
-
Alert.alert('Error', 'Invalid affiliate code. Please check and try again.');
|
|
1251
|
-
}
|
|
1252
|
-
}}
|
|
1253
|
-
/>
|
|
810
|
+
// Use dynamicProductId when fetching/purchasing products
|
|
1254
811
|
```
|
|
1255
812
|
|
|
1256
|
-
**
|
|
813
|
+
**[View complete Dynamic Offer Codes guide](docs/dynamic-offer-codes.md)**
|
|
1257
814
|
|
|
1258
|
-
|
|
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
|
|
1259
820
|
|
|
1260
|
-
|
|
821
|
+
</details>
|
|
1261
822
|
|
|
1262
|
-
|
|
823
|
+
<details>
|
|
824
|
+
<summary><h3>Attribution Timeout Control</h3></summary>
|
|
1263
825
|
|
|
1264
|
-
|
|
826
|
+
Control how long affiliate attribution remains active after a user clicks a link.
|
|
1265
827
|
|
|
1266
|
-
|
|
1267
|
-
const Child = () => {
|
|
1268
|
-
const { initialize, isInitialized } = useDeepLinkIapProvider();
|
|
828
|
+
**Set Timeout During Initialization:**
|
|
1269
829
|
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
);
|
|
1280
|
-
}
|
|
1281
|
-
}, [initialize, isInitialized]);
|
|
1282
|
-
}
|
|
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
|
+
);
|
|
1283
839
|
```
|
|
1284
840
|
|
|
1285
|
-
**
|
|
1286
|
-
- Set to a number in seconds to define how long affiliate attributions remain active
|
|
1287
|
-
- Set to `null` or omit to disable attribution timeout (attribution never expires)
|
|
1288
|
-
- Common values: 86400 (1 day), 604800 (7 days), 2592000 (30 days)
|
|
1289
|
-
|
|
1290
|
-
#### Common Timeout Values
|
|
841
|
+
**Check Attribution Validity:**
|
|
1291
842
|
|
|
1292
843
|
```javascript
|
|
1293
|
-
|
|
1294
|
-
initialize("your-company-code", false, false, false, 86400);
|
|
844
|
+
const { isAffiliateAttributionValid, getAffiliateStoredDate } = useDeepLinkIapProvider();
|
|
1295
845
|
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
// 30 days
|
|
1300
|
-
initialize("your-company-code", false, false, false, 2592000);
|
|
1301
|
-
|
|
1302
|
-
// No timeout (attribution never expires)
|
|
1303
|
-
initialize("your-company-code", false, false, false); // or pass null/undefined
|
|
846
|
+
const isValid = await isAffiliateAttributionValid();
|
|
847
|
+
const storedDate = await getAffiliateStoredDate();
|
|
1304
848
|
```
|
|
1305
849
|
|
|
1306
|
-
|
|
850
|
+
**Common Timeout Values:**
|
|
851
|
+
- 1 day: `86400`
|
|
852
|
+
- 7 days: `604800` (recommended)
|
|
853
|
+
- 30 days: `2592000`
|
|
854
|
+
- No timeout: omit parameter (default)
|
|
1307
855
|
|
|
1308
|
-
|
|
856
|
+
**Bypass Timeout Check:**
|
|
1309
857
|
|
|
1310
858
|
```javascript
|
|
1311
|
-
|
|
1312
|
-
returnInsertAffiliateIdentifier,
|
|
1313
|
-
isAffiliateAttributionValid,
|
|
1314
|
-
getAffiliateStoredDate
|
|
1315
|
-
} = useDeepLinkIapProvider();
|
|
1316
|
-
|
|
1317
|
-
// Get affiliate identifier (respects timeout)
|
|
1318
|
-
const identifier = await returnInsertAffiliateIdentifier();
|
|
1319
|
-
|
|
1320
|
-
// Get affiliate identifier ignoring timeout
|
|
859
|
+
// Get identifier even if attribution has expired
|
|
1321
860
|
const rawIdentifier = await returnInsertAffiliateIdentifier(true);
|
|
861
|
+
```
|
|
1322
862
|
|
|
1323
|
-
|
|
1324
|
-
const isValid = await isAffiliateAttributionValid();
|
|
863
|
+
</details>
|
|
1325
864
|
|
|
1326
|
-
|
|
1327
|
-
const storedDate = await getAffiliateStoredDate();
|
|
1328
|
-
```
|
|
865
|
+
---
|
|
1329
866
|
|
|
1330
|
-
|
|
867
|
+
## 🔍 Troubleshooting
|
|
1331
868
|
|
|
1332
|
-
|
|
1333
|
-
2. **Timeout Check**: When `returnInsertAffiliateIdentifier()` is called, the SDK checks if the stored attribution is still within the timeout window
|
|
1334
|
-
3. **Expired Attribution**: If the attribution has expired, the method returns `null` instead of the affiliate identifier
|
|
1335
|
-
4. **Bypass Option**: You can bypass the timeout check by passing `true` to `returnInsertAffiliateIdentifier(true)`
|
|
869
|
+
### Initialization Issues
|
|
1336
870
|
|
|
1337
|
-
|
|
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
|
|
1338
874
|
|
|
1339
|
-
###
|
|
875
|
+
### Deep Linking Issues
|
|
1340
876
|
|
|
1341
|
-
|
|
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
|
|
1342
882
|
|
|
1343
|
-
|
|
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
|
+
```
|
|
1344
892
|
|
|
1345
|
-
|
|
1346
|
-
getAffiliateDetails(affiliateCode: string): Promise<AffiliateDetails>
|
|
893
|
+
### Purchase Tracking Issues
|
|
1347
894
|
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
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
|
|
1354
901
|
|
|
1355
|
-
|
|
902
|
+
### Verbose Logging
|
|
1356
903
|
|
|
1357
|
-
|
|
1358
|
-
import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
|
|
1359
|
-
import type { AffiliateDetails } from 'insert-affiliate-react-native-sdk';
|
|
904
|
+
Enable detailed logs during development to diagnose issues:
|
|
1360
905
|
|
|
1361
|
-
|
|
1362
|
-
|
|
906
|
+
```javascript
|
|
907
|
+
initialize("YOUR_COMPANY_CODE", true); // second parameter enables verbose logging
|
|
908
|
+
```
|
|
1363
909
|
|
|
1364
|
-
|
|
1365
|
-
const details = await getAffiliateDetails(code);
|
|
910
|
+
**Important:** Disable verbose logging in production builds.
|
|
1366
911
|
|
|
1367
|
-
|
|
1368
|
-
console.log('Affiliate Name:', details.affiliateName);
|
|
1369
|
-
console.log('Short Code:', details.affiliateShortCode);
|
|
1370
|
-
console.log('Deep Link:', details.deeplinkurl);
|
|
912
|
+
### Getting Help
|
|
1371
913
|
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
`This code belongs to ${details.affiliateName}`
|
|
1376
|
-
);
|
|
1377
|
-
} else {
|
|
1378
|
-
console.log('Affiliate not found');
|
|
1379
|
-
Alert.alert('Error', 'Invalid affiliate code');
|
|
1380
|
-
}
|
|
1381
|
-
};
|
|
914
|
+
- [Documentation](https://docs.insertaffiliate.com)
|
|
915
|
+
- [Dashboard Support](https://app.insertaffiliate.com/help)
|
|
916
|
+
- [Report Issues](https://github.com/Insert-Affiliate/InsertAffiliateReactNativeSDK/issues)
|
|
1382
917
|
|
|
1383
|
-
|
|
1384
|
-
<View>
|
|
1385
|
-
<Button
|
|
1386
|
-
title="Get Affiliate Info"
|
|
1387
|
-
onPress={() => handleGetAffiliateInfo('JOIN_123')}
|
|
1388
|
-
/>
|
|
1389
|
-
</View>
|
|
1390
|
-
);
|
|
1391
|
-
};
|
|
1392
|
-
```
|
|
918
|
+
---
|
|
1393
919
|
|
|
1394
|
-
|
|
920
|
+
## 📚 Support
|
|
1395
921
|
|
|
1396
|
-
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
- Returns `null` if:
|
|
1401
|
-
- The affiliate code doesn't exist
|
|
1402
|
-
- The company code is not initialized
|
|
1403
|
-
- There's a network error or API issue
|
|
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)
|
|
1404
926
|
|
|
1405
|
-
|
|
927
|
+
---
|
|
1406
928
|
|
|
1407
|
-
|
|
1408
|
-
- Use `setShortCode()` to actually associate an affiliate with a user
|
|
1409
|
-
- The method automatically strips UUIDs from codes (e.g., "ABC123-uuid" becomes "ABC123")
|
|
1410
|
-
- Works with both short codes and deep link URLs
|
|
929
|
+
**Need help getting started?** Check out our [quickstart guide](https://docs.insertaffiliate.com) or [contact support](https://app.insertaffiliate.com/help).
|