@tryinhouse/react-native-inhouse-sdk
v1.0.14
Published
A React Native module for tracking SDK functionality
Readme
@tryinhouse/react-native-inhouse-sdk
A powerful React Native SDK for tracking user interactions, app installs, and deep linking with install referrer support. Built for seamless integration with the TryInHouse platform.
🚀 Features
- 📱 Cross-platform: Works on both iOS and Android
- 🔗 Deep Linking: Handle custom schemes and universal/app links
- 📊 Event Tracking: Track app opens, sessions, and custom events
- 🎯 Install Attribution: Advanced install referrer tracking
📋 Prerequisites
- React Native 0.60.0 or higher
- iOS 16.0+ / Android API level 24+
- CocoaPods (for iOS)
📦 Installation
Using npm
npm install @tryinhouse/react-native-inhouse-sdkUsing yarn
yarn add @tryinhouse/react-native-inhouse-sdk🔧 Platform Setup
iOS Setup
- Install CocoaPods dependencies:
cd ios && pod install- Add Thumbmark Swift Package Dependency:
The SDK requires the Thumbmark Swift package for device fingerprinting and secure identification.
Option A: Using Xcode (Recommended)
- Open your iOS project in Xcode (
ios/YourApp.xcworkspace) - Go to File → Add Package Dependencies...
- Enter the repository URL:
https://github.com/thumbmarkjs/thumbmark-swift - Select Up to Next Major Version and click Add Package
- Select the Thumbmark target and click Add Package
Option B: Using Package.swift (for SPM projects)
Add the following to your Package.swift dependencies:
dependencies: [
.package(url: "https://github.com/thumbmarkjs/thumbmark-swift", from: "1.1.0")
]- Configure URL Schemes in
ios/YourApp/Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>your-app-identifier</string>
<key>CFBundleURLSchemes</key>
<array>
<string>myiosapp</string>
</array>
</dict>
</array>- Add Associated Domains for universal links:
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:your-shortlink-domain.tryinhouse.co</string>
</array>Android Setup
The SDK uses React Native's autolinking feature for automatic integration.
- Add Install Referrer Receiver to
android/app/src/main/AndroidManifest.xml:
<application>
<!-- Your existing application content -->
<!-- Install Referrer Receiver -->
<receiver
android:name="co.tryinhouse.android.InstallReferrerReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
</application>- Configure Deep Link Intent Filters in your main activity:
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/AppTheme">
<!-- Existing intent filters -->
<!-- Custom Scheme Deep Links -->
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="myandroidapp"/>
</intent-filter>
<!-- App Links (Universal Links) -->
<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" />
<data android:host="your-shortlink-domain.tryinhouse.co" />
</intent-filter>
</activity>🔗 TryInHouse Platform Configuration
After setting up the mobile app configurations above, you need to configure the well-known files in your TryInHouse dashboard to enable proper deep linking verification.
Configure Well-Known Files
Log in to TryInHouse Dashboard:
- Go to https://app.tryinhouse.co/
- Sign in to your account or create a new one
Navigate to Project Settings:
- Select your project from the dashboard
- Go to Settings → Linkings
Configure iOS Universal Links (apple-app-site-association):
Add the following configuration for iOS universal links:
{
"applinks": {
"details": [
{
"appIDs": ["TEAMID.com.yourcompany.yourapp"],
"components": [
{
"/#": "*",
"exclude": true,
"comment": "Matches any URL with a fragment identifier"
},
{
"/?*": "*",
"comment": "Matches any URL with query parameters"
},
{
"/": "*",
"comment": "Matches the root URL and any path"
}
]
}
]
},
"webcredentials": {
"apps": ["TEAMID.com.yourcompany.yourapp"]
}
}Important: Replace TEAMID.com.yourcompany.yourapp with your actual Team ID and Bundle Identifier from your iOS app.
- Configure Android App Links (assetlinks.json):
Add the following configuration for Android app links:
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.yourcompany.yourapp",
"sha256_cert_fingerprints": ["YOUR_APP_SHA256_FINGERPRINT"]
}
}
]Important: Replace the following values:
com.yourcompany.yourappwith your Android package nameYOUR_APP_SHA256_FINGERPRINTwith your app's SHA256 certificate fingerprint
- Get Your Android SHA256 Fingerprint:
For debug builds:
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass androidFor release builds:
keytool -list -v -keystore /path/to/your/release.keystore -alias your-key-alias- Save and Deploy:
- Save the configurations in your TryInHouse dashboard
- The platform will automatically deploy these files to your domain
- Files will be accessible at:
https://your-shortlink-domain.tryinhouse.co/.well-known/apple-app-site-associationhttps://your-shortlink-domain.tryinhouse.co/.well-known/assetlinks.json
Verify Configuration
Test iOS Universal Links:
# Test the apple-app-site-association file
curl -s https://your-shortlink-domain.tryinhouse.co/.well-known/apple-app-site-association | jq .Test Android App Links:
# Test the assetlinks.json file
curl -s https://your-shortlink-domain.tryinhouse.co/.well-known/assetlinks.json | jq .
# Verify with Google's validation tool
# https://developers.google.com/digital-asset-links/tools/generatorTest Deep Link Handling:
# Android testing
adb shell am start -W -a android.intent.action.VIEW -d "https://your-shortlink-domain.tryinhouse.co/test" com.yourcompany.yourapp
# iOS testing (use iOS Simulator)
xcrun simctl openurl booted "https://your-shortlink-domain.tryinhouse.co/test"Manual Linking (Legacy React Native)
Android
- Add to
android/settings.gradle:
include ':react-native-inhouse-sdk'
project(':react-native-inhouse-sdk').projectDir = new File(rootProject.projectDir, '../node_modules/@tryinhouse/react-native-inhouse-sdk/android')- Add to
android/app/build.gradle:
dependencies {
implementation project(':react-native-inhouse-sdk')
// ... other dependencies
}- Update
MainApplication.java:
import co.tryinhouse.react_native.TrackingSDKPackage;
public class MainApplication extends Application implements ReactApplication {
// ...
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new TrackingSDKPackage() // Add this line
);
}
}🚀 Quick Start
1. Initialize the SDK
import TrackingSDK from "@tryinhouse/react-native-inhouse-sdk";
// Initialize in your App.js or App.tsx
const initializeSDK = async () => {
try {
await TrackingSDK.initialize(
"your-project-id", // Project ID from TryInHouse dashboard
"your-project-token", // Project token from TryInHouse dashboard
"your-shortlink-domain", // Your custom domain (e.g., 'myapp.tryinhouse.co')
"https://api.tryinhouse.co", // Optional: API endpoint
__DEV__ // Enable debug logging in development
);
console.log("SDK initialized successfully");
} catch (error) {
console.error("SDK initialization failed:", error);
}
};
// Call during app startup
initializeSDK();2. Handle App Lifecycle
import { AppState } from "react-native";
useEffect(() => {
const handleAppStateChange = (nextAppState: string) => {
if (nextAppState === "active") {
TrackingSDK.onAppResume();
}
};
const subscription = AppState.addEventListener(
"change",
handleAppStateChange
);
return () => subscription?.remove();
}, []);3. Track Events
// Track app open (typically in App.js)
const trackAppOpen = async () => {
try {
const result = await TrackingSDK.trackAppOpen();
console.log("App open tracked:", result);
} catch (error) {
console.error("Failed to track app open:", error);
}
};
// Track session start
const trackSession = async () => {
try {
const result = await TrackingSDK.trackSessionStart();
console.log("Session tracked:", result);
} catch (error) {
console.error("Failed to track session:", error);
}
};📖 Detailed Usage
Event Tracking
Track App Open
// Basic app open tracking
await TrackingSDK.trackAppOpen();
// Track app open with specific shortlink
await TrackingSDK.trackAppOpen("https://myapp.tryinhouse.co/abc123");Track Session Start
// Basic session tracking
await TrackingSDK.trackSessionStart();
// Track session with shortlink context
await TrackingSDK.trackSessionStart("https://myapp.tryinhouse.co/xyz789");Track Short Link Clicks
// Track when user clicks on a short link
await TrackingSDK.trackShortLinkClick(
"https://myapp.tryinhouse.co/campaign1", // Short link URL
"myapp://product/123" // Optional: Deep link destination
);Install Referrer Tracking
// Get stored install referrer
const getStoredReferrer = async () => {
try {
const referrer = await TrackingSDK.getInstallReferrer();
console.log("Stored referrer:", referrer);
} catch (error) {
console.error("Error getting referrer:", error);
}
};
// Fetch fresh install referrer data
const fetchFreshReferrer = async () => {
try {
const referrer = await TrackingSDK.fetchInstallReferrer();
console.log("Fresh referrer:", referrer);
} catch (error) {
console.error("Error fetching referrer:", error);
}
};Real-time Event Callbacks
import { useEffect, useState } from 'react';
const useSDKCallbacks = () => {
useEffect(() => {
// Add callback listener
const subscription = TrackingSDK.addCallbackListener((data) => {
console.log('SDK Event:', data.callbackType);
console.log('Event Data:', data.data);
switch (data.callbackType) {
case 'session_start_shortlink':
handleSessionWithShortlink(data.data);
break;
case 'app_open_shortlink':
handleAppOpenFromShortlink(data.data);
break;
case 'app_install_from_shortlink':
handleInstallFromShortlink(data.data);
break;
default:
console.log('Unknown callback type:', data.callbackType);
}
});
// Cleanup function
return () => {
TrackingSDK.removeCallbackListener(subscription);
};
}, []);
};
// Usage in component
const App = () => {
useSDKCallbacks();
return (
// Your app content
);
};Deep Link Handling
import { Linking } from "react-native";
const handleDeepLink = (url: string) => {
console.log("Deep link received:", url);
// Parse and handle the deep link
if (url.includes("product/")) {
const productId = url.split("product/")[1];
// Navigate to product page
}
};
useEffect(() => {
// Handle initial URL (app opened via deep link)
Linking.getInitialURL().then((url) => {
if (url) {
handleDeepLink(url);
}
});
// Handle URLs while app is running
const subscription = Linking.addEventListener("url", ({ url }) => {
handleDeepLink(url);
});
return () => subscription?.remove();
}, []);📊 Event Data Structure
All tracking events return link data with the following structure:
interface LinkData {
id: string;
domain: string;
key: string;
url: string;
short_link: string;
title: string;
description: string;
image: string;
utm_source: string;
utm_medium: string;
utm_campaign: string;
utm_term: string;
utm_content: string;
ios: string;
android: string;
project_id: string;
folder_id: string;
playstore: string;
appstore: string;
deeplink_path: string;
link_data: string; // JSON object with custom key-value pairs
website_link: string;
refer_code: string;
unique_clicks: number;
app_installs: number;
}⚙️ Configuration
Dependency Versions
You can override dependency versions in your android/build.gradle:
ext {
okhttpVersion = '4.12.0'
gsonVersion = '2.10.1'
installReferrerVersion = '2.2'
coroutinesVersion = '1.7.3'
coreKtxVersion = '1.12.0'
appcompatVersion = '1.6.1'
}Debug Mode
Enable comprehensive logging during development:
await TrackingSDK.initialize(
"project-id",
"project-token",
"domain",
"https://api.tryinhouse.co",
true // Enable debug logging
);🧪 Testing
Reset First Install State
For testing install attribution:
// Reset first install state (use only for testing)
await TrackingSDK.resetFirstInstall();Example Test Scenarios
// Test deep link handling
const testDeepLink = async () => {
const shortLink = "https://myapp.tryinhouse.co/test123";
const deepLink = "myapp://home?tab=featured";
await TrackingSDK.trackShortLinkClick(shortLink, deepLink);
};
// Test install referrer
const testInstallReferrer = async () => {
const referrer = await TrackingSDK.fetchInstallReferrer();
console.log("Test referrer:", referrer);
};🔧 Troubleshooting
Build Errors
Problem: Build fails with dependency conflicts Solution: Ensure you're using compatible React Native version (0.60+)
npx react-native doctoriOS Pod Install Issues
Problem: CocoaPods installation fails Solution:
cd ios
rm -rf Pods Podfile.lock
pod cache clean --all
pod installAndroid Linking Issues
Problem: SDK not found or linking errors Solution: Clean and rebuild
cd android
./gradlew clean
cd ..
npx react-native run-androidDeep Links Not Working
Problem: Deep links not opening the app Solution:
- Verify AndroidManifest.xml intent filters
- Check iOS URL schemes in Info.plist
- Test with
adbcommand:
adb shell am start -W -a android.intent.action.VIEW -d "myapp://test" com.yourappInstall Referrer Not Tracked
Problem: Install referrer data is empty Solution:
- Verify InstallReferrerReceiver is added to AndroidManifest.xml
- Test with Google Play Console's internal testing
- Check that app is installed from Play Store, not sideloaded
📚 API Reference
Core Methods
| Method | Description | Parameters | Returns |
| ------------------------ | -------------------- | ----------------------------------------------------------------- | ------------------------- |
| initialize() | Initialize the SDK | projectId, projectToken, domain, serverUrl?, debugMode? | Promise<void> |
| onAppResume() | Handle app resume | None | Promise<void> |
| trackAppOpen() | Track app open event | shortLink? | Promise<TrackingResult> |
| trackSessionStart() | Track session start | shortLink? | Promise<TrackingResult> |
| trackShortLinkClick() | Track link click | shortLink, deepLink? | Promise<TrackingResult> |
| getInstallReferrer() | Get stored referrer | None | Promise<string> |
| fetchInstallReferrer() | Fetch fresh referrer | None | Promise<string> |
| resetFirstInstall() | Reset install state | None | Promise<void> |
Event Listeners
| Method | Description | Parameters | Returns |
| -------------------------- | ------------------------ | -------------------------- | --------------------- |
| addCallbackListener() | Add event listener | callback: (data) => void | EmitterSubscription |
| removeCallbackListener() | Remove specific listener | subscription | void |
| removeAllListeners() | Remove all listeners | None | void |
TypeScript Types
interface TrackingSDKCallback {
callbackType:
| "session_start_shortlink"
| "app_open_shortlink"
| "app_install_from_shortlink";
data: LinkData;
}
interface TrackingResult {
success: boolean;
data?: LinkData;
error?: string;
}🤝 Contributing
We welcome contributions! Please see our Contributing Guide for details.
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🔗 Links
📞 Support
- 📧 Email: [email protected]
- 🐛 Report Issues
- 💬 Discussions
Made with ❤️ by the TryInHouse team
