The official Android SDK for Insert Affiliate - track affiliate-driven in-app purchases and reward your partners automatically.
What does this SDK do? It connects your Android 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.
- Quick Start (5 Minutes)
- Essential Setup
- Verify Your Integration
- Advanced Features
- Troubleshooting
- Support
Get up and running with minimal code to validate the SDK works before tackling IAP and deep linking setup.
- Android 5.0+ (API level 21 or higher)
- Android Gradle Plugin 8.1+ and Gradle 8.0+
- Company Code from your Insert Affiliate dashboard
Step 1: Add JitPack repository to your root build.gradle:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
}
}Step 2: Add the SDK dependency to your module's build.gradle:
dependencies {
implementation 'com.github.Insert-Affiliate:InsertAffiliateAndroidSDK:v1.2.0'
}Add this minimal code to your MainActivity.java to test the SDK:
import com.aks.insertaffiliateandroid.InsertAffiliateManager;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initialize SDK with verbose logging (recommended during setup)
InsertAffiliateManager.init(
this,
"YOUR_COMPANY_CODE", // Get from https://app.insertaffiliate.com/settings
true // Enable verbose logging for setup
);
}
}Expected Console Output:
When the SDK initializes successfully, you'll see these logs:
I/InsertAffiliate TAG: [Insert Affiliate] [VERBOSE] Starting SDK initialization...
I/InsertAffiliate TAG: [Insert Affiliate] [VERBOSE] Company code provided: Yes
I/InsertAffiliate TAG: [Insert Affiliate] [VERBOSE] Verbose logging enabled
I/InsertAffiliate TAG: [Insert Affiliate] SDK initialized with company code: YOUR_COMPANY_CODE
I/InsertAffiliate TAG: [Insert Affiliate] [VERBOSE] Generated and saved new user ID: a1b2c3
I/InsertAffiliate TAG: [Insert Affiliate] [VERBOSE] SDK initialization completed
β If you see these logs, the SDK is working! Now proceed to Essential Setup below.
false or omitting it.
Complete these three required steps to start tracking affiliate-driven purchases.
The SDK must be initialized in your MainActivity before using any features. You've already done the basic initialization above, but here are additional options:
// Minimal setup with verbose logging enabled (recommended during development)
InsertAffiliateManager.init(this, "YOUR_COMPANY_CODE", true);Advanced Initialization Options (click to expand)
// With Insert Links enabled (for Insert Affiliate's built-in deep linking)
InsertAffiliateManager.init(
this, // Activity context
"YOUR_COMPANY_CODE", // Your company code
true, // Enable verbose logging
true // Enable Insert Links (includes install referrer)
);
// With attribution timeout (7 days = 604800 seconds)
InsertAffiliateManager.init(
this,
"YOUR_COMPANY_CODE",
true, // Enable verbose logging
false, // Insert Links disabled (if using 3rd party like Branch)
604800 // Attribution expires after 7 days
);
// With affiliate transfer prevention (prevents new affiliates from overwriting existing)
InsertAffiliateManager.init(
this,
"YOUR_COMPANY_CODE",
true, // Enable verbose logging
false, // Insert Links disabled
604800, // Attribution expires after 7 days
true // Prevent affiliate transfer
);Parameters:
enableVerboseLogging: Shows detailed logs for debugging (disable in production)enableInsertLinks: Set totrueif using Insert Links,falseif using Branch/AppsFlyeraffiliateAttributionActiveTimeSeconds: How long affiliate attribution lasts (0 = never expires)preventAffiliateTransfer: Whentrue, the first affiliate is locked and new affiliate links won't overwrite existing attribution
Insert Affiliate requires a receipt verification method to validate purchases. Choose ONE of the following:
| Method | Best For | Setup Time | Complexity |
|---|---|---|---|
| RevenueCat | Most developers, managed infrastructure | ~10 min | β Simple |
| Adapty | Paywall A/B testing, analytics | ~10 min | β Simple |
| Google Play Direct | Cost-focused users, no 3rd party fees | ~15 min | ββ Medium |
| Iaptic | Custom requirements, direct control | ~20 min | βββ Advanced |
Step 1: Code Setup
Complete the RevenueCat Android SDK installation first, then modify your MainActivity.java:
import com.revenuecat.purchases.Purchases;
import com.aks.insertaffiliateandroid.InsertAffiliateManager;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initialize Insert Affiliate SDK with 7-day attribution timeout
InsertAffiliateManager.init(this, "YOUR_COMPANY_CODE", true, false, 604800);
// Set up callback for affiliate identifier changes (now includes offer code)
InsertAffiliateManager.setInsertAffiliateIdentifierChangeCallback(
this,
(identifier, offerCode) -> {
if (identifier != null) {
updateRevenueCatAttribution(identifier, offerCode);
}
}
);
}
private void updateRevenueCatAttribution(String affiliateId, String offerCode) {
// OPTIONAL: Prevent attribution for existing subscribers
// Uncomment to ensure affiliates only earn from users they actually brought:
/*
Purchases.getSharedInstance().getCustomerInfo(new ReceiveCustomerInfoCallback() {
@Override
public void onReceived(@NonNull CustomerInfo customerInfo) {
if (!customerInfo.getEntitlements().getActive().isEmpty()) {
// User already subscribed, don't attribute to this affiliate
return;
}
// Continue with attribution below...
}
@Override
public void onError(@NonNull PurchasesError error) { }
});
*/
// Set main attributes
Map<String, String> attributes = new HashMap<>();
attributes.put("insert_affiliate", affiliateId);
// Add expiry timestamp for RevenueCat targeting rules
Long expiryTimestamp = InsertAffiliateManager.getAffiliateExpiryTimestamp(this);
if (expiryTimestamp != null) {
attributes.put("insert_timedout", String.valueOf(expiryTimestamp));
}
Purchases.getSharedInstance().setAttributes(attributes);
// IMPORTANT: Set affiliateOfferCode in a SEPARATE call for targeting to work reliably
if (offerCode != null && !offerCode.isEmpty()) {
Map<String, String> offerCodeAttr = new HashMap<>();
offerCodeAttr.put("affiliateOfferCode", offerCode);
Purchases.getSharedInstance().setAttributes(offerCodeAttr);
}
// Sync attributes AND reload offerings for targeting to work
Purchases.getSharedInstance().syncAttributesAndOfferingsIfNeededWith(
error -> Log.e("MainActivity", "Sync error: " + error.getMessage()),
offerings -> {
// Offerings now reflect targeting based on affiliateOfferCode
Log.d("MainActivity", "RevenueCat synced, current offering: " +
(offerings.getCurrent() != null ? offerings.getCurrent().getIdentifier() : "null"));
}
);
}
}Expected Console Output:
I/InsertAffiliate TAG: [Insert Affiliate] SDK initialized with company code: YOUR_COMPANY_CODE
I/InsertAffiliate TAG: [Insert Affiliate] [VERBOSE] Found identifier: SHORTCODE-a1b2c3
Step 2: Webhook Setup
- In RevenueCat, create a new webhook
- Configure webhook settings:
- Webhook URL:
https://api.insertaffiliate.com/v1/api/revenuecat-webhook - Event Type: "All events"
- Webhook URL:
- In your Insert Affiliate dashboard:
- Set In-App Purchase Verification to
RevenueCat - Copy the
RevenueCat Webhook Authentication Headervalue
- Set In-App Purchase Verification to
- Back in RevenueCat webhook config:
- Paste the authentication header value into the Authorization header field
β RevenueCat setup complete! Now skip to Step 3: Set Up Deep Linking
Step 1: Add Adapty Dependency
Add Adapty to your module's build.gradle:
dependencies {
implementation 'io.adapty:android-sdk:3.3.0'
implementation 'io.adapty:android-ui:3.3.0'
}Step 2: Initialize Adapty
In your Application class (e.g., MyApp.java):
import android.app.Application;
import com.adapty.Adapty;
import com.adapty.models.AdaptyConfig;
import com.adapty.utils.AdaptyLogLevel;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
public class MyApp extends Application {
// Track Adapty activation state to prevent double activation and fix race conditions
private static final CountDownLatch adaptyActivationLatch = new CountDownLatch(1);
private static final AtomicBoolean adaptyActivated = new AtomicBoolean(false);
@Override
public void onCreate() {
super.onCreate();
// Set log level before activation (optional)
Adapty.setLogLevel(AdaptyLogLevel.VERBOSE);
// Initialize Adapty with protection against double activation
if (adaptyActivated.compareAndSet(false, true)) {
Adapty.activate(
getApplicationContext(),
new AdaptyConfig.Builder("YOUR_ADAPTY_PUBLIC_KEY").build(),
(AdaptyProfile profile) -> {
adaptyActivationLatch.countDown(); // Signal activation complete
}
);
}
}
// Call this method to wait for Adapty activation before updating profile
public static void waitForAdaptyActivation() {
try {
adaptyActivationLatch.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}Step 3: Code Setup
In your MainActivity.java:
import com.adapty.Adapty;
import com.adapty.models.AdaptyProfileParameters;
import com.aks.insertaffiliateandroid.InsertAffiliateManager;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initialize Insert Affiliate SDK
InsertAffiliateManager.init(this, "YOUR_COMPANY_CODE", true);
// Set up callback for affiliate identifier changes - update Adapty when identifier changes
InsertAffiliateManager.setInsertAffiliateIdentifierChangeCallback(
this,
new InsertAffiliateManager.InsertAffiliateIdentifierChangeCallback() {
@Override
public void onIdentifierChanged(String identifier, String offerCode) {
if (identifier != null && !identifier.isEmpty()) {
updateAdaptyProfile(identifier);
}
}
}
);
}
private void updateAdaptyProfile(String affiliateId) {
// Run on background thread to avoid blocking UI while waiting for Adapty
new Thread(() -> {
// Wait for Adapty activation before updating profile
MyApp.waitForAdaptyActivation();
AdaptyProfileParameters.Builder builder = new AdaptyProfileParameters.Builder()
.withCustomAttribute("insert_affiliate", affiliateId);
Adapty.updateProfile(builder.build(), error -> {
if (error != null) {
Log.e("MainActivity", "Failed to update Adapty profile: " + error.getMessage());
} else {
Log.d("MainActivity", "Adapty profile updated with insert_affiliate: " + affiliateId);
}
});
}).start();
}
}Expected Console Output:
D/MainActivity: Adapty profile updated with insert_affiliate: SHORTCODE-a1b2c3
Step 4: Webhook Setup
-
In your Insert Affiliate dashboard:
- Set In-App Purchase Verification to
Adapty - Copy the Adapty Webhook URL
- Copy the Adapty Webhook Authorization Header value
- Set In-App Purchase Verification to
-
In the Adapty Dashboard:
- Navigate to Integrations β Webhooks
- Set Production URL to the webhook URL from Insert Affiliate
- Set Sandbox URL to the same webhook URL
- Paste the authorization header value into Authorization header value
- Enable these options:
- Exclude historical events
- Send attribution
- Send trial price
- Send user attributes
- Save the configuration
Step 5: Verify Integration
To confirm the affiliate identifier is set correctly:
- Go to app.adapty.io/profiles/users
- Find the test user who made a purchase
- Look for
insert_affiliatein Custom attributes with format:{SHORT_CODE}-{UUID}
β Adapty setup complete! Now skip to Step 3: Set Up Deep Linking
Step 1: RTDN Setup
Complete the Real Time Developer Notifications setup in the Insert Affiliate documentation.
Step 2: Code Implementation
import com.aks.insertaffiliateandroid.InsertAffiliateManager;
public class InAppFragment extends Fragment {
@Override
public void onProductsPurchased(@NonNull List<PurchaseInfo> purchases) {
for (PurchaseInfo purchase : purchases) {
purchasedInfoList.add(purchase);
// Store expected transaction for backend validation
InsertAffiliateManager.storeExpectedPlayStoreTransaction(
getActivity(),
purchase.getPurchaseToken()
);
}
}
}Expected Console Output:
I/InsertAffiliate TAG: [Insert Affiliate] Storing expected transaction: {"UUID":"token123...","companyCode":"YOUR_CODE","shortCode":"AFFILIATE1","storedDate":"2025-11-24T10:30:00Z"}
I/InsertAffiliate TAG: [Insert Affiliate] Expected transaction stored successfully.
β Google Play Direct setup complete! Now proceed to Step 3: Set Up Deep Linking
Step 1: Code Setup
Install the Google In-App Billing Library (or your preferred billing library), then add this to your purchase handling code:
import com.aks.insertaffiliateandroid.InsertAffiliateManager;
public class InAppFragment extends Fragment {
InsertAffiliateManager insertAffiliateManager;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
insertAffiliateManager = new InsertAffiliateManager(getActivity());
return view;
}
@Override
public void onProductsPurchased(@NonNull List<PurchaseInfo> purchases) {
for (PurchaseInfo purchase : purchases) {
// Validate purchase with Iaptic via Insert Affiliate SDK
insertAffiliateManager.validatePurchaseWithIapticAPI(
getActivity(),
"YOUR_IAPTIC_APP_NAME", // From https://www.iaptic.com/account
"YOUR_IAPTIC_PUBLIC_KEY", // From https://www.iaptic.com/settings
purchase.getProduct(),
purchase.getOrderId(),
purchase.getPurchaseToken(),
purchase.getOriginalJson(),
purchase.getSignature()
);
}
}
}Step 2: Webhook Setup
- In your Insert Affiliate dashboard settings:
- Set In-App Purchase Verification to
Iaptic - Copy both
Iaptic Webhook URLandIaptic Webhook Sandbox URL
- Set In-App Purchase Verification to
- In your Iaptic Settings:
- Paste the webhook URLs into
Webhook URLandSandbox Webhook URLfields - Click Save Settings
- Paste the webhook URLs into
- Complete the Iaptic Google Play Notifications setup
β Iaptic setup complete! Now proceed to Step 3: Set Up Deep Linking
Deep linking lets affiliates share unique links that track users to your app. Choose ONE deep linking provider:
| Provider | Best For | Complexity | Setup Guide |
|---|---|---|---|
| Insert Links | Simple setup, no 3rd party | β Simple | View |
| Branch.io | Robust attribution, deferred deep linking | ββ Medium | View |
| AppsFlyer | Enterprise analytics, comprehensive attribution | ββ Medium | View |
Insert Links is Insert Affiliate's built-in deep linking solutionβno third-party SDK required.
Prerequisites:
- Complete the Insert Links setup in the Insert Affiliate dashboard
Code Implementation:
Choose the example that matches your IAP verification platform:
With RevenueCat:
import com.aks.insertaffiliateandroid.InsertAffiliateManager;
import com.revenuecat.purchases.Purchases;
import android.content.Intent;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initialize SDK with Insert Links enabled
InsertAffiliateManager.init(
this,
"YOUR_COMPANY_CODE",
true, // Verbose logging
true // Enable Insert Links
);
// Set up callback for affiliate identifier changes (now includes offer code)
InsertAffiliateManager.setInsertAffiliateIdentifierChangeCallback(
this,
(identifier, offerCode) -> {
if (identifier != null) {
// OPTIONAL: Check if user already has active subscription
// Uncomment to prevent affiliates earning from existing subscribers:
// Purchases.getSharedInstance().getCustomerInfo(info -> {
// if (!info.getEntitlements().getActive().isEmpty()) return;
// // Continue with attribution...
// });
Map<String, String> attributes = new HashMap<>();
attributes.put("insert_affiliate", identifier);
Purchases.getSharedInstance().setAttributes(attributes);
// Set affiliateOfferCode separately for targeting
if (offerCode != null && !offerCode.isEmpty()) {
Map<String, String> offerCodeAttr = new HashMap<>();
offerCodeAttr.put("affiliateOfferCode", offerCode);
Purchases.getSharedInstance().setAttributes(offerCodeAttr);
}
Purchases.getSharedInstance().syncAttributesAndOfferingsIfNeededWith(
error -> { /* handle error */ },
offerings -> { /* offerings synced with targeting */ }
);
}
}
);
// Handle deep link from app launch
InsertAffiliateManager.handleInsertLink(this, getIntent());
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
InsertAffiliateManager.handleInsertLink(this, intent);
}
}With Adapty:
import com.aks.insertaffiliateandroid.InsertAffiliateManager;
import com.adapty.Adapty;
import com.adapty.models.AdaptyProfileParameters;
import android.content.Intent;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initialize SDK with Insert Links enabled
InsertAffiliateManager.init(
this,
"YOUR_COMPANY_CODE",
true, // Verbose logging
true // Enable Insert Links
);
// Set up callback for affiliate identifier changes (now includes offer code)
InsertAffiliateManager.setInsertAffiliateIdentifierChangeCallback(
this,
(identifier, offerCode) -> {
if (identifier != null && !identifier.isEmpty()) {
updateAdaptyProfile(identifier);
}
}
);
// Handle deep link from app launch
InsertAffiliateManager.handleInsertLink(this, getIntent());
}
private void updateAdaptyProfile(String affiliateId) {
AdaptyProfileParameters.Builder builder = new AdaptyProfileParameters.Builder()
.withCustomAttribute("insert_affiliate", affiliateId);
Adapty.updateProfile(builder.build(), error -> {
if (error != null) {
Log.e("MainActivity", "Failed to update Adapty: " + error.getMessage());
} else {
Log.d("MainActivity", "Adapty updated with: " + affiliateId);
}
});
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
InsertAffiliateManager.handleInsertLink(this, intent);
}
}With Google Play Direct or Iaptic:
import com.aks.insertaffiliateandroid.InsertAffiliateManager;
import android.content.Intent;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initialize SDK with Insert Links enabled
InsertAffiliateManager.init(
this,
"YOUR_COMPANY_CODE",
true, // Verbose logging
true // Enable Insert Links
);
// Set up callback for affiliate identifier changes (now includes offer code)
InsertAffiliateManager.setInsertAffiliateIdentifierChangeCallback(
this,
(identifier, offerCode) -> {
Log.i("InsertAffiliate", "Affiliate identifier stored: " + identifier + ", offerCode: " + offerCode);
// Identifier is stored automatically for direct store integration
}
);
// Handle deep link from app launch
InsertAffiliateManager.handleInsertLink(this, getIntent());
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
InsertAffiliateManager.handleInsertLink(this, intent);
}
}Expected Console Output:
I/InsertAffiliate TAG: [Insert Affiliate] [VERBOSE] Insert links enabled: true
I/InsertAffiliate TAG: [Insert Affiliate] Deep link detected with insertAffiliate parameter: AFFILIATE1
I/InsertAffiliate TAG: [Insert Affiliate] Setting affiliate identifier.
I/InsertAffiliate TAG: [Insert Affiliate] Short link received: AFFILIATE1
I/InsertAffiliate TAG: [Insert Affiliate] Storing affiliate identifier: AFFILIATE1
Android App Links provide a better user experience than custom URL schemes. When a user taps an Insert Link and already has your app installed, Android opens the app directly β without loading the browser or showing a disambiguation dialog.
Prerequisites:
- Enter your Android Bundle Identifier (package name) and SHA-256 Certificate Fingerprints in the Insert Affiliate dashboard settings
To find your SHA-256 fingerprint:
# For debug builds
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android | grep SHA256
# For release builds (use your keystore)
keytool -list -v -keystore your-release-key.keystore -alias your-alias | grep SHA256Step 1: Add intent filter to AndroidManifest.xml
Add this inside your main <activity> tag:
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="insertaffiliate.link" />
</intent-filter>If you have a custom domain (e.g. links.yourcompany.com), add another intent filter:
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="links.yourcompany.com" />
</intent-filter>Step 2: Set launch mode on your Activity
Add android:launchMode="singleTop" to your main activity to prevent it being recreated when an App Link is tapped while the app is already running:
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
...>This ensures onNewIntent() is called instead of creating a new activity instance. Without this, the activity will "flash" and reload, potentially losing the deep link data.
Step 3: Handle App Links in your Activity
No additional code changes needed β handleInsertLink() already handles both custom URL schemes and https:// App Links automatically. Just make sure you call it from both onCreate() and onNewIntent().
Testing App Links:
# Via ADB
adb shell am start -a android.intent.action.VIEW -d "https://insertaffiliate.link/YOUR_COMPANY_CODE/TEST_SHORT_CODE"Note: App Links verification requires the app to be signed with the certificate matching the fingerprint in the dashboard. Debug builds use a different certificate than release builds β add both fingerprints if testing in debug mode.
β Insert Links setup complete! Skip to Verify Your Integration
Branch.io provides robust attribution and deferred deep linking capabilities.
Key Integration Steps:
- Install and configure Branch SDK for Android
- Extract
~referring_linkfrom Branch callback - Pass to Insert Affiliate SDK using
setInsertAffiliateIdentifier()
π View complete Branch.io integration guide β
β After completing Branch setup, skip to Verify Your Integration
AppsFlyer provides enterprise-grade analytics and comprehensive attribution.
Key Integration Steps:
- Install and configure AppsFlyer SDK for Android
- Create AppsFlyer OneLink in dashboard
- Extract deep link from
onAppOpenAttribution()callback - Pass to Insert Affiliate SDK using
setInsertAffiliateIdentifier()
π View complete AppsFlyer integration guide β
β After completing AppsFlyer setup, proceed to Verify Your Integration
Before going live, verify everything works correctly:
- SDK Initializes: Check console for
SDK initialized with company codelog - Affiliate Identifier Stored: Click a test affiliate link and verify console shows
Storing affiliate identifier: [CODE] - Purchase Tracked: Make a test purchase and verify transaction is sent to Insert Affiliate
Test Deep Link (via ADB):
# Replace with your actual deep link URL
adb shell am start -a android.intent.action.VIEW -d "https://your-app.onelink.me/abc123"Check Stored Affiliate Identifier:
String affiliateId = InsertAffiliateManager.returnInsertAffiliateIdentifier(this);
Log.d("Test", "Current affiliate ID: " + affiliateId);Expected Output: Current affiliate ID: AFFILIATE1-a1b2c3
| Issue | Solution |
|---|---|
| "Company code is not set" | Ensure init() is called before any other SDK methods |
| "No affiliate identifier found" | User must click an affiliate link before making a purchase |
| Deep link opens browser instead of app | Verify intent filters in AndroidManifest.xml and SHA-256 certificate |
| Purchase not tracked | Check webhook configuration in IAP verification platform |
Track custom events beyond purchases (e.g., signups, referrals) to incentivize affiliates for specific actions.
// Track custom event (affiliate identifier must be set first)
InsertAffiliateManager.trackEvent(this, "user_signup");Expected Console Output:
I/InsertAffiliate TAG: [Insert Affiliate] Event tracked successfully
Use Cases:
- Pay affiliates for signups instead of purchases
- Track trial starts, content unlocks, or other conversions
Short codes are 3-25 character alphanumeric codes affiliates can share (e.g., "SAVE20" in a TikTok video description).
Validate and Store Short Code:
InsertAffiliateManager.setShortCode(this, "SAVE20", new InsertAffiliateManager.ShortCodeValidationCallback() {
@Override
public void onValidationComplete(boolean isValid) {
if (isValid) {
Log.i("MyApp", "Short code is valid!");
// Show success message to user
} else {
Log.e("MyApp", "Invalid short code");
// Show error message
}
}
});Get Affiliate Details Without Setting:
InsertAffiliateManager.getAffiliateDetails("SAVE20", new InsertAffiliateManager.AffiliateDetailsCallback() {
@Override
public void onAffiliateDetailsReceived(InsertAffiliateManager.AffiliateDetails details) {
if (details != null) {
Log.i("MyApp", "Affiliate: " + details.getAffiliateName());
// Display affiliate info to user
}
}
});Learn more: Short Codes Documentation
Automatically apply discounts or trials when users come from specific affiliates.
How It Works:
- Configure an offer code modifier in your Insert Affiliate dashboard (e.g.,
-oneweekfree) - SDK automatically fetches and stores the modifier when affiliate identifier is set
- Use the modifier to construct dynamic product IDs
Quick Example:
String offerCode = InsertAffiliateManager.getStoredOfferCode(this);
if (offerCode != null) {
// Construct dynamic product ID
String productId = "oneMonthSubscription" + offerCode;
// Result: "oneMonthSubscription-oneweekfree"
}π View complete Dynamic Offer Codes guide β
Includes full examples for:
- Google Play Console setup (multiple products, base plans, developer offers)
- Google Play Billing integration with automatic product selection
- RevenueCat integration with dynamic offerings
- Testing and troubleshooting
Control how long affiliate attribution remains active after a user clicks a link (e.g., 7-day attribution window).
Set Timeout During Initialization:
// 7-day attribution window (604800 seconds)
InsertAffiliateManager.init(this, "YOUR_COMPANY_CODE", false, false, 604800);Check Attribution Validity:
boolean isValid = InsertAffiliateManager.isAffiliateAttributionValid(this);
if (isValid) {
// Attribution is still active
} else {
// Attribution expired
}Common Timeout Values:
- 1 day:
86400 - 7 days:
604800(recommended) - 30 days:
2592000 - No timeout:
0(default)
Get Attribution Date:
long storedDate = InsertAffiliateManager.getAffiliateStoredDate(this);
// Returns seconds since epochGet Expiry Timestamp (for RevenueCat targeting):
Long expiryTimestamp = InsertAffiliateManager.getAffiliateExpiryTimestamp(this);
// Returns Unix timestamp in milliseconds when attribution expires
// Returns null if no timeout configured or no affiliate existsTurn your own users into affiliates from inside your app, show them a ready-made "Refer a friend" screen, and read their referral stats so you can reward them.
In-app referrers are normal affiliates: they get the same dashboard login, commission and payouts as any other affiliate, and they take a seat like any other affiliate.
Before you start: switch on In-app referrals in your Insert Affiliate dashboard and choose what counts as a referral (install, a tracked event, or a purchase). Initialise the SDK with InsertAffiliateManager.init(...) as usual.
Drop-in screen (quickest):
InsertAffiliateManager.showReferAFriend(this, new ReferAFriendOptions()
.setEmail(currentUser.getEmail()) // prefill, usually your logged-in user
.setName(currentUser.getName())
.setOnClose(() -> Log.i("MyApp", "Refer a friend closed")));The screen handles everything itself:
- Not joined yet: email and name fields (prefilled) and a "Get my link" button.
- Email already belongs to an affiliate (for example after a reinstall or on a new phone, unless Auto Backup restored the connection): asks for the 6-digit code we email them, with "Send a new code".
- Joined: their code and link with Copy buttons, a Share button (system share sheet), their referral count and earnings, "Free premium until {date}" while a referrer reward is active, "Your rewards" with any Google Play promo codes (Copy and Redeem), and "Open my dashboard".
Headline, reward text and colour come from your dashboard, so you can change the wording without an app release. You can override them in code:
| Option | Description |
|---|---|
setEmail(String) / setName(String) |
Prefill the join form |
setShareMessage(String) |
Text shared with the link. May use {link} and {code} placeholders |
setPrimaryColor(int) / setPrimaryColor(String) |
Button colour. Order: this option, then your dashboard colour, then #6A0DAD |
setHeadline(String) / setRewardText(String) |
Override the dashboard copy. Default headline: "Refer a friend" |
setTypeface(Typeface) / setCornerRadius(float dp) |
Match your app's font and shape |
setOnClose(Runnable) |
Called on the main thread when the screen closes |
setStrings(Map<String, String>) / setString(key, value) |
Replace any label on the screen, keyed by ReferralStrings (see Translating the screen) |
setAppUserId(String) / setPlayPurchaseToken(String) |
The user's RevenueCat / Adapty app user id and own Google Play purchase token, for automatic referrer rewards. Sent when they join; if they already joined, saved once each time the screen opens (see Automatic referrer rewards) |
The screen is built with standard Android views, so it adds no dependencies and works with any app theme (light and dark).
Translating the screen: every label has an English default that you can replace with setStrings (a map) or setString (one key). Keys you leave out keep their default, a blank override falls back to the default, and unknown keys are ignored. Keep any {email} or {date} placeholder in your text: the SDK fills them in.
Map<String, String> strings = new HashMap<>();
strings.put(ReferralStrings.EMAIL_LABEL, "Courriel");
strings.put(ReferralStrings.NAME_LABEL, "Nom");
strings.put(ReferralStrings.JOIN_BUTTON, "Obtenir mon lien");
strings.put(ReferralStrings.SHARE_BUTTON, "Partager");
strings.put(ReferralStrings.PREMIUM_UNTIL, "Premium gratuit jusqu'au {date}");
strings.put(ReferralStrings.ERROR_INVALID_CODE, "Ce code est incorrect ou a expire.");
InsertAffiliateManager.showReferAFriend(this, new ReferAFriendOptions()
.setEmail(currentUser.getEmail())
.setStrings(strings)
.setString(ReferralStrings.CLOSE_BUTTON, "Fermer"));Key (ReferralStrings.) |
String value | Default |
|---|---|---|
EMAIL_LABEL |
emailLabel |
|
NAME_LABEL |
nameLabel |
Name |
JOIN_BUTTON |
joinButton |
Get my link |
CODE_LABEL |
codeLabel |
6-digit code |
CODE_SENT_NOTICE |
codeSentNotice |
We sent a 6-digit code to {email}. Enter it below to connect your account. |
VERIFY_BUTTON |
verifyButton |
Verify |
RESEND_BUTTON |
resendButton |
Send a new code |
CODE_RESENT_NOTICE |
codeResentNotice |
New code sent |
DIFFERENT_EMAIL_BUTTON |
differentEmailButton |
Use a different email |
CODE_LABEL_TITLE |
codeLabelTitle |
Your code |
LINK_LABEL_TITLE |
linkLabelTitle |
Your link |
COPY_BUTTON |
copyButton |
Copy |
COPIED_NOTICE |
copiedNotice |
Copied |
SHARE_BUTTON |
shareButton |
Share |
REFERRALS_LABEL |
referralsLabel |
Referrals |
EARNED_LABEL |
earnedLabel |
Earned |
PREMIUM_UNTIL |
premiumUntil |
Free premium until {date} |
REWARDS_HEADING |
rewardsHeading |
Your rewards |
REDEEM_BUTTON |
redeemButton |
Redeem |
DASHBOARD_LINK |
dashboardLink |
Open my dashboard |
CLOSE_BUTTON |
closeButton |
Close |
TRY_AGAIN_BUTTON |
tryAgainButton |
Try again |
BUSY_BUTTON |
busyButton |
Please wait... |
ERROR_PROGRAM_DISABLED |
errorProgramDisabled |
Referrals are not available in this app right now. |
ERROR_AFFILIATE_LIMIT_REACHED |
errorAffiliateLimitReached |
The referral program is full right now. Please try again later. |
ERROR_INVALID_CODE |
errorInvalidCode |
That code is wrong or has expired. |
ERROR_TOO_MANY_CODES |
errorTooManyCodes |
Too many codes requested. Please wait a while and try again. |
ERROR_RATE_LIMITED |
errorRateLimited |
Too many attempts. Please try again later. |
ERROR_INVALID_EMAIL |
errorInvalidEmail |
Please enter a valid email address. |
ERROR_NETWORK |
errorNetwork |
Could not connect. Check your connection and try again. |
ERROR_SERVER |
errorServer |
Something went wrong. Please try again. |
The headline and reward text are not in this list: they come from your dashboard and are overridden with setHeadline and setRewardText. An error code with no key of its own (for example COMPANY_NOT_FOUND) shows ERROR_SERVER.
Build your own screen:
All callbacks below run on a background thread (like getAffiliateDetails). Use runOnUiThread to update your UI.
// 1. Make the user an affiliate (usually with your logged-in user's email)
InsertAffiliateManager.createAffiliateForUser(email, name, result -> {
if (result.isSuccess()) {
// status "created": this device is now connected
String link = result.getAffiliate().getDeeplinkUrl();
} else if (result.isVerificationRequired()) {
// Email already belongs to an affiliate: we emailed them a 6-digit code.
// Ask for it, then call verifyAffiliateCode.
} else {
// result.getErrorCode(): PROGRAM_DISABLED, AFFILIATE_LIMIT_REACHED, INVALID_EMAIL,
// TOO_MANY_CODES, RATE_LIMITED, COMPANY_NOT_FOUND, INVALID_COMPANY_ID,
// DEEP_LINK_POOL_CONFLICT (try again), NOT_INITIALIZED, NETWORK_ERROR, SERVER_ERROR
Log.e("MyApp", result.getErrorMessage());
}
});
// 2. Only when verification was required
InsertAffiliateManager.verifyAffiliateCode(email, "123456", name, result -> {
if (result.isSuccess()) {
// status "connected" (existing affiliate) or "created"
} else if ("INVALID_CODE".equals(result.getErrorCode())) {
// Wrong or expired code. Spaces, dashes and digits in any script are accepted.
}
// Other codes: PROGRAM_DISABLED, INVALID_EMAIL, RATE_LIMITED, COMPANY_NOT_FOUND,
// INVALID_COMPANY_ID, DEEP_LINK_POOL_CONFLICT (try again), AFFILIATE_LIMIT_REACHED,
// NOT_INITIALIZED, NETWORK_ERROR, SERVER_ERROR
});
// 3. Read their stats (null if this device is not connected)
InsertAffiliateManager.getMyAffiliateDetails(details -> {
if (details != null) {
int referrals = details.getReferralCount(); // for your configured trigger
double earned = details.getTotalEarned(); // in details.getCurrency()
String code = details.getAffiliateShortCode();
String link = details.getDeeplinkUrl();
String dashboard = details.getDashboardUrl();
}
});
// 4. Open the system share sheet with their link
InsertAffiliateManager.shareReferralLink(this, "Get a free week of MyApp: {link}");| Method | Description |
|---|---|
createAffiliateForUser(email, name, [options,] callback) |
Makes the user an affiliate and connects this device. Result status: created, verificationRequired or error. options (ReferrerAccountOptions) is optional |
verifyAffiliateCode(email, code, name, [options,] callback) |
Finishes connecting with the emailed 6-digit code. Result status: connected, created or error. name and options are optional |
setReferrerAccount(options, callback) |
Saves the user's RevenueCat / Adapty app user id or Google Play purchase token after they joined. Callback receives true when saved |
getMyAffiliateDetails(callback) |
The user's code, link and stats (referralCount, installCount, eventCount, purchaseCount, totalEarned, totalPaid, totalUnpaid, currency, dashboardUrl, rewardsGranted, premiumUntil, rewardCodes). null when not connected |
isUserAnAffiliate() |
true when this device is connected. Local check, no network |
signOutAffiliate() |
Disconnects this device (call on app logout). Their affiliate account is untouched |
getReferralProgramConfig(callback) |
Your dashboard settings: enabled, companyName, referralTrigger, headline, rewardText, primaryColor |
shareReferralLink(activity, message) |
Opens the share sheet. message is optional |
showReferAFriend(activity, options) |
Presents the drop-in screen. options is optional |
Order to call them in, and the states to handle:
getReferralProgramConfig(callback): readisEnabled()first. When it is off, show nothing.getCompanyName(),getHeadline(),getRewardText()andgetPrimaryColor()are your dashboard copy, andgetReferralTrigger()says what counts as a referral.isUserAnAffiliate(): a local check, no network. Not enrolled: ask for an email and name, then callcreateAffiliateForUser.- Code needed:
result.isVerificationRequired()means we emailed a 6-digit code. Ask for it and callverifyAffiliateCode. CallcreateAffiliateForUseragain for a new code. Spaces, dashes and digits in any script are accepted. - Enrolled:
getMyAffiliateDetails(callback)forgetAffiliateShortCode(),getDeeplinkUrl(),getReferralCount(),getTotalEarned()withgetCurrency()andgetDashboardUrl(). Show the link when it starts withhttp, otherwise show the code (Short Code Only apps). - Sharing:
shareReferralLink(activity, message)opens the system share sheet, or build your own text from the code and link. - Rewards:
getRewardsGranted(),getPremiumUntilDate()(null when none) andgetRewardCodes(). Show only codes whereisGooglePlay()is true, since App Store codes cannot be redeemed on Android, and opengetRedeemUrl()for Redeem. - Accounts:
setReferrerAccount(options, callback)whenever the user subscribes or logs in after joining. - Signing out:
signOutAffiliate()on app logout, which disconnects this device only.
Errors: every failure from createAffiliateForUser and verifyAffiliateCode arrives as result.getErrorCode() (the codes listed above), so you can word each one yourself. getMyAffiliateDetails and getReferralProgramConfig pass null on failure: use isUserAnAffiliate() to tell "not connected" from a failed request. If the server says the connection is no longer valid, the SDK clears it, so isUserAnAffiliate() then returns false and the user joins again with an email code.
Share text: with a web link the SDK shares "<message> <link>" (default message "Try {your app name}:"). For Short Code Only apps it shares "Use my code {code} in {your app name}".
Automatic referrer rewards: if you switched on referrer rewards in your dashboard (RevenueCat, Adapty or Google Play), the server needs to know which account belongs to your user. Pass it when they join (or set it on ReferAFriendOptions if you only use the drop-in screen), or later with setReferrerAccount when they subscribe or log in after joining; the server then grants any rewards that were waiting. The SDK also sends this device's id (the one in the insert affiliate identifier) so a "friend" who is really the referrer isn't counted.
ReferrerAccountOptions account = new ReferrerAccountOptions()
.setAppUserId(Purchases.getSharedInstance().getAppUserID()) // RevenueCat app user id, or Adapty customer user id
.setPlayPurchaseToken(purchase.getPurchaseToken()); // the user's own Google Play subscription token (optional)
// When joining
InsertAffiliateManager.createAffiliateForUser(email, name, account, result -> { /* ... */ });
InsertAffiliateManager.verifyAffiliateCode(email, "123456", name, account, result -> { /* ... */ });
// Or later, once the user has subscribed or logged in
InsertAffiliateManager.setReferrerAccount(account, saved -> {
Log.i("MyApp", "Referrer account saved: " + saved);
});
// What they have been granted
InsertAffiliateManager.getMyAffiliateDetails(details -> {
if (details != null) {
int rewards = details.getRewardsGranted();
Date premiumUntil = details.getPremiumUntilDate(); // null when none; getPremiumUntil() is the ISO string
List<MyAffiliateDetails.RewardCode> codes = details.getRewardCodes(); // reward codes, newest first
}
});getRewardCodes() holds reward codes (getCode(), getRedeemUrl(), getStore(), getGrantedAt()). getStore() is "google_play" for Google Play promo codes and "app_store" for App Store one-time offer codes (codes with no store are App Store codes); isGooglePlay() is a shortcut. The drop-in screen shows Google Play promo codes under "Your rewards", each with Copy and a Redeem button that opens the Play Store to redeem it. App Store codes can only be redeemed on iOS, so the drop-in screen keeps them hidden on Android.
How the connection works: when a user joins, the server gives this device a private token, stored in private SharedPreferences (one per company code). It only lets the device read the user's own stats. If Android Auto Backup is on for your app (the default), the token can be restored after a reinstall or on a new phone, and the user stays connected without an email code. Otherwise they enter their email again and confirm with the emailed code. Either way their affiliate account, earnings and dashboard are unchanged. The token is cleared when the server reports it is no longer valid, or when you call signOutAffiliate().
Rewarding referrers: values shown on the device are for display only, because a modified device can fake what it shows. Grant anything valuable (credits, premium time) from your server, using the referral.created webhook or the Public API. referralCount only goes up, so you can compare it with what you have already rewarded and grant the difference.
Store rules: the SDK uses the system share sheet only, needs no Contacts permission and never gates features behind sharing. Do not reward ratings or reviews. For free premium time, use Google Play promo codes or RevenueCat promotional entitlements.
By default, clicking a new affiliate link will overwrite any existing attribution. Enable preventAffiliateTransfer to lock the first affiliate:
InsertAffiliateManager.init(
this,
"YOUR_COMPANY_CODE",
true, // verbose logging
false, // insert links
604800, // 7-day timeout
true // prevent affiliate transfer
);How it works:
- When enabled, once a user is attributed to an affiliate, that attribution is locked
- New affiliate links will not overwrite the existing attribution
- The callback still fires with the existing affiliate data (not the new one)
- Useful for preventing "affiliate stealing" where users click competitor links
Example scenario:
- User clicks Affiliate A's link β attributed to Affiliate A
- User later clicks Affiliate B's link β still attributed to Affiliate A (blocked)
- Affiliate A gets credit for any purchases
Learn more: Prevent Affiliate Transfer Documentation
Error: "Company code is not set"
- Cause: SDK not initialized or
init()called after other SDK methods - Solution: Call
InsertAffiliateManager.init()inonCreate()before any other SDK methods
Problem: Deep link opens Play Store or browser instead of app
- Cause: Missing or incorrect intent filters, or SHA-256 certificate not configured
- Solution:
- Verify intent filters in
AndroidManifest.xmlmatch your deep link domain - Add SHA-256 certificate fingerprint to your deep linking provider's console
- For Play App Signing, use SHA-256 from Google Play Console β Setup β App Integrity
- Verify intent filters in
Problem: "No affiliate identifier found"
- Cause: User hasn't clicked an affiliate link yet
- Solution: Ensure users come from affiliate links before purchases. Test with
adbcommand:adb shell am start -a android.intent.action.VIEW -d "YOUR_DEEP_LINK_URL"
Problem: RevenueCat not returning the expected targeted offering
- Cause:
affiliateOfferCodeattribute not being saved properly - Solution:
- Set
affiliateOfferCodein a separatesetAttributes()call (see RevenueCat code example above) - Always call
syncAttributesAndOfferingsIfNeeded()after setting attributes - Fetch offerings after sync completes, not before
- Verify the targeting rule exists in RevenueCat dashboard
- Check RevenueCat customer profile to confirm
affiliateOfferCodeattribute is saved
- Set
Problem: Purchases not appearing in Insert Affiliate dashboard
- Cause: Webhook not configured or affiliate identifier not passed to IAP platform
- Solution:
- Verify webhook URL and authorization headers are correct
- For RevenueCat: Confirm
insert_affiliateattribute is set before purchase - For Iaptic/Google Direct: Check that affiliate identifier exists when purchase is made
- Enable verbose logging and check console for errors
Enable detailed logs during development to diagnose issues:
InsertAffiliateManager.init(this, "YOUR_COMPANY_CODE", true);Filter logs by tag:
adb logcat | grep "InsertAffiliate TAG"Important: Disable verbose logging in production builds.
- π Documentation
- π¬ Dashboard Support
- π Report Issues
- Documentation: docs.insertaffiliate.com
- Dashboard Support: app.insertaffiliate.com/help
- Issues: GitHub Issues
- Company Code: Get yours from Settings
Need help getting started? Check out our quickstart guide or contact support.