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/dist/DeepLinkIapProvider.d.ts +7 -1
- package/dist/DeepLinkIapProvider.js +209 -17
- package/dist/index.d.ts +1 -1
- package/dist/useDeepLinkIapProvider.d.ts +2 -1
- package/dist/useDeepLinkIapProvider.js +2 -1
- 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 +600 -982
- package/src/DeepLinkIapProvider.tsx +256 -28
- package/src/index.ts +1 -1
- package/src/useDeepLinkIapProvider.tsx +2 -0
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
|
-
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
|
-
|
|
119
|
+
## ⚙️ Essential Setup
|
|
123
120
|
|
|
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
|
|
121
|
+
Complete these three required steps to start tracking affiliate-driven purchases.
|
|
130
122
|
|
|
131
|
-
|
|
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
|
-
|
|
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>
|
|
155
|
+
|
|
156
|
+
---
|
|
151
157
|
|
|
152
|
-
|
|
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)
|
|
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
|
-
|
|
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
|
-
|
|
367
|
+
</details>
|
|
399
368
|
|
|
400
|
-
|
|
369
|
+
<details>
|
|
370
|
+
<summary><h4>Option 4: App Store Direct</h4></summary>
|
|
401
371
|
|
|
402
|
-
|
|
372
|
+
**Step 1: Apple App Store Notification Setup**
|
|
403
373
|
|
|
404
|
-
|
|
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
|
-
|
|
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,741 +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
|
-
|
|
767
|
-
initAppsFlyer();
|
|
768
|
-
}, [setInsertAffiliateIdentifier, isInitialized]);
|
|
594
|
+
});
|
|
769
595
|
|
|
770
|
-
|
|
771
|
-
};
|
|
596
|
+
return () => setInsertAffiliateIdentifierChangeCallback(null);
|
|
597
|
+
}, []);
|
|
772
598
|
|
|
773
|
-
|
|
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
|
-
|
|
603
|
+
**Step 3: iOS Native Setup (Required)**
|
|
785
604
|
|
|
786
|
-
|
|
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
|
-
|
|
796
|
-
|
|
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
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
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
|
-
|
|
829
|
-
|
|
830
|
-
|
|
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
|
-
|
|
833
|
-
}, [setInsertAffiliateIdentifier, isInitialized]);
|
|
626
|
+
**Testing Deep Links:**
|
|
834
627
|
|
|
835
|
-
|
|
836
|
-
|
|
628
|
+
```bash
|
|
629
|
+
# iOS Simulator
|
|
630
|
+
xcrun simctl openurl booted "YOUR_IOS_URL_SCHEME://TEST_SHORT_CODE"
|
|
837
631
|
|
|
838
|
-
|
|
839
|
-
|
|
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
|
-
|
|
636
|
+
**Insert Links setup complete!** Skip to [Verify Your Integration](#-verify-your-integration)
|
|
848
637
|
|
|
849
|
-
|
|
638
|
+
</details>
|
|
850
639
|
|
|
851
|
-
|
|
852
|
-
|
|
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
|
-
|
|
643
|
+
Branch.io provides robust attribution and deferred deep linking capabilities.
|
|
857
644
|
|
|
858
|
-
|
|
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
|
-
|
|
651
|
+
**[View complete Branch.io integration guide](docs/deep-linking-branch.md)**
|
|
861
652
|
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
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
|
-
|
|
660
|
+
**After completing Branch setup**, skip to [Verify Your Integration](#-verify-your-integration)
|
|
883
661
|
|
|
884
|
-
|
|
662
|
+
</details>
|
|
885
663
|
|
|
886
|
-
|
|
664
|
+
<details>
|
|
665
|
+
<summary><h4>Option 3: AppsFlyer</h4></summary>
|
|
887
666
|
|
|
888
|
-
|
|
667
|
+
AppsFlyer provides enterprise-grade analytics and comprehensive attribution.
|
|
889
668
|
|
|
890
|
-
|
|
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
|
-
|
|
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
|
-
|
|
896
|
-
|
|
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
|
-
|
|
899
|
-
const { OfferCode } = useDeepLinkIapProvider();
|
|
900
|
-
```
|
|
685
|
+
**After completing AppsFlyer setup**, proceed to [Verify Your Integration](#-verify-your-integration)
|
|
901
686
|
|
|
902
|
-
|
|
687
|
+
</details>
|
|
903
688
|
|
|
904
|
-
|
|
689
|
+
---
|
|
905
690
|
|
|
906
|
-
|
|
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
|
-
|
|
693
|
+
Before going live, verify everything works correctly:
|
|
914
694
|
|
|
915
|
-
|
|
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
|
-
|
|
922
|
-
|
|
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
|
-
|
|
925
|
-
- Base product: `oneMonthSubscription`
|
|
926
|
-
- Promo product: `oneMonthSubscription-oneweekfree`
|
|
701
|
+
### Testing Commands
|
|
927
702
|
|
|
928
|
-
|
|
703
|
+
**Test Deep Link (iOS Simulator):**
|
|
929
704
|
|
|
930
|
-
|
|
705
|
+
```bash
|
|
706
|
+
xcrun simctl openurl booted "https://your-deep-link-url/abc123"
|
|
707
|
+
```
|
|
931
708
|
|
|
932
|
-
|
|
709
|
+
**Test Deep Link (Android Emulator):**
|
|
933
710
|
|
|
934
|
-
|
|
711
|
+
```bash
|
|
712
|
+
adb shell am start -W -a android.intent.action.VIEW -d "https://your-deep-link-url/abc123"
|
|
713
|
+
```
|
|
935
714
|
|
|
936
|
-
**
|
|
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
|
-
|
|
941
|
-
|
|
942
|
-
|
|
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
|
-
|
|
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
|
-
|
|
949
|
-
1. Create separate offerings:
|
|
950
|
-
- Base offering: `premium_monthly`
|
|
951
|
-
- Modified offering: `premium_monthly_oneWeekFree`
|
|
731
|
+
---
|
|
952
732
|
|
|
953
|
-
|
|
733
|
+
## 🔧 Advanced Features
|
|
954
734
|
|
|
955
|
-
|
|
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
|
-
|
|
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
|
-
|
|
966
|
-
|
|
967
|
-
|
|
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
|
-
|
|
974
|
-
|
|
747
|
+
**Use Cases:**
|
|
748
|
+
- Pay affiliates for signups instead of purchases
|
|
749
|
+
- Track trial starts, content unlocks, or other conversions
|
|
975
750
|
|
|
976
|
-
|
|
977
|
-
const baseProducts = offerings.current.availablePackages;
|
|
751
|
+
</details>
|
|
978
752
|
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
const modifiedProductId = `${baseProductId}_${OfferCode}`;
|
|
753
|
+
<details>
|
|
754
|
+
<summary><h3>Short Codes</h3></summary>
|
|
982
755
|
|
|
983
|
-
|
|
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
|
-
|
|
988
|
-
const modifiedPackage = offering.availablePackages.find(pkg =>
|
|
989
|
-
pkg.product.identifier === modifiedProductId
|
|
990
|
-
);
|
|
758
|
+
**Validate and Store Short Code:**
|
|
991
759
|
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1009
|
-
|
|
775
|
+
```javascript
|
|
776
|
+
const { getAffiliateDetails } = useDeepLinkIapProvider();
|
|
1010
777
|
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
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
|
-
|
|
1020
|
-
fetchSubscriptions();
|
|
1021
|
-
}, [OfferCode]);
|
|
786
|
+
Learn more: [Short Codes Documentation](https://docs.insertaffiliate.com/short-codes)
|
|
1022
787
|
|
|
1023
|
-
|
|
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
|
-
|
|
790
|
+
<details>
|
|
791
|
+
<summary><h3>Dynamic Offer Codes / Discounts</h3></summary>
|
|
1042
792
|
|
|
1043
|
-
|
|
793
|
+
Automatically apply discounts or trials when users come from specific affiliates.
|
|
1044
794
|
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
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
|
-
|
|
1108
|
-
// Implement the purchase handling logic as outlined in the remaining SDK integration steps.
|
|
1109
|
-
};
|
|
800
|
+
**Quick Example:**
|
|
1110
801
|
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
fetchProducts();
|
|
1114
|
-
}
|
|
1115
|
-
}, [connected, OfferCode]);;
|
|
802
|
+
```javascript
|
|
803
|
+
const { OfferCode } = useDeepLinkIapProvider();
|
|
1116
804
|
|
|
1117
|
-
|
|
805
|
+
const baseProductId = "oneMonthSubscription";
|
|
806
|
+
const dynamicProductId = OfferCode
|
|
807
|
+
? `${baseProductId}${OfferCode}` // e.g., "oneMonthSubscription_oneWeekFree"
|
|
808
|
+
: baseProductId;
|
|
1118
809
|
|
|
1119
|
-
|
|
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
|
-
|
|
813
|
+
**[View complete Dynamic Offer Codes guide](docs/dynamic-offer-codes.md)**
|
|
1191
814
|
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
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
|
-
|
|
823
|
+
<details>
|
|
824
|
+
<summary><h3>Attribution Timeout Control</h3></summary>
|
|
1199
825
|
|
|
1200
|
-
|
|
826
|
+
Control how long affiliate attribution remains active after a user clicks a link.
|
|
1201
827
|
|
|
1202
|
-
|
|
828
|
+
**Set Timeout During Initialization:**
|
|
1203
829
|
|
|
1204
|
-
|
|
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
|
-
|
|
841
|
+
**Check Attribution Validity:**
|
|
1207
842
|
|
|
1208
|
-
|
|
843
|
+
```javascript
|
|
844
|
+
const { isAffiliateAttributionValid, getAffiliateStoredDate } = useDeepLinkIapProvider();
|
|
1209
845
|
|
|
1210
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1219
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1237
|
-
|
|
1238
|
-
When initializing the SDK, you can specify the attribution timeout in seconds:
|
|
865
|
+
---
|
|
1239
866
|
|
|
1240
|
-
|
|
1241
|
-
const Child = () => {
|
|
1242
|
-
const { initialize, isInitialized } = useDeepLinkIapProvider();
|
|
867
|
+
## 🔍 Troubleshooting
|
|
1243
868
|
|
|
1244
|
-
|
|
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
|
-
**
|
|
1260
|
-
-
|
|
1261
|
-
-
|
|
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
|
-
|
|
875
|
+
### Deep Linking Issues
|
|
1265
876
|
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
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
|
-
|
|
1271
|
-
|
|
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
|
-
|
|
1274
|
-
initialize("your-company-code", false, false, false, 2592000);
|
|
893
|
+
### Purchase Tracking Issues
|
|
1275
894
|
|
|
1276
|
-
|
|
1277
|
-
|
|
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
|
-
|
|
902
|
+
### Verbose Logging
|
|
1281
903
|
|
|
1282
|
-
|
|
904
|
+
Enable detailed logs during development to diagnose issues:
|
|
1283
905
|
|
|
1284
906
|
```javascript
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
isAffiliateAttributionValid,
|
|
1288
|
-
getAffiliateStoredDate
|
|
1289
|
-
} = useDeepLinkIapProvider();
|
|
907
|
+
initialize("YOUR_COMPANY_CODE", true); // second parameter enables verbose logging
|
|
908
|
+
```
|
|
1290
909
|
|
|
1291
|
-
|
|
1292
|
-
const identifier = await returnInsertAffiliateIdentifier();
|
|
910
|
+
**Important:** Disable verbose logging in production builds.
|
|
1293
911
|
|
|
1294
|
-
|
|
1295
|
-
const rawIdentifier = await returnInsertAffiliateIdentifier(true);
|
|
912
|
+
### Getting Help
|
|
1296
913
|
|
|
1297
|
-
|
|
1298
|
-
|
|
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
|
-
|
|
1301
|
-
const storedDate = await getAffiliateStoredDate();
|
|
1302
|
-
```
|
|
918
|
+
---
|
|
1303
919
|
|
|
1304
|
-
|
|
920
|
+
## 📚 Support
|
|
1305
921
|
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
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
|
-
|
|
929
|
+
**Need help getting started?** Check out our [quickstart guide](https://docs.insertaffiliate.com) or [contact support](https://app.insertaffiliate.com/help).
|