From d276622a5289d2573724b36fa840c8e9ecbaa06b Mon Sep 17 00:00:00 2001 From: chetan Date: Fri, 7 Nov 2025 19:22:48 +0530 Subject: [PATCH 01/10] fix added event_id --- api-reference/event-capture.mdx | 18 +++++++++++++++--- sdk/android/usage.mdx | 18 +++++++++++++++--- sdk/flutter/usage.mdx | 22 +++++++++++++++++++++- sdk/ios/usage.mdx | 18 +++++++++++++++--- sdk/react-native/usage.mdx | 25 +++++++++++++++++++------ 5 files changed, 85 insertions(+), 16 deletions(-) diff --git a/api-reference/event-capture.mdx b/api-reference/event-capture.mdx index 5377a0e..69faacc 100644 --- a/api-reference/event-capture.mdx +++ b/api-reference/event-capture.mdx @@ -40,7 +40,8 @@ POST: /capture-event "currency": "USD", "is_featured": true }, - "user_id": "user_12345" + "user_id": "user_12345", + "event_id": "550e8400-e29b-41d4-a716-446655440000" } ``` @@ -49,6 +50,7 @@ POST: /capture-event | event_name | string | **Required**. Name of the event to track | | event_data | object | **Optional**. Additional data associated with the event | | user_id | string | **Required**. User identifier to associate with the event | +| event_id | string | **Optional**. Unique event identifier (String). Recommended to use UUID format for uniqueness | ### Responses @@ -97,7 +99,8 @@ To enable revenue sharing with ad networks like Google Ads and Meta, include an "category": "electronics", "amount": 149.99 }, - "user_id": "user_12345" + "user_id": "user_12345", + "event_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8" } ``` @@ -106,6 +109,10 @@ To enable revenue sharing with ad networks like Google Ads and Meta, include an string. + + The `event_id` parameter should be a unique String identifier for each event. It's recommended to use a UUID (Universally Unique Identifier) format to ensure uniqueness. This helps track and deduplicate events on the server side. + + ## Best Practices 1. **Consistent naming**: Use consistent naming conventions for your events (snake_case is recommended) @@ -118,7 +125,10 @@ To enable revenue sharing with ad networks like Google Ads and Meta, include an ### Tracking a Purchase Event ```javascript -// Using fetch API +// Using fetch API with crypto.randomUUID() (available in Node.js 14.17.0+ and modern browsers) +// For older environments, use a UUID library like 'uuid' +import { v4 as uuidv4 } from 'uuid'; // npm install uuid + fetch("https://api.linkrunner.io/api/v1/capture-event", { method: "POST", headers: { @@ -135,6 +145,8 @@ fetch("https://api.linkrunner.io/api/v1/capture-event", { payment_method: "credit_card", }, user_id: "user_12345", + event_id: uuidv4(), // Recommended: Use UUID for uniqueness + // Alternative: event_id: crypto.randomUUID() // Available in Node.js 14.17.0+ and modern browsers }), }) .then((response) => response.json()) diff --git a/sdk/android/usage.mdx b/sdk/android/usage.mdx index 12d04c0..2ea32f7 100644 --- a/sdk/android/usage.mdx +++ b/sdk/android/usage.mdx @@ -197,6 +197,8 @@ private fun setIntegrationData() { Track custom events in your app: ```kotlin +import java.util.UUID + private fun trackEvent() { CoroutineScope(Dispatchers.IO).launch { try { @@ -206,7 +208,8 @@ private fun trackEvent() { "product_id" to "12345", "category" to "electronics", "amount" to 99.99 // Include amount as a number for revenue sharing with ad networks like Google and Meta - ) + ), + eventId = UUID.randomUUID().toString() // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness ) result.onSuccess { @@ -221,11 +224,17 @@ private fun trackEvent() { } ``` + + The `eventId` parameter should be a unique String identifier for each event. It's recommended to use `UUID.randomUUID().toString()` to generate a unique identifier. This helps track and deduplicate events on the server side. + + ### Revenue Sharing with Ad Networks To enable revenue sharing with ad networks like Google Ads and Meta, include an `amount` parameter as a number in your custom event data. This allows the ad networks to optimize campaigns based on the revenue value of conversions: ```kotlin +import java.util.UUID + private fun trackPurchaseEvent() { CoroutineScope(Dispatchers.IO).launch { try { @@ -235,7 +244,8 @@ private fun trackPurchaseEvent() { "product_id" to "12345", "category" to "electronics", "amount" to 149.99 // Revenue amount as a number - ) + ), + eventId = UUID.randomUUID().toString() // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness ) result.onSuccess { @@ -381,6 +391,7 @@ import io.linkrunner.sdk.models.request.UserDataRequest import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import java.util.UUID class MyApplication : Application() { override fun onCreate() { @@ -448,7 +459,8 @@ class MainActivity : AppCompatActivity() { try { LinkRunner.getInstance().trackEvent( eventName = "button_clicked", - eventData = mapOf("screen" to "main") + eventData = mapOf("screen" to "main"), + eventId = UUID.randomUUID().toString() // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness ) } catch (e: Exception) { println("Error tracking event: ${e.message}") diff --git a/sdk/flutter/usage.mdx b/sdk/flutter/usage.mdx index d913bac..3e96c0e 100644 --- a/sdk/flutter/usage.mdx +++ b/sdk/flutter/usage.mdx @@ -160,6 +160,10 @@ This method allows you to connect user identities across different analytics and Track custom events in your app: ```dart +import 'package:uuid/uuid.dart'; + +final _uuid = Uuid(); + Future trackEvent() async { try { await LinkRunner().trackEvent( @@ -169,6 +173,7 @@ Future trackEvent() async { 'category': 'electronics', 'amount': 99.99, // Include amount as a number for revenue sharing with ad networks like Google and Meta }, + eventId: _uuid.v4(), // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness ); print('Event tracked successfully'); } catch (e) { @@ -177,11 +182,19 @@ Future trackEvent() async { } ``` + + The `eventId` parameter should be a unique String identifier for each event. It's recommended to use the `uuid` package to generate a unique identifier. This helps track and deduplicate events on the server side. + + ### Revenue Sharing with Ad Networks To enable revenue sharing with ad networks like Google Ads and Meta, include an `amount` parameter as a number in your custom event data. This allows the ad networks to optimize campaigns based on the revenue value of conversions: ```dart +import 'package:uuid/uuid.dart'; + +final _uuid = Uuid(); + Future trackPurchaseEvent() async { try { await LinkRunner().trackEvent( @@ -191,6 +204,7 @@ Future trackPurchaseEvent() async { 'category': 'electronics', 'amount': 149.99, // Revenue amount as a number }, + eventId: _uuid.v4(), // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness ); print('Purchase event with revenue tracked successfully'); } catch (e) { @@ -327,6 +341,9 @@ You can find your project token [here](https://www.linkrunner.io/dashboard?s=mem ```dart import 'package:flutter/material.dart'; import 'package:linkrunner/linkrunner.dart'; +import 'package:uuid/uuid.dart'; + +final _uuid = Uuid(); final linkrunner = LinkRunner(); @@ -381,7 +398,10 @@ class _HomeScreenState extends State { SizedBox(height: 20), ElevatedButton( onPressed: () async { - await LinkRunner().trackEvent(eventName: 'button_clicked'); + await LinkRunner().trackEvent( + eventName: 'button_clicked', + eventId: _uuid.v4(), // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness + ); }, child: Text('Track Custom Event'), ), diff --git a/sdk/ios/usage.mdx b/sdk/ios/usage.mdx index a973b58..bd1ec1d 100644 --- a/sdk/ios/usage.mdx +++ b/sdk/ios/usage.mdx @@ -187,6 +187,8 @@ func setAdditionalData() async { Track custom events in your app: ```swift +import Foundation + func trackEvent() async { do { try await LinkrunnerSDK.shared.trackEvent( @@ -195,7 +197,8 @@ func trackEvent() async { "product_id": "12345", "category": "electronics", "amount": 99.99 // Include amount as a number for revenue sharing with ad networks like Google and Meta - ] + ], + eventId: UUID().uuidString // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness ) print("Event tracked successfully") } catch { @@ -204,11 +207,17 @@ func trackEvent() async { } ``` + + The `eventId` parameter should be a unique String identifier for each event. It's recommended to use `UUID().uuidString` to generate a unique identifier. This helps track and deduplicate events on the server side. + + ### Revenue Sharing with Ad Networks To enable revenue sharing with ad networks like Google Ads and Meta, include an `amount` parameter as a number in your custom event data. This allows the ad networks to optimize campaigns based on the revenue value of conversions: ```swift +import Foundation + func trackPurchaseEvent() async { do { try await LinkrunnerSDK.shared.trackEvent( @@ -217,7 +226,8 @@ func trackPurchaseEvent() async { "product_id": "12345", "category": "electronics", "amount": 149.99 // Revenue amount as a number - ] + ], + eventId: UUID().uuidString // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness ) print("Purchase event with revenue tracked successfully") } catch { @@ -335,6 +345,7 @@ You can find your project token [here](https://www.linkrunner.io/dashboard?s=mem ```swift import SwiftUI import Linkrunner +import Foundation @main struct MyApp: App { @@ -382,7 +393,8 @@ struct ContentView: View { do { try await LinkrunnerSDK.shared.trackEvent( eventName: "button_clicked", - eventData: ["screen": "home"] + eventData: ["screen": "home"], + eventId: UUID().uuidString // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness ) print("Event tracked successfully") } catch { diff --git a/sdk/react-native/usage.mdx b/sdk/react-native/usage.mdx index 3c3dea8..c29bd1c 100644 --- a/sdk/react-native/usage.mdx +++ b/sdk/react-native/usage.mdx @@ -161,25 +161,38 @@ This method allows you to connect user identities across different analytics and Track custom events in your app: ```javascript +import { v4 as uuidv4 } from 'uuid'; // or use crypto.randomUUID() if available + const trackEvent = async () => { await linkrunner.trackEvent( "purchase_initiated", // Event name - { product_id: "12345", category: "electronics", amount: 99.99 } // Optional: Event data, include amount as a number for revenue sharing with ad networks like Google and Meta + { product_id: "12345", category: "electronics", amount: 99.99 }, // Optional: Event data, include amount as a number for revenue sharing with ad networks like Google and Meta + uuidv4() // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness ); }; ``` + + The `eventId` parameter should be a unique String identifier for each event. It's recommended to use a UUID library (like `uuid`) or `crypto.randomUUID()` to generate a unique identifier. This helps track and deduplicate events on the server side. + + ### Revenue Sharing with Ad Networks To enable revenue sharing with ad networks like Google Ads and Meta, include an `amount` parameter as a number in your custom event data. This allows the ad networks to optimize campaigns based on the revenue value of conversions: ```javascript +import { v4 as uuidv4 } from 'uuid'; // or use crypto.randomUUID() if available + const trackPurchaseEvent = async () => { - await linkrunner.trackEvent("purchase_completed", { - product_id: "12345", - category: "electronics", - amount: 149.99, // Revenue amount as a number - }); + await linkrunner.trackEvent( + "purchase_completed", + { + product_id: "12345", + category: "electronics", + amount: 149.99, // Revenue amount as a number + }, + uuidv4() // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness + ); }; ``` From c670b343d7f9c0a3a080cbcff9f07de20741759d Mon Sep 17 00:00:00 2001 From: chetan Date: Wed, 14 Jan 2026 12:48:56 +0530 Subject: [PATCH 02/10] added docs events --- dashboard-links-audit.json | 127 +++++++++++++++++++++++++++++++++++++ sdk/android/usage.mdx | 2 +- 2 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 dashboard-links-audit.json diff --git a/dashboard-links-audit.json b/dashboard-links-audit.json new file mode 100644 index 0000000..1a42b19 --- /dev/null +++ b/dashboard-links-audit.json @@ -0,0 +1,127 @@ +[ + { + "url": "https://dashboard.linkrunner.io/settings?s=data-apis", + "purpose": "Access Data APIs settings to obtain server key for authentication", + "context": "Used for API authentication setup in Data APIs and Campaign APIs documentation", + "files": [ + "api-reference/data-apis.mdx", + "api-reference/campaign-apis.mdx" + ] + }, + { + "url": "https://dashboard.linkrunner.io/settings?p_id=4&s=data-apis", + "purpose": "Generate server code and access server key for revenue tracking and event capture APIs", + "context": "Used for server-side API authentication setup", + "files": [ + "api-reference/revenue-tracking.mdx", + "api-reference/event-capture.mdx" + ] + }, + { + "url": "https://dashboard.linkrunner.io/settings?sort_by=activity-1&s=meta-integration&meta_tab=meta-ad-account", + "purpose": "Connect and configure Meta advertising account with Linkrunner for web-to-app campaigns", + "context": "Meta Web to App integration setup", + "files": [ + "ad-networks/meta-web-to-app.mdx" + ] + }, + { + "url": "https://dashboard.linkrunner.io/dashboard?m=create-campaign", + "purpose": "Create new campaigns with deferred deep linking configuration", + "context": "Campaign creation for deferred deep linking setup", + "files": [ + "features/deferred-deep-linking.mdx", + "testing/integration-testing.mdx" + ] + }, + { + "url": "https://dashboard.linkrunner.io/settings?sort_by=activity-1&s=store-verification", + "purpose": "Configure domain verification for App Links (Android) and Universal Links (iOS)", + "context": "Upload iOS and Android JSON verification objects for deep linking", + "files": [ + "features/deep-linking-verification.mdx" + ] + }, + { + "url": "https://dashboard.linkrunner.io/dashboard?s=members&m=documentation", + "purpose": "Find project token for SDK initialization", + "context": "SDK setup and initialization - used across all SDK documentation", + "files": [ + "sdk/react-native.mdx", + "sdk/android.mdx", + "sdk/flutter.mdx", + "sdk/ios.mdx", + "quickstart.mdx" + ] + }, + { + "url": "https://dashboard.linkrunner.io/settings?s=sdk-signing", + "purpose": "Find project token, secret key, and key ID for enhanced SDK security signing", + "context": "SDK signing parameters for secure authentication", + "files": [ + "sdk/react-native.mdx", + "sdk/android.mdx", + "sdk/flutter.mdx", + "sdk/ios.mdx" + ] + }, + { + "url": "https://dashboard.linkrunner.io/settings?s=domains", + "purpose": "Add and configure subdomain for referral code tracking and domain verification", + "context": "Domain setup for deep linking and referral tracking", + "files": [ + "features/referral-codes.mdx", + "testing/integration-testing.mdx" + ] + }, + { + "url": "https://dashboard.linkrunner.io/settings?s=google-ads-integration§ion=skadnetwork&p_id=27&google_ads=skan_integration", + "purpose": "Complete Google Ads SKAdNetwork integration checklist", + "context": "Configure SKAdNetwork for Google Ads campaigns on iOS", + "files": [ + "features/skadnetwork-integration.mdx" + ] + }, + { + "url": "https://dashboard.linkrunner.io/settings?s=meta-integration§ion=skadnetwork&p_id=27&google_ads=skan_integration&meta_tab=skan_integration", + "purpose": "Complete Meta (Facebook) SKAdNetwork integration checklist", + "context": "Configure SKAdNetwork for Meta ad campaigns on iOS", + "files": [ + "features/skadnetwork-integration.mdx" + ] + }, + { + "url": "https://dashboard.linkrunner.io", + "purpose": "Access main dashboard homepage", + "context": "General dashboard access for campaign creation and management", + "files": [ + "ad-networks/tiktok.mdx", + "ad-networks/meta-ads.mdx", + "docs.json" + ] + }, + { + "url": "https://dashboard.linkrunner.io/settings?s=meta-integration", + "purpose": "Configure Meta app integration with App ID and Referrer Decryption Key", + "context": "Setup Meta Ads integration for attribution tracking and event mapping", + "files": [ + "ad-networks/meta-ads.mdx" + ] + }, + { + "url": "https://dashboard.linkrunner.io/settings?s=store-listings", + "purpose": "Create and manage custom store listings for targeted app marketing", + "context": "Configure custom Play Store and App Store listings for campaigns", + "files": [ + "features/custom-store-listing.mdx" + ] + }, + { + "url": "https://dashboard.linkrunner.io/dashboard?m=documentation", + "purpose": "Find project token for SDK initialization (alternate URL path)", + "context": "Alternative path to access project token for Flutter SDK", + "files": [ + "sdk/flutter.mdx" + ] + } +] diff --git a/sdk/android/usage.mdx b/sdk/android/usage.mdx index 2ea32f7..822828e 100644 --- a/sdk/android/usage.mdx +++ b/sdk/android/usage.mdx @@ -460,7 +460,7 @@ class MainActivity : AppCompatActivity() { LinkRunner.getInstance().trackEvent( eventName = "button_clicked", eventData = mapOf("screen" to "main"), - eventId = UUID.randomUUID().toString() // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness + eventId = UUID.randomUUID().toString() // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness. ) } catch (e: Exception) { println("Error tracking event: ${e.message}") From de634c8c1f7307aec1cc6550c2232afb927ae04d Mon Sep 17 00:00:00 2001 From: chetan Date: Wed, 14 Jan 2026 12:50:13 +0530 Subject: [PATCH 03/10] delete json file --- dashboard-links-audit.json | 127 ------------------------------------- 1 file changed, 127 deletions(-) delete mode 100644 dashboard-links-audit.json diff --git a/dashboard-links-audit.json b/dashboard-links-audit.json deleted file mode 100644 index 1a42b19..0000000 --- a/dashboard-links-audit.json +++ /dev/null @@ -1,127 +0,0 @@ -[ - { - "url": "https://dashboard.linkrunner.io/settings?s=data-apis", - "purpose": "Access Data APIs settings to obtain server key for authentication", - "context": "Used for API authentication setup in Data APIs and Campaign APIs documentation", - "files": [ - "api-reference/data-apis.mdx", - "api-reference/campaign-apis.mdx" - ] - }, - { - "url": "https://dashboard.linkrunner.io/settings?p_id=4&s=data-apis", - "purpose": "Generate server code and access server key for revenue tracking and event capture APIs", - "context": "Used for server-side API authentication setup", - "files": [ - "api-reference/revenue-tracking.mdx", - "api-reference/event-capture.mdx" - ] - }, - { - "url": "https://dashboard.linkrunner.io/settings?sort_by=activity-1&s=meta-integration&meta_tab=meta-ad-account", - "purpose": "Connect and configure Meta advertising account with Linkrunner for web-to-app campaigns", - "context": "Meta Web to App integration setup", - "files": [ - "ad-networks/meta-web-to-app.mdx" - ] - }, - { - "url": "https://dashboard.linkrunner.io/dashboard?m=create-campaign", - "purpose": "Create new campaigns with deferred deep linking configuration", - "context": "Campaign creation for deferred deep linking setup", - "files": [ - "features/deferred-deep-linking.mdx", - "testing/integration-testing.mdx" - ] - }, - { - "url": "https://dashboard.linkrunner.io/settings?sort_by=activity-1&s=store-verification", - "purpose": "Configure domain verification for App Links (Android) and Universal Links (iOS)", - "context": "Upload iOS and Android JSON verification objects for deep linking", - "files": [ - "features/deep-linking-verification.mdx" - ] - }, - { - "url": "https://dashboard.linkrunner.io/dashboard?s=members&m=documentation", - "purpose": "Find project token for SDK initialization", - "context": "SDK setup and initialization - used across all SDK documentation", - "files": [ - "sdk/react-native.mdx", - "sdk/android.mdx", - "sdk/flutter.mdx", - "sdk/ios.mdx", - "quickstart.mdx" - ] - }, - { - "url": "https://dashboard.linkrunner.io/settings?s=sdk-signing", - "purpose": "Find project token, secret key, and key ID for enhanced SDK security signing", - "context": "SDK signing parameters for secure authentication", - "files": [ - "sdk/react-native.mdx", - "sdk/android.mdx", - "sdk/flutter.mdx", - "sdk/ios.mdx" - ] - }, - { - "url": "https://dashboard.linkrunner.io/settings?s=domains", - "purpose": "Add and configure subdomain for referral code tracking and domain verification", - "context": "Domain setup for deep linking and referral tracking", - "files": [ - "features/referral-codes.mdx", - "testing/integration-testing.mdx" - ] - }, - { - "url": "https://dashboard.linkrunner.io/settings?s=google-ads-integration§ion=skadnetwork&p_id=27&google_ads=skan_integration", - "purpose": "Complete Google Ads SKAdNetwork integration checklist", - "context": "Configure SKAdNetwork for Google Ads campaigns on iOS", - "files": [ - "features/skadnetwork-integration.mdx" - ] - }, - { - "url": "https://dashboard.linkrunner.io/settings?s=meta-integration§ion=skadnetwork&p_id=27&google_ads=skan_integration&meta_tab=skan_integration", - "purpose": "Complete Meta (Facebook) SKAdNetwork integration checklist", - "context": "Configure SKAdNetwork for Meta ad campaigns on iOS", - "files": [ - "features/skadnetwork-integration.mdx" - ] - }, - { - "url": "https://dashboard.linkrunner.io", - "purpose": "Access main dashboard homepage", - "context": "General dashboard access for campaign creation and management", - "files": [ - "ad-networks/tiktok.mdx", - "ad-networks/meta-ads.mdx", - "docs.json" - ] - }, - { - "url": "https://dashboard.linkrunner.io/settings?s=meta-integration", - "purpose": "Configure Meta app integration with App ID and Referrer Decryption Key", - "context": "Setup Meta Ads integration for attribution tracking and event mapping", - "files": [ - "ad-networks/meta-ads.mdx" - ] - }, - { - "url": "https://dashboard.linkrunner.io/settings?s=store-listings", - "purpose": "Create and manage custom store listings for targeted app marketing", - "context": "Configure custom Play Store and App Store listings for campaigns", - "files": [ - "features/custom-store-listing.mdx" - ] - }, - { - "url": "https://dashboard.linkrunner.io/dashboard?m=documentation", - "purpose": "Find project token for SDK initialization (alternate URL path)", - "context": "Alternative path to access project token for Flutter SDK", - "files": [ - "sdk/flutter.mdx" - ] - } -] From 4612cf917d4a622132d5a810560a2943e1635d81 Mon Sep 17 00:00:00 2001 From: chetan Date: Wed, 14 Jan 2026 13:02:48 +0530 Subject: [PATCH 04/10] added uuid in the flutter code --- sdk/flutter.mdx | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/sdk/flutter.mdx b/sdk/flutter.mdx index 76cb767..ad0f6f2 100644 --- a/sdk/flutter.mdx +++ b/sdk/flutter.mdx @@ -337,7 +337,19 @@ This method allows you to connect user identities across different analytics and Track custom events in your app: + + To use UUID generation, first add the `uuid` package to your `pubspec.yaml`: + + ```bash + flutter pub add uuid + ``` + + ```dart +import 'package:uuid/uuid.dart'; + +final _uuid = Uuid(); + Future trackEvent() async { try { await LinkRunner().trackEvent( @@ -347,6 +359,7 @@ Future trackEvent() async { 'category': 'electronics', 'amount': 99.99, // Include amount as a number for revenue sharing with ad networks like Google and Meta }, + eventId: _uuid.v4(), // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness ); print('Event tracked successfully'); } catch (e) { @@ -355,11 +368,19 @@ Future trackEvent() async { } ``` + + The `eventId` parameter should be a unique String identifier for each event. It's recommended to use the `uuid` package to generate a unique identifier. This helps track and deduplicate events on the server side. + + ### Revenue Sharing with Ad Networks To enable revenue sharing with ad networks like Google Ads and Meta, include an `amount` parameter as a number in your custom event data. This allows the ad networks to optimize campaigns based on the revenue value of conversions: ```dart +import 'package:uuid/uuid.dart'; + +final _uuid = Uuid(); + Future trackPurchaseEvent() async { try { await LinkRunner().trackEvent( @@ -369,6 +390,7 @@ Future trackPurchaseEvent() async { 'category': 'electronics', 'amount': 149.99, // Revenue amount as a number }, + eventId: _uuid.v4(), // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness ); print('Purchase event with revenue tracked successfully'); } catch (e) { @@ -683,7 +705,9 @@ You can find your project token [here](https://dashboard.linkrunner.io/dashboard ```dart import 'package:flutter/material.dart'; import 'package:linkrunner/linkrunner.dart'; +import 'package:uuid/uuid.dart'; +final _uuid = Uuid(); final linkrunner = LinkRunner(); void main() { @@ -737,7 +761,10 @@ class _HomeScreenState extends State { SizedBox(height: 20), ElevatedButton( onPressed: () async { - await LinkRunner().trackEvent(eventName: 'button_clicked'); + await LinkRunner().trackEvent( + eventName: 'button_clicked', + eventId: _uuid.v4(), // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness + ); }, child: Text('Track Custom Event'), ), From 80288484f02ab0a5dc652fb4f4133151f9095422 Mon Sep 17 00:00:00 2001 From: chetan Date: Wed, 14 Jan 2026 14:48:40 +0530 Subject: [PATCH 05/10] updated docs, removed uuid and added redirection from sdks to event capture --- api-reference/event-capture.mdx | 13 ++++--------- sdk/android.mdx | 13 ++++--------- sdk/flutter.mdx | 26 ++++---------------------- sdk/flutter/usage.mdx | 18 ++++-------------- sdk/ios.mdx | 12 ++++-------- sdk/react-native.mdx | 10 +++------- 6 files changed, 23 insertions(+), 69 deletions(-) diff --git a/api-reference/event-capture.mdx b/api-reference/event-capture.mdx index 0aef398..863c541 100644 --- a/api-reference/event-capture.mdx +++ b/api-reference/event-capture.mdx @@ -50,7 +50,7 @@ POST: /capture-event | event_name | string | **Required**. Name of the event to track | | event_data | object | **Optional**. Additional data associated with the event | | user_id | string | **Required**. User identifier to associate with the event | -| event_id | string | **Optional**. Unique event identifier (String). Recommended to use UUID format for uniqueness | +| event_id | string | **Optional**. Unique event identifier (String) for deduplication. If you're tracking the same event from both your app (SDK) and backend (API), make sure to send the same `event_id` from both sources | ### Responses @@ -100,7 +100,7 @@ To enable revenue sharing with ad networks like Google Ads and Meta, include an "amount": 149.99 }, "user_id": "user_12345", - "event_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8" + "event_id": "550e8400-e29b-41d4-a716-446655440000" } ``` @@ -110,7 +110,7 @@ To enable revenue sharing with ad networks like Google Ads and Meta, include an - The `event_id` parameter should be a unique String identifier for each event. It's recommended to use a UUID (Universally Unique Identifier) format to ensure uniqueness. This helps track and deduplicate events on the server side. + The `event_id` parameter is optional and should be a unique String identifier for each event. It's used for deduplication on the server side. If you're tracking the same event from both your app (SDK) and backend (API), make sure to send the same `event_id` from both sources to prevent duplicate event tracking. ## Best Practices @@ -125,10 +125,6 @@ To enable revenue sharing with ad networks like Google Ads and Meta, include an ### Tracking a Purchase Event ```javascript -// Using fetch API with crypto.randomUUID() (available in Node.js 14.17.0+ and modern browsers) -// For older environments, use a UUID library like 'uuid' -import { v4 as uuidv4 } from 'uuid'; // npm install uuid - fetch("https://api.linkrunner.io/api/v1/capture-event", { method: "POST", headers: { @@ -145,8 +141,7 @@ fetch("https://api.linkrunner.io/api/v1/capture-event", { payment_method: "credit_card", }, user_id: "user_12345", - event_id: uuidv4(), // Recommended: Use UUID for uniqueness - // Alternative: event_id: crypto.randomUUID() // Available in Node.js 14.17.0+ and modern browsers + event_id: "550e8400-e29b-41d4-a716-446655440000", // Optional: Unique event identifier for deduplication. Use the same event_id if tracking from both SDK and API }), }) .then((response) => response.json()) diff --git a/sdk/android.mdx b/sdk/android.mdx index dba645b..a63950e 100644 --- a/sdk/android.mdx +++ b/sdk/android.mdx @@ -326,8 +326,6 @@ private fun setIntegrationData() { Track custom events in your app: ```kotlin -import java.util.UUID - private fun trackEvent() { CoroutineScope(Dispatchers.IO).launch { try { @@ -338,7 +336,7 @@ private fun trackEvent() { "category" to "electronics", "amount" to 99.99 // Include amount as a number for revenue sharing with ad networks like Google and Meta ), - eventId = UUID.randomUUID().toString() // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness + eventId = "550e8400-e29b-41d4-a716-446655440000" // Optional: Unique event identifier (String) for deduplication ) result.onSuccess { @@ -354,7 +352,7 @@ private fun trackEvent() { ``` - The `eventId` parameter should be a unique String identifier for each event. It's recommended to use `UUID.randomUUID().toString()` to generate a unique identifier. This helps track and deduplicate events on the server side. + The `eventId` parameter is optional and should be a unique String identifier for each event. It's used for deduplication on the server side. If you're tracking the same event from both your app and backend, make sure to send the same `eventId` from the [Event Capture API](/api-reference/event-capture) as well. ### Revenue Sharing with Ad Networks @@ -362,8 +360,6 @@ private fun trackEvent() { To enable revenue sharing with ad networks like Google Ads and Meta, include an `amount` parameter as a number in your custom event data. This allows the ad networks to optimize campaigns based on the revenue value of conversions: ```kotlin -import java.util.UUID - private fun trackPurchaseEvent() { CoroutineScope(Dispatchers.IO).launch { try { @@ -374,7 +370,7 @@ private fun trackPurchaseEvent() { "category" to "electronics", "amount" to 149.99 // Revenue amount as a number ), - eventId = UUID.randomUUID().toString() // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness + eventId = "550e8400-e29b-41d4-a716-446655440000" // Optional: Unique event identifier (String) for deduplication ) result.onSuccess { @@ -548,7 +544,6 @@ import io.linkrunner.sdk.models.request.UserDataRequest import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import java.util.UUID class MyApplication : Application() { override fun onCreate() { @@ -617,7 +612,7 @@ class MainActivity : AppCompatActivity() { LinkRunner.getInstance().trackEvent( eventName = "button_clicked", eventData = mapOf("screen" to "main"), - eventId = UUID.randomUUID().toString() // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness. + eventId = "550e8400-e29b-41d4-a716-446655440000" // Optional: Unique event identifier (String) for deduplication ) } catch (e: Exception) { println("Error tracking event: ${e.message}") diff --git a/sdk/flutter.mdx b/sdk/flutter.mdx index ad0f6f2..972d09b 100644 --- a/sdk/flutter.mdx +++ b/sdk/flutter.mdx @@ -337,19 +337,7 @@ This method allows you to connect user identities across different analytics and Track custom events in your app: - - To use UUID generation, first add the `uuid` package to your `pubspec.yaml`: - - ```bash - flutter pub add uuid - ``` - - ```dart -import 'package:uuid/uuid.dart'; - -final _uuid = Uuid(); - Future trackEvent() async { try { await LinkRunner().trackEvent( @@ -359,7 +347,7 @@ Future trackEvent() async { 'category': 'electronics', 'amount': 99.99, // Include amount as a number for revenue sharing with ad networks like Google and Meta }, - eventId: _uuid.v4(), // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness + eventId: '550e8400-e29b-41d4-a716-446655440000', // Optional: Unique event identifier (String) for deduplication ); print('Event tracked successfully'); } catch (e) { @@ -369,7 +357,7 @@ Future trackEvent() async { ``` - The `eventId` parameter should be a unique String identifier for each event. It's recommended to use the `uuid` package to generate a unique identifier. This helps track and deduplicate events on the server side. + The `eventId` parameter is optional and should be a unique String identifier for each event. It's used for deduplication on the server side. If you're tracking the same event from both your app and backend, make sure to send the same `eventId` from the [Event Capture API](/api-reference/event-capture) as well. ### Revenue Sharing with Ad Networks @@ -377,10 +365,6 @@ Future trackEvent() async { To enable revenue sharing with ad networks like Google Ads and Meta, include an `amount` parameter as a number in your custom event data. This allows the ad networks to optimize campaigns based on the revenue value of conversions: ```dart -import 'package:uuid/uuid.dart'; - -final _uuid = Uuid(); - Future trackPurchaseEvent() async { try { await LinkRunner().trackEvent( @@ -390,7 +374,7 @@ Future trackPurchaseEvent() async { 'category': 'electronics', 'amount': 149.99, // Revenue amount as a number }, - eventId: _uuid.v4(), // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness + eventId: '550e8400-e29b-41d4-a716-446655440000', // Optional: Unique event identifier (String) for deduplication ); print('Purchase event with revenue tracked successfully'); } catch (e) { @@ -705,9 +689,7 @@ You can find your project token [here](https://dashboard.linkrunner.io/dashboard ```dart import 'package:flutter/material.dart'; import 'package:linkrunner/linkrunner.dart'; -import 'package:uuid/uuid.dart'; -final _uuid = Uuid(); final linkrunner = LinkRunner(); void main() { @@ -763,7 +745,7 @@ class _HomeScreenState extends State { onPressed: () async { await LinkRunner().trackEvent( eventName: 'button_clicked', - eventId: _uuid.v4(), // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness + eventId: '550e8400-e29b-41d4-a716-446655440000', // Optional: Unique event identifier (String) for deduplication ); }, child: Text('Track Custom Event'), diff --git a/sdk/flutter/usage.mdx b/sdk/flutter/usage.mdx index 3e96c0e..5f0928b 100644 --- a/sdk/flutter/usage.mdx +++ b/sdk/flutter/usage.mdx @@ -160,10 +160,6 @@ This method allows you to connect user identities across different analytics and Track custom events in your app: ```dart -import 'package:uuid/uuid.dart'; - -final _uuid = Uuid(); - Future trackEvent() async { try { await LinkRunner().trackEvent( @@ -173,7 +169,7 @@ Future trackEvent() async { 'category': 'electronics', 'amount': 99.99, // Include amount as a number for revenue sharing with ad networks like Google and Meta }, - eventId: _uuid.v4(), // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness + eventId: '550e8400-e29b-41d4-a716-446655440000', // Optional: Unique event identifier (String) for deduplication ); print('Event tracked successfully'); } catch (e) { @@ -183,7 +179,7 @@ Future trackEvent() async { ``` - The `eventId` parameter should be a unique String identifier for each event. It's recommended to use the `uuid` package to generate a unique identifier. This helps track and deduplicate events on the server side. + The `eventId` parameter is optional and should be a unique String identifier for each event. It's used for deduplication on the server side. If you're tracking the same event from both your app and backend, make sure to send the same `eventId` from the [Event Capture API](/api-reference/event-capture) as well. ### Revenue Sharing with Ad Networks @@ -191,10 +187,6 @@ Future trackEvent() async { To enable revenue sharing with ad networks like Google Ads and Meta, include an `amount` parameter as a number in your custom event data. This allows the ad networks to optimize campaigns based on the revenue value of conversions: ```dart -import 'package:uuid/uuid.dart'; - -final _uuid = Uuid(); - Future trackPurchaseEvent() async { try { await LinkRunner().trackEvent( @@ -204,7 +196,7 @@ Future trackPurchaseEvent() async { 'category': 'electronics', 'amount': 149.99, // Revenue amount as a number }, - eventId: _uuid.v4(), // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness + eventId: '550e8400-e29b-41d4-a716-446655440000', // Optional: Unique event identifier (String) for deduplication ); print('Purchase event with revenue tracked successfully'); } catch (e) { @@ -341,9 +333,7 @@ You can find your project token [here](https://www.linkrunner.io/dashboard?s=mem ```dart import 'package:flutter/material.dart'; import 'package:linkrunner/linkrunner.dart'; -import 'package:uuid/uuid.dart'; -final _uuid = Uuid(); final linkrunner = LinkRunner(); @@ -400,7 +390,7 @@ class _HomeScreenState extends State { onPressed: () async { await LinkRunner().trackEvent( eventName: 'button_clicked', - eventId: _uuid.v4(), // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness + eventId: '550e8400-e29b-41d4-a716-446655440000', // Optional: Unique event identifier (String) for deduplication ); }, child: Text('Track Custom Event'), diff --git a/sdk/ios.mdx b/sdk/ios.mdx index 4015679..3d88ab1 100644 --- a/sdk/ios.mdx +++ b/sdk/ios.mdx @@ -263,8 +263,6 @@ func setAdditionalData() async { Track custom events in your app: ```swift -import Foundation - func trackEvent() async { do { try await LinkrunnerSDK.shared.trackEvent( @@ -274,7 +272,7 @@ func trackEvent() async { "category": "electronics", "amount": 99.99 // Include amount as a number for revenue sharing with ad networks like Google and Meta ], - eventId: UUID().uuidString // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness + eventId: "550e8400-e29b-41d4-a716-446655440000" // Optional: Unique event identifier (String) for deduplication ) print("Event tracked successfully") } catch { @@ -284,7 +282,7 @@ func trackEvent() async { ``` - The `eventId` parameter should be a unique String identifier for each event. It's recommended to use `UUID().uuidString` to generate a unique identifier. This helps track and deduplicate events on the server side. + The `eventId` parameter is optional and should be a unique String identifier for each event. It's used for deduplication on the server side. If you're tracking the same event from both your app and backend, make sure to send the same `eventId` from the [Event Capture API](/api-reference/event-capture) as well. ### Revenue Sharing with Ad Networks @@ -292,8 +290,6 @@ func trackEvent() async { To enable revenue sharing with ad networks like Google Ads and Meta, include an `amount` parameter as a number in your custom event data. This allows the ad networks to optimize campaigns based on the revenue value of conversions: ```swift -import Foundation - func trackPurchaseEvent() async { do { try await LinkrunnerSDK.shared.trackEvent( @@ -303,7 +299,7 @@ func trackPurchaseEvent() async { "category": "electronics", "amount": 149.99 // Revenue amount as a number ], - eventId: UUID().uuidString // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness + eventId: "550e8400-e29b-41d4-a716-446655440000" // Optional: Unique event identifier (String) for deduplication ) print("Purchase event with revenue tracked successfully") } catch { @@ -470,7 +466,7 @@ struct ContentView: View { try await LinkrunnerSDK.shared.trackEvent( eventName: "button_clicked", eventData: ["screen": "home"], - eventId: UUID().uuidString // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness + eventId: "550e8400-e29b-41d4-a716-446655440000" // Optional: Unique event identifier (String) for deduplication ) print("Event tracked successfully") } catch { diff --git a/sdk/react-native.mdx b/sdk/react-native.mdx index f64fe89..e2e8ff4 100644 --- a/sdk/react-native.mdx +++ b/sdk/react-native.mdx @@ -210,19 +210,17 @@ This method allows you to connect user identities across different analytics and Track custom events in your app: ```javascript -import { v4 as uuidv4 } from 'uuid'; // or use crypto.randomUUID() if available - const trackEvent = async () => { await linkrunner.trackEvent( "purchase_initiated", // Event name { product_id: "12345", category: "electronics", amount: 99.99 }, // Optional: Event data, include amount as a number for revenue sharing with ad networks like Google and Meta - uuidv4() // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness + "550e8400-e29b-41d4-a716-446655440000" // Optional: Unique event identifier (String) for deduplication ); }; ``` - The `eventId` parameter should be a unique String identifier for each event. It's recommended to use a UUID library (like `uuid`) or `crypto.randomUUID()` to generate a unique identifier. This helps track and deduplicate events on the server side. + The `eventId` parameter is optional and should be a unique String identifier for each event. It's used for deduplication on the server side. If you're tracking the same event from both your app and backend, make sure to send the same `eventId` from the [Event Capture API](/api-reference/event-capture) as well. ### Revenue Sharing with Ad Networks @@ -230,8 +228,6 @@ const trackEvent = async () => { To enable revenue sharing with ad networks like Google Ads and Meta, include an `amount` parameter as a number in your custom event data. This allows the ad networks to optimize campaigns based on the revenue value of conversions: ```javascript -import { v4 as uuidv4 } from 'uuid'; // or use crypto.randomUUID() if available - const trackPurchaseEvent = async () => { await linkrunner.trackEvent( "purchase_completed", @@ -240,7 +236,7 @@ const trackPurchaseEvent = async () => { category: "electronics", amount: 149.99, // Revenue amount as a number }, - uuidv4() // Optional: Unique event identifier (String). Recommended to use UUID for uniqueness + "550e8400-e29b-41d4-a716-446655440000" // Optional: Unique event identifier (String) for deduplication ); }; ``` From 9b06e026e57b92b2cb75b81dd330c8dfc9833046 Mon Sep 17 00:00:00 2001 From: chetan Date: Thu, 19 Feb 2026 00:05:17 +0530 Subject: [PATCH 06/10] initial --- api-reference/custom-event-parameters.mdx | 139 ++++++++++++++++++++++ api-reference/event-capture.mdx | 121 +++++++++++++------ api-reference/revenue-tracking.mdx | 73 +++++++++++- docs.json | 1 + 4 files changed, 292 insertions(+), 42 deletions(-) create mode 100644 api-reference/custom-event-parameters.mdx diff --git a/api-reference/custom-event-parameters.mdx b/api-reference/custom-event-parameters.mdx new file mode 100644 index 0000000..f89ff8d --- /dev/null +++ b/api-reference/custom-event-parameters.mdx @@ -0,0 +1,139 @@ +--- +title: "Custom Event Parameters" +description: "Standard and custom event parameters for ad network data forwarding" +icon: "list" +--- + +Both `capture-event` and `capture-payment` APIs accept an `event_data` field — a flat key-value map of event parameters. Standard parameters are automatically mapped to each ad network's expected format. Custom parameters are passed through as-is. + +## How It Works + +1. Your SDK or server sends `event_data` with your event or payment +2. LinkRunner stores the full `event_data` in the database +3. Standard parameters are mapped to each ad network's field names +4. Custom parameters are passed through as-is to networks that support them +5. Revenue parameters (`amount`, `currency`) are handled automatically + +## Ad Network Parameter Mapping + +| You Send | Meta CAPI | Google Ads | TikTok | Snapchat | +| ---------------- | ---------------- | --------------------------- | ---------------------------------------- | -------------- | +| product_id | content_ids | item_id | content_ids | item_ids | +| order_id | order_id | order_id | order_id (purchase only) | transaction_id | +| content_type | content_type | category | auto-derived from content_ids | — | +| num_items | num_items | — | — | number_items | +| contents | contents | — | — | — | +| search_string | search_string | search_string | search_string (custom events only) | — | +| description | — | — | description | — | +| content_name | content_name | — | — | — | +| content_category | content_category | — | — | — | +| amount / value | value | value (query param) | value | value | +| currency | currency | currency_code (query param) | currency | currency | +| *any other key* | custom property | — | — | — | + +## Best Practices + +- Always include `product_id` for purchase events — Meta requires it for product catalog matching +- Include `order_id` for deduplication across ad networks +- Use `content_type: "product"` when `product_id` refers to a specific SKU, or `"product_group"` for product variants +- For `capture-payment`, the top-level `amount` and `currency` are used for revenue tracking — don't duplicate them in `event_data` +- Custom keys like `coupon_code`, `payment_plan`, `subscription_tier` are passed through to networks that support custom properties (currently Meta) + +## Examples + +### Purchase event (via capture-event) + +```json +{ + "event_name": "purchase_completed", + "event_data": { + "product_id": "sku_12345", + "order_id": "order_98765", + "content_type": "product", + "num_items": 2, + "amount": 49.99, + "currency": "USD", + "coupon_code": "SAVE20" + }, + "user_id": "user_12345" +} +``` + +### Payment with product details (via capture-payment) + +```json +{ + "user_id": "user_12345", + "payment_id": "pay_abc123", + "amount": 49.99, + "currency": "USD", + "type": "ONE_TIME", + "event_data": { + "product_id": "sku_12345", + "order_id": "order_98765", + "content_type": "product", + "num_items": 2 + } +} +``` + +### Add to cart + +```json +{ + "event_name": "cart_added", + "event_data": { + "product_id": "SKU-789", + "content_type": "product", + "num_items": 1, + "currency": "USD", + "amount": 29.99 + }, + "user_id": "user_12345" +} +``` + +### Search + +```json +{ + "event_name": "search_performed", + "event_data": { + "search_string": "running shoes", + "content_type": "product" + }, + "user_id": "user_12345" +} +``` + +### Subscription + +```json +{ + "user_id": "user_12345", + "payment_id": "sub_xyz789", + "amount": 9.99, + "currency": "USD", + "type": "SUBSCRIPTION_CREATED", + "event_data": { + "product_id": "plan_premium", + "order_id": "sub_xyz789", + "payment_plan": "monthly" + } +} +``` + +### Custom event with arbitrary params + +```json +{ + "event_name": "level_completed", + "event_data": { + "level_number": 5, + "score": 12500, + "time_spent_seconds": 180, + "difficulty": "hard" + }, + "user_id": "user_12345" +} +``` diff --git a/api-reference/event-capture.mdx b/api-reference/event-capture.mdx index 863c541..f55b34b 100644 --- a/api-reference/event-capture.mdx +++ b/api-reference/event-capture.mdx @@ -32,24 +32,24 @@ POST: /capture-event ```json { - "event_name": "product_viewed", + "event_name": "purchase_completed", "event_data": { "product_id": "ABC123", - "category": "electronics", - "amount": 249.99, - "currency": "USD", - "is_featured": true + "order_id": "ORD-12345", + "content_type": "product", + "num_items": 2, + "amount": 149.99, + "currency": "USD" }, - "user_id": "user_12345", - "event_id": "550e8400-e29b-41d4-a716-446655440000" + "user_id": "user_12345" } ``` -| Parameter | Type | Description | -| ---------- | ------ | --------------------------------------------------------- | -| event_name | string | **Required**. Name of the event to track | -| event_data | object | **Optional**. Additional data associated with the event | -| user_id | string | **Required**. User identifier to associate with the event | +| Parameter | Type | Description | +| ---------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| event_name | string | **Required**. Name of the event to track | +| event_data | object | **Optional**. Event parameters — standard keys are mapped to ad networks automatically, custom keys are passed through as-is | +| user_id | string | **Required**. User identifier to associate with the event | | event_id | string | **Optional**. Unique event identifier (String) for deduplication. If you're tracking the same event from both your app (SDK) and backend (API), make sure to send the same `event_id` from both sources | ### Responses @@ -87,31 +87,31 @@ Here are some common event names you might want to track: | `achievement_unlocked` | User unlocks an achievement | | `user_referred` | User refers someone | -## Revenue Sharing with Ad Networks - -To enable revenue sharing with ad networks like Google Ads and Meta, include an `amount` parameter as a number in your custom event data. This allows the ad networks to optimize campaigns based on the revenue value of conversions: - -```json -{ - "event_name": "purchase_completed", - "event_data": { - "product_id": "ABC123", - "category": "electronics", - "amount": 149.99 - }, - "user_id": "user_12345", - "event_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` +## Event Data Parameters - For revenue sharing with ad networks to work properly, ensure the `amount` parameter is passed as a number, not as a - string. + The `event_data` field accepts a flat key-value map. Standard parameters are recognized and automatically mapped to each ad network's expected format. Any additional keys are passed through as custom parameters. - - The `event_id` parameter is optional and should be a unique String identifier for each event. It's used for deduplication on the server side. If you're tracking the same event from both your app (SDK) and backend (API), make sure to send the same `event_id` from both sources to prevent duplicate event tracking. - +**Standard parameters:** + +| Parameter | Type | Description | +| ---------------- | ----------------- | -------------------------------------------------------------- | +| product_id | string or string[] | Product SKU/identifier | +| order_id | string | Transaction/order identifier | +| content_type | string | "product" or "product_group" | +| num_items | number | Number of items in the transaction | +| contents | array | Array of `{ id, quantity, item_price }` for multi-product events | +| search_string | string | Search query text | +| content_name | string | Name of the content/product | +| content_category | string | Category of the content/product | +| description | string | Description of the event or product | +| amount | number | Revenue value for the event | +| currency | string | ISO 4217 currency code | + +Any keys not listed above (e.g. `coupon_code`, `payment_plan`, `subscription_tier`) are passed through to ad networks that support custom properties (currently Meta). + +For the full parameter mapping across ad networks, see [Custom Event Parameters](/api-reference/custom-event-parameters). ## Best Practices @@ -134,14 +134,15 @@ fetch("https://api.linkrunner.io/api/v1/capture-event", { body: JSON.stringify({ event_name: "purchase_completed", event_data: { + product_id: "P-001", order_id: "ORD-12345", - product_ids: ["P-001", "P-002"], - total_amount: 125.99, + content_type: "product", + num_items: 1, + amount: 125.99, currency: "USD", - payment_method: "credit_card", + coupon_code: "SAVE20", }, user_id: "user_12345", - event_id: "550e8400-e29b-41d4-a716-446655440000", // Optional: Unique event identifier for deduplication. Use the same event_id if tracking from both SDK and API }), }) .then((response) => response.json()) @@ -149,6 +150,52 @@ fetch("https://api.linkrunner.io/api/v1/capture-event", { .catch((error) => console.error("Error:", error)); ``` +### Add to Cart + +```json +{ + "event_name": "cart_added", + "event_data": { + "product_id": "SKU-789", + "content_type": "product", + "num_items": 1, + "currency": "USD", + "amount": 29.99 + }, + "user_id": "user_12345" +} +``` + +### Search + +```json +{ + "event_name": "search_performed", + "event_data": { + "search_string": "running shoes", + "content_type": "product" + }, + "user_id": "user_12345" +} +``` + +### Subscription + +```json +{ + "event_name": "subscription_started", + "event_data": { + "product_id": "plan_premium_monthly", + "order_id": "sub_abc123", + "amount": 9.99, + "currency": "USD", + "payment_plan": "monthly", + "trial_period_days": 7 + }, + "user_id": "user_12345" +} +``` + ## Error Handling The API will return appropriate HTTP status codes along with error messages when issues occur: diff --git a/api-reference/revenue-tracking.mdx b/api-reference/revenue-tracking.mdx index 436fed9..193dbd8 100644 --- a/api-reference/revenue-tracking.mdx +++ b/api-reference/revenue-tracking.mdx @@ -31,11 +31,74 @@ POST: /capture-payment ```json { "user_id": "666", - "payment_id": "ABC", // optional but recommended - "amount": 25096, // Send amount in one currency only - "type": "FIRST_PAYMENT", // optional - // "type": "SECOND_PAYMENT", // optional - "status": "PAYMENT_COMPLETED" // optional + "payment_id": "ABC", + "amount": 25096, + "currency": "USD", + "type": "FIRST_PAYMENT", + "status": "PAYMENT_COMPLETED", + "event_data": { + "product_id": "sku_12345", + "order_id": "order_98765", + "content_type": "product", + "num_items": 1 + } +} +``` + +| Parameter | Type | Description | +| ---------- | ------ | ---------------------------------------------------------------------------------------------------------------------------- | +| user_id | string | **Required**. User identifier | +| payment_id | string | Optional but recommended. Unique payment identifier for deduplication | +| amount | number | Payment amount. Send in one currency only | +| currency | string | Optional. ISO 4217 currency code (e.g. "USD", "INR") | +| type | string | Optional. Payment type (defaults to DEFAULT) | +| status | string | Optional. Payment status (defaults to PAYMENT_COMPLETED) | +| event_data | object | Optional. Product and event parameters forwarded to ad networks (see [Standard Parameters](/api-reference/custom-event-parameters)) | + +### Event Data for Payments + + + The `event_data` field lets you send product-level details alongside your payment. Standard parameters are automatically mapped to each ad network's format. Custom keys are passed through as-is. + + + + `amount` and `currency` from the top-level request body are used for revenue tracking. Do not duplicate them inside `event_data`. + + +**Purchase with product details:** + +```json +{ + "user_id": "user_12345", + "payment_id": "pay_abc123", + "amount": 49.99, + "currency": "USD", + "type": "ONE_TIME", + "event_data": { + "product_id": "sku_12345", + "order_id": "order_98765", + "content_type": "product", + "num_items": 2, + "coupon_code": "SAVE20" + } +} +``` + +**Subscription with custom params:** + +```json +{ + "user_id": "user_12345", + "payment_id": "sub_xyz789", + "amount": 9.99, + "currency": "USD", + "type": "SUBSCRIPTION_CREATED", + "event_data": { + "product_id": "plan_premium", + "order_id": "sub_xyz789", + "payment_plan": "monthly", + "trial_converted": true + } } ``` diff --git a/docs.json b/docs.json index b678884..e538a1d 100644 --- a/docs.json +++ b/docs.json @@ -69,6 +69,7 @@ "api-reference/data-apis", "api-reference/revenue-tracking", "api-reference/event-capture", + "api-reference/custom-event-parameters", "api-reference/campaign-apis" ] } From f08a0e534b4a0a5f9b10808182129f636cae79d9 Mon Sep 17 00:00:00 2001 From: Chetan Bhosale <105789660+ChetanBhosale@users.noreply.github.com> Date: Thu, 19 Feb 2026 00:59:01 +0530 Subject: [PATCH 07/10] Update api-reference/revenue-tracking.mdx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- api-reference/revenue-tracking.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api-reference/revenue-tracking.mdx b/api-reference/revenue-tracking.mdx index 193dbd8..08b4f7d 100644 --- a/api-reference/revenue-tracking.mdx +++ b/api-reference/revenue-tracking.mdx @@ -49,7 +49,7 @@ POST: /capture-payment | ---------- | ------ | ---------------------------------------------------------------------------------------------------------------------------- | | user_id | string | **Required**. User identifier | | payment_id | string | Optional but recommended. Unique payment identifier for deduplication | -| amount | number | Payment amount. Send in one currency only | +| amount | number | Optional. Payment amount. Send in one currency only | | currency | string | Optional. ISO 4217 currency code (e.g. "USD", "INR") | | type | string | Optional. Payment type (defaults to DEFAULT) | | status | string | Optional. Payment status (defaults to PAYMENT_COMPLETED) | From 820c8398cda2962a7aa63b05600c1bb84b643aa0 Mon Sep 17 00:00:00 2001 From: Darshil Rathod Date: Thu, 19 Feb 2026 11:28:26 +0000 Subject: [PATCH 08/10] Rewrite custom event parameters docs and add writing guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rewrite custom-event-parameters.mdx for clarity: add "why" section, standard parameters table, Steps component, Notes/Warnings/Tips, contextual example descriptions, and related page links - Add CLAUDE.md with docs writing conventions for consistency - Fix LinkRunner → Linkrunner in prose text across SDK pages Co-Authored-By: Claude Opus 4.6 --- CLAUDE.md | 195 ++++++++++++++++++++++ api-reference/custom-event-parameters.mdx | 141 ++++++++++++---- sdk/android.mdx | 2 +- sdk/flutter.mdx | 2 +- sdk/ios.mdx | 2 +- sdk/react-native.mdx | 2 +- 6 files changed, 304 insertions(+), 40 deletions(-) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..66a1024 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,195 @@ +# Linkrunner Docs — Writing Guide + +This file defines the writing conventions for the Linkrunner documentation site. Follow these rules when creating or editing any page to keep the docs consistent. + +## Branding + +- Always write **Linkrunner** (capital L, lowercase r). Never "LinkRunner", "linkRunner", or "LINKRUNNER". +- Exception: SDK class names in code examples use the actual class name (`LinkRunner` in Kotlin/Dart/Swift, `linkrunner` in npm packages). Do not change these. +- The product is a **Mobile Measurement Partner (MMP)**. +- Dashboard URL: `https://dashboard.linkrunner.io` +- API base URL: `https://api.linkrunner.io/api/v1` +- Support email: `darshil@linkrunner.io` + +## File format + +- All pages are **MDX** files with YAML front matter. +- The site is built with [Mintlify](https://mintlify.com). Site config lives in `docs.json`. +- Every page must have front matter with `title`, `description`, and `icon`: + +```yaml +--- +title: "Page Title" +description: "One-sentence summary for SEO and navigation" +icon: "icon-name" +--- +``` + +- Icons come from the [Font Awesome](https://fontawesome.com/icons) set (Mintlify subset). + +## Tone and voice + +- **Professional but approachable.** Write like you're explaining something to a smart colleague, not writing a legal document. +- **Second person.** Address the reader as "you" / "your". +- **Active voice.** "Linkrunner sends a POST request" not "A POST request is sent by Linkrunner". +- **Imperative for instructions.** "Install the SDK", "Enter your App ID", "Click Save". +- **Short paragraphs.** Keep paragraphs to 1-3 sentences. Docs are scanned, not read cover-to-cover. +- **No filler words.** Cut "simply", "just", "easily", "please note that" unless they genuinely add meaning. +- **No emojis** in documentation content. + +## Structure + +Every page should follow this general flow (skip sections that don't apply): + +1. **Intro paragraph** — 1-2 sentences explaining what this page covers and why it matters. +2. **Core content** — The main explanation, setup steps, or reference material. +3. **Examples** — Real, runnable code examples with realistic data. +4. **Best practices** — Actionable recommendations (if applicable). +5. **Troubleshooting** — Common issues and solutions (if applicable). +6. **Related / Next steps** — Links to connected pages using ``. +7. **Support footer** — `For any help please reach out to [darshil@linkrunner.io](mailto:darshil@linkrunner.io)` + +### Headings + +- Use `##` (H2) for top-level sections. +- Use `###` (H3) for subsections. +- Avoid H4+ — if you need that much nesting, restructure the content. +- Use sentence case for headings: "Ad network parameter mapping" not "Ad Network Parameter Mapping". + +## Mintlify components + +Use these components where appropriate: + +### Notes, warnings, and tips + +```mdx + + Informational callout — useful context that isn't critical. + + + + Critical information the reader must not miss. Use sparingly. + + + + Helpful suggestion that improves the reader's workflow. + +``` + +### Cards + +Use `` with `` for navigation links and feature overviews: + +```mdx + + + Short description + + +``` + +### Tabs + +Use `` when showing platform-specific content (React Native, Flutter, iOS, Android): + +```mdx + + + Content for React Native + + + Content for Flutter + + +``` + +### Steps + +Use `` for sequential processes: + +```mdx + + + Description of what to do. + + +``` + +## Code examples + +- Use fenced code blocks with a language identifier: ` ```json `, ` ```javascript `, ` ```bash `, ` ```dart `, ` ```kotlin `, ` ```xml `, ` ```tsx `. +- Use realistic but fake data in examples (e.g. `user_12345`, `sku_12345`, `order_98765`). +- Keep examples minimal — show exactly what's needed, nothing more. +- Add a short sentence before each code block explaining what it demonstrates. +- When showing API payloads, use 4-space indentation in JSON. +- For inline code, use backticks: `event_data`, `capture-event`, `linkrunner-key`. + +## Tables + +- Use Markdown pipe tables for parameter references and field descriptions. +- Standard columns for API parameters: `Parameter`, `Type`, `Description`. +- Mark required fields with **Required** in bold inside the description. +- Use `string \| null` for nullable types in TypeScript type tables. + +```markdown +| Parameter | Type | Description | +|-----------|--------|--------------------------------------| +| user_id | string | **Required**. User identifier | +| event_id | string | Optional. Unique event ID | +``` + +## Links + +- Use relative paths for internal links: `[Event Capture API](/api-reference/event-capture)`. +- Use full URLs for external links: `[Meta for Developers](https://developers.facebook.com/)`. +- Use `mailto:` for email links: `[darshil@linkrunner.io](mailto:darshil@linkrunner.io)`. +- Dashboard settings links should include query params for direct navigation: `https://dashboard.linkrunner.io/settings?s=meta-integration`. + +## Naming conventions + +- Use **snake_case** for API parameter names, event names, and field names: `event_name`, `capture-event`, `product_id`. +- Use **kebab-case** for URL paths and file names: `custom-event-parameters.mdx`, `/api-reference/event-capture`. +- Ad network names: **Meta**, **Google Ads**, **TikTok**, **Snapchat**, **Apple Search Ads** (proper case). +- SDK names: **React Native**, **Flutter**, **iOS**, **Android**, **Expo**, **Web**. + +## Common patterns + +### API reference pages + +``` +- Base URL section +- Authentication section (with linkrunner-key header) +- Endpoint(s) with method and path +- Request body with JSON example +- Parameter table +- Response codes +- Sample response JSON +- TypeScript types (if applicable) +- Error handling table +- Support footer +``` + +### Feature/setup pages + +``` +- Overview paragraph with use cases +- Prerequisites or requirements (if any) +- Step-by-step setup (use or numbered headings) +- Platform-specific content in +- Configuration options (tables) +- Testing/verification +- Troubleshooting +- Support footer +``` + +### SDK guide pages + +``` +- Installation instructions per platform +- Initialization code +- Core methods (signup, attribution, events, payments) +- Platform-specific tabs +- Method reference table (Method | Where to call | When to call) +- Full working example +- Support footer +``` diff --git a/api-reference/custom-event-parameters.mdx b/api-reference/custom-event-parameters.mdx index f89ff8d..89b90e3 100644 --- a/api-reference/custom-event-parameters.mdx +++ b/api-reference/custom-event-parameters.mdx @@ -1,48 +1,96 @@ --- title: "Custom Event Parameters" -description: "Standard and custom event parameters for ad network data forwarding" +description: "Send product and event details with your events so Linkrunner can forward them to ad networks automatically" icon: "list" --- -Both `capture-event` and `capture-payment` APIs accept an `event_data` field — a flat key-value map of event parameters. Standard parameters are automatically mapped to each ad network's expected format. Custom parameters are passed through as-is. - -## How It Works - -1. Your SDK or server sends `event_data` with your event or payment -2. LinkRunner stores the full `event_data` in the database -3. Standard parameters are mapped to each ad network's field names -4. Custom parameters are passed through as-is to networks that support them -5. Revenue parameters (`amount`, `currency`) are handled automatically - -## Ad Network Parameter Mapping - -| You Send | Meta CAPI | Google Ads | TikTok | Snapchat | -| ---------------- | ---------------- | --------------------------- | ---------------------------------------- | -------------- | -| product_id | content_ids | item_id | content_ids | item_ids | -| order_id | order_id | order_id | order_id (purchase only) | transaction_id | -| content_type | content_type | category | auto-derived from content_ids | — | -| num_items | num_items | — | — | number_items | -| contents | contents | — | — | — | -| search_string | search_string | search_string | search_string (custom events only) | — | -| description | — | — | description | — | -| content_name | content_name | — | — | — | -| content_category | content_category | — | — | — | -| amount / value | value | value (query param) | value | value | -| currency | currency | currency_code (query param) | currency | currency | -| *any other key* | custom property | — | — | — | - -## Best Practices - -- Always include `product_id` for purchase events — Meta requires it for product catalog matching -- Include `order_id` for deduplication across ad networks -- Use `content_type: "product"` when `product_id` refers to a specific SKU, or `"product_group"` for product variants -- For `capture-payment`, the top-level `amount` and `currency` are used for revenue tracking — don't duplicate them in `event_data` -- Custom keys like `coupon_code`, `payment_plan`, `subscription_tier` are passed through to networks that support custom properties (currently Meta) +When you track events or payments through Linkrunner, you can include an `event_data` object with additional details like product IDs, order IDs, and item counts. Linkrunner automatically translates these parameters into the format each ad network expects, so you only need to send them once. + +## Why send event parameters? + +Ad networks like Meta, Google, TikTok, and Snapchat use event parameters to: + +- **Match conversions to product catalogs** — Meta uses `product_id` to connect purchases to your product feed +- **Deduplicate events** — `order_id` prevents the same purchase from being counted twice +- **Optimize ad delivery** — richer event data helps ad networks find higher-value users +- **Power reporting** — parameters like `content_type` and `content_category` improve breakdown reports + +## How it works + + + + Include an `event_data` object in your [`capture-event`](/api-reference/event-capture) or [`capture-payment`](/api-reference/revenue-tracking) API call. + + + The full `event_data` object is saved alongside the event in your Linkrunner dashboard. + + + Standard parameters (like `product_id`, `order_id`) are automatically translated to each network's field names. Custom parameters are passed through as-is to networks that support them. + + + The `amount` and `currency` fields are used for revenue reporting across all networks. + + + +## Standard parameters + +These parameters are recognized by Linkrunner and automatically mapped to each ad network's expected format. + +| Parameter | Type | Description | +|-----------|------|-------------| +| `product_id` | `string` or `string[]` | Product SKU or identifier. Required by Meta for product catalog matching. | +| `order_id` | `string` | Transaction or order identifier. Used for deduplication across ad networks. | +| `content_type` | `string` | Set to `"product"` for a specific SKU or `"product_group"` for product variants. | +| `num_items` | `number` | Number of items in the transaction. | +| `contents` | `array` | Array of `{ id, quantity, item_price }` objects for multi-product events. | +| `search_string` | `string` | The user's search query text. | +| `content_name` | `string` | Name of the content or product. | +| `content_category` | `string` | Category of the content or product. | +| `description` | `string` | Description of the event or product. | +| `amount` | `number` | Revenue value for the event. | +| `currency` | `string` | ISO 4217 currency code (e.g. `"USD"`, `"EUR"`). | + + + Any key not listed above (e.g. `coupon_code`, `payment_plan`, `subscription_tier`) is treated as a custom parameter and passed through to ad networks that support custom properties. Currently, only Meta accepts custom parameters. + + +## Ad network parameter mapping + +When you send a standard parameter, Linkrunner translates it to the field name each ad network expects. A dash (`—`) means that network does not support the parameter. + +| Linkrunner parameter | Meta CAPI | Google Ads | TikTok | Snapchat | +|----------------------|-----------|------------|--------|----------| +| `product_id` | `content_ids` | `item_id` | `content_ids` | `item_ids` | +| `order_id` | `order_id` | `order_id` | `order_id` (purchase only) | `transaction_id` | +| `content_type` | `content_type` | `category` | Auto-derived from `content_ids` | — | +| `num_items` | `num_items` | — | — | `number_items` | +| `contents` | `contents` | — | — | — | +| `search_string` | `search_string` | `search_string` | `search_string` (custom events only) | — | +| `description` | — | — | `description` | — | +| `content_name` | `content_name` | — | — | — | +| `content_category` | `content_category` | — | — | — | +| `amount` / `value` | `value` | `value` (query param) | `value` | `value` | +| `currency` | `currency` | `currency_code` (query param) | `currency` | `currency` | +| *any custom key* | Custom property | — | — | — | + + + You don't need to worry about these mappings. Just send your parameters using the names in the "Linkrunner parameter" column and Linkrunner handles the rest. + + +## Best practices + +- **Always include `product_id` for purchase events.** Meta requires it for product catalog matching. If you skip it, Meta can't connect the purchase to a product in your catalog. +- **Include `order_id` for deduplication.** Ad networks use this to ensure the same transaction isn't counted twice, especially when events are sent from both your app and server. +- **Use `content_type` to describe what `product_id` refers to.** Set it to `"product"` for a specific SKU, or `"product_group"` when the ID covers multiple variants. +- **Don't duplicate `amount` and `currency` inside `event_data` for payments.** When using [`capture-payment`](/api-reference/revenue-tracking), the top-level `amount` and `currency` fields are used for revenue tracking. Putting them in `event_data` as well can cause double-counting. +- **Custom keys are forwarded to Meta only.** Parameters like `coupon_code` or `subscription_tier` are passed through as custom properties to Meta CAPI. Other networks do not receive them. ## Examples ### Purchase event (via capture-event) +Send product details alongside a purchase event tracked from your backend. + ```json { "event_name": "purchase_completed", @@ -61,6 +109,8 @@ Both `capture-event` and `capture-payment` APIs accept an `event_data` field — ### Payment with product details (via capture-payment) +When using the payment API, put product details in `event_data` and keep `amount`/`currency` at the top level. + ```json { "user_id": "user_12345", @@ -77,6 +127,10 @@ Both `capture-event` and `capture-payment` APIs accept an `event_data` field — } ``` + + Notice that `amount` and `currency` are **not** inside `event_data` here. For `capture-payment`, always use the top-level fields for revenue. + + ### Add to cart ```json @@ -123,7 +177,9 @@ Both `capture-event` and `capture-payment` APIs accept an `event_data` field — } ``` -### Custom event with arbitrary params +### Custom event with arbitrary parameters + +Any event can include custom key-value pairs. These are stored by Linkrunner and forwarded to Meta as custom properties. ```json { @@ -137,3 +193,16 @@ Both `capture-event` and `capture-payment` APIs accept an `event_data` field — "user_id": "user_12345" } ``` + +## Related + + + + Track custom events from your backend + + + Capture payments and revenue data + + + +For any help please reach out to [darshil@linkrunner.io](mailto:darshil@linkrunner.io) diff --git a/sdk/android.mdx b/sdk/android.mdx index a63950e..bb80113 100644 --- a/sdk/android.mdx +++ b/sdk/android.mdx @@ -179,7 +179,7 @@ class MyApplication : Application() { ### SDK Signing Parameters (Optional) -For enhanced security, the LinkRunner SDK requires the following signing parameters during initialization: +For enhanced security, the Linkrunner SDK requires the following signing parameters during initialization: - **`secretKey`**: A unique secret key used for request signing and authentication - **`keyId`**: A unique identifier for the key pair used in the signing process diff --git a/sdk/flutter.mdx b/sdk/flutter.mdx index 972d09b..32eb9b1 100644 --- a/sdk/flutter.mdx +++ b/sdk/flutter.mdx @@ -126,7 +126,7 @@ You'll need your [project token](https://dashboard.linkrunner.io/dashboard?m=doc ### SDK Signing Parameters (Optional) -For enhanced security, the LinkRunner SDK requires the following signing parameters during initialization: +For enhanced security, the Linkrunner SDK requires the following signing parameters during initialization: - **`secretKey`**: A unique secret key used for request signing and authentication - **`keyId`**: A unique identifier for the key pair used in the signing process diff --git a/sdk/ios.mdx b/sdk/ios.mdx index 3d88ab1..7cfa927 100644 --- a/sdk/ios.mdx +++ b/sdk/ios.mdx @@ -122,7 +122,7 @@ struct MyApp: App { ### SDK Signing Parameters (Optional) -For enhanced security, the LinkRunner SDK requires the following signing parameters during initialization: +For enhanced security, the Linkrunner SDK requires the following signing parameters during initialization: - **`secretKey`**: A unique secret key used for request signing and authentication - **`keyId`**: A unique identifier for the key pair used in the signing process diff --git a/sdk/react-native.mdx b/sdk/react-native.mdx index e2e8ff4..b4cd9ab 100644 --- a/sdk/react-native.mdx +++ b/sdk/react-native.mdx @@ -64,7 +64,7 @@ You can find your project token [here](https://dashboard.linkrunner.io/dashboard ### SDK Signing Parameters (Optional) -For enhanced security, the LinkRunner SDK requires the following signing parameters during initialization: +For enhanced security, the Linkrunner SDK requires the following signing parameters during initialization: - **`secretKey`**: A unique secret key used for request signing and authentication - **`keyId`**: A unique identifier for the key pair used in the signing process From daec62112889a2617e3a214271737bb61bda70bf Mon Sep 17 00:00:00 2001 From: Darshil Rathod Date: Fri, 20 Feb 2026 11:53:07 +0000 Subject: [PATCH 09/10] Add link redirection documentation page Co-Authored-By: Claude Opus 4.6 --- docs.json | 1 + features/link-redirection.mdx | 116 ++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 features/link-redirection.mdx diff --git a/docs.json b/docs.json index 60382b6..ce7dcbb 100644 --- a/docs.json +++ b/docs.json @@ -38,6 +38,7 @@ "pages": ["features/deep-linking-setup", "features/deep-linking-verification"] }, "features/deferred-deep-linking", + "features/link-redirection", "features/referral-codes", "features/custom-store-listing", "features/uninstall-tracking", diff --git a/features/link-redirection.mdx b/features/link-redirection.mdx new file mode 100644 index 0000000..9bcf1b5 --- /dev/null +++ b/features/link-redirection.mdx @@ -0,0 +1,116 @@ +--- +title: "Link redirection" +description: "How Linkrunner routes users to the right destination when they click a campaign link" +icon: "route" +--- + +When someone clicks a Linkrunner campaign link, the system detects their device, records the click for attribution, and redirects them to the best destination — whether that's your app, the app store, or your website. + +## How it works + + + + Linkrunner extracts the campaign identifier from the link. This can be a `?c=` query parameter or a single path segment (e.g., `get.yourapp.com/AbCdEf`). + + + The system reads the user agent to determine the device type (mobile, tablet, or desktop), the operating system (iOS or Android), and whether the click came from an in-app browser like Instagram, Facebook, TikTok, Snapchat, LinkedIn, or Twitter. + + + Linkrunner records the click with device info, operating system, browser details, referrer URL, advertising IDs (`gaid` / `idfa`), ad network click IDs, and a unique attribution identifier (`lr_ia_id`) used to match the click to a future install. + + + Based on the device type and browser context, Linkrunner routes the user to the appropriate destination using the fallback chains described below. + + + +## Routing by platform + + + + Social media apps like Instagram and TikTok open links in their own built-in browser, which blocks normal redirects to the app store or your installed app. Linkrunner handles this by rendering an intermediary page. + + ### What happens + + 1. The intermediary page loads and immediately attempts to open your app via a deep link (custom URI scheme). + 2. If the app is installed and opens, the page detects this and stops. + 3. If the app does not open within the timeout, the page redirects to the App Store (iOS) or Play Store (Android). + 4. The user can also tap the **"Get the App"** button to go to the store immediately. + + ### Timeout behavior + + - **iOS**: 300ms timeout before falling back to the App Store. + - **Android**: 5-second timeout with a visible countdown before falling back to the Play Store. + + + The intermediary page can be customized to match your brand. See [Social media intermediary page](/features/social-media-intermediary-page) for details. + + + This flow also applies when the **"Open in app"** option is enabled on a campaign, regardless of which browser the user is in. + + + On mobile and tablet devices using a regular browser (Safari, Chrome, etc.), Linkrunner redirects through a fallback chain without showing an intermediary page. + + ### iOS + + 1. **iOS redirect URL** — A custom redirect URL configured on the campaign + 2. **App Store link** — Your app's App Store page (with custom store listing if configured) + 3. **Campaign website** — The website URL set on the campaign + 4. **Project website** — Your project's default website (with the deep link path appended if a deferred deep link is configured) + + ### Android + + 1. **Android redirect URL** — A custom redirect URL configured on the campaign + 2. **Play Store link** — Your app's Play Store page (with UTM parameters and custom store listing if configured) + 3. **Campaign website** — The website URL set on the campaign + 4. **Project website** — Your project's default website (with the deep link path appended if a deferred deep link is configured) + + Linkrunner uses the first available URL in the chain. If a platform-specific redirect URL is set on the campaign, it takes priority over the store link. + + + Desktop visitors are redirected through a different fallback chain since they cannot install a mobile app directly. + + 1. **Campaign website** — The website URL set on the campaign + 2. **Project website** — Your project's default website (with the deep link path appended if a deferred deep link is configured) + 3. **Store link** — Falls back to the appropriate store page if no website is configured + + + +## Redirect priority + +| Scenario | Priority 1 | Priority 2 | Priority 3 | Priority 4 | +|----------|-----------|-----------|-----------|-----------| +| In-app browser | Deep link into app | App Store / Play Store | Campaign website | Project website | +| iOS (regular browser) | iOS redirect URL | App Store | Campaign website | Project website | +| Android (regular browser) | Android redirect URL | Play Store | Campaign website | Project website | +| Desktop | Campaign website | Project website | Store link | — | + +## Troubleshooting + +**Store redirect not working?** Verify that your App Store and Play Store links are configured correctly in [project settings](https://dashboard.linkrunner.io/settings). The Play Store link must include `google.com` in the URL. + +**Deep link not opening the app?** Ensure your app has a custom URI scheme configured and that the Linkrunner SDK is initialized. See [Deep linking setup](/features/deep-linking-setup) for configuration steps. + +**Blank intermediary page?** This usually means the app link or store link failed to load. Check that your custom URI scheme and store links are set correctly in project settings. + +**Attribution not matching?** Make sure the Linkrunner SDK is initialized before calling `getAttributionData()`. The app must be installed through the campaign link — direct store installs cannot be attributed. + +**Desktop users seeing the store instead of your website?** Add a website URL to your campaign or project settings. Without a website configured, Linkrunner falls back to the store link on all platforms. + +--- + + + + Customize the intermediary page for in-app browsers + + + Configure deep links to open specific screens in your app + + + Route users to content after they install your app + + + Show tailored store pages for different campaigns + + + +For any help please reach out to [darshil@linkrunner.io](mailto:darshil@linkrunner.io) From e19ee90f4ca8f5e59fd716613b65bc439d1e0142 Mon Sep 17 00:00:00 2001 From: Darshil Rathod Date: Fri, 20 Feb 2026 11:53:52 +0000 Subject: [PATCH 10/10] Revert "Add link redirection documentation page" This reverts commit daec62112889a2617e3a214271737bb61bda70bf. --- docs.json | 1 - features/link-redirection.mdx | 116 ---------------------------------- 2 files changed, 117 deletions(-) delete mode 100644 features/link-redirection.mdx diff --git a/docs.json b/docs.json index ce7dcbb..60382b6 100644 --- a/docs.json +++ b/docs.json @@ -38,7 +38,6 @@ "pages": ["features/deep-linking-setup", "features/deep-linking-verification"] }, "features/deferred-deep-linking", - "features/link-redirection", "features/referral-codes", "features/custom-store-listing", "features/uninstall-tracking", diff --git a/features/link-redirection.mdx b/features/link-redirection.mdx deleted file mode 100644 index 9bcf1b5..0000000 --- a/features/link-redirection.mdx +++ /dev/null @@ -1,116 +0,0 @@ ---- -title: "Link redirection" -description: "How Linkrunner routes users to the right destination when they click a campaign link" -icon: "route" ---- - -When someone clicks a Linkrunner campaign link, the system detects their device, records the click for attribution, and redirects them to the best destination — whether that's your app, the app store, or your website. - -## How it works - - - - Linkrunner extracts the campaign identifier from the link. This can be a `?c=` query parameter or a single path segment (e.g., `get.yourapp.com/AbCdEf`). - - - The system reads the user agent to determine the device type (mobile, tablet, or desktop), the operating system (iOS or Android), and whether the click came from an in-app browser like Instagram, Facebook, TikTok, Snapchat, LinkedIn, or Twitter. - - - Linkrunner records the click with device info, operating system, browser details, referrer URL, advertising IDs (`gaid` / `idfa`), ad network click IDs, and a unique attribution identifier (`lr_ia_id`) used to match the click to a future install. - - - Based on the device type and browser context, Linkrunner routes the user to the appropriate destination using the fallback chains described below. - - - -## Routing by platform - - - - Social media apps like Instagram and TikTok open links in their own built-in browser, which blocks normal redirects to the app store or your installed app. Linkrunner handles this by rendering an intermediary page. - - ### What happens - - 1. The intermediary page loads and immediately attempts to open your app via a deep link (custom URI scheme). - 2. If the app is installed and opens, the page detects this and stops. - 3. If the app does not open within the timeout, the page redirects to the App Store (iOS) or Play Store (Android). - 4. The user can also tap the **"Get the App"** button to go to the store immediately. - - ### Timeout behavior - - - **iOS**: 300ms timeout before falling back to the App Store. - - **Android**: 5-second timeout with a visible countdown before falling back to the Play Store. - - - The intermediary page can be customized to match your brand. See [Social media intermediary page](/features/social-media-intermediary-page) for details. - - - This flow also applies when the **"Open in app"** option is enabled on a campaign, regardless of which browser the user is in. - - - On mobile and tablet devices using a regular browser (Safari, Chrome, etc.), Linkrunner redirects through a fallback chain without showing an intermediary page. - - ### iOS - - 1. **iOS redirect URL** — A custom redirect URL configured on the campaign - 2. **App Store link** — Your app's App Store page (with custom store listing if configured) - 3. **Campaign website** — The website URL set on the campaign - 4. **Project website** — Your project's default website (with the deep link path appended if a deferred deep link is configured) - - ### Android - - 1. **Android redirect URL** — A custom redirect URL configured on the campaign - 2. **Play Store link** — Your app's Play Store page (with UTM parameters and custom store listing if configured) - 3. **Campaign website** — The website URL set on the campaign - 4. **Project website** — Your project's default website (with the deep link path appended if a deferred deep link is configured) - - Linkrunner uses the first available URL in the chain. If a platform-specific redirect URL is set on the campaign, it takes priority over the store link. - - - Desktop visitors are redirected through a different fallback chain since they cannot install a mobile app directly. - - 1. **Campaign website** — The website URL set on the campaign - 2. **Project website** — Your project's default website (with the deep link path appended if a deferred deep link is configured) - 3. **Store link** — Falls back to the appropriate store page if no website is configured - - - -## Redirect priority - -| Scenario | Priority 1 | Priority 2 | Priority 3 | Priority 4 | -|----------|-----------|-----------|-----------|-----------| -| In-app browser | Deep link into app | App Store / Play Store | Campaign website | Project website | -| iOS (regular browser) | iOS redirect URL | App Store | Campaign website | Project website | -| Android (regular browser) | Android redirect URL | Play Store | Campaign website | Project website | -| Desktop | Campaign website | Project website | Store link | — | - -## Troubleshooting - -**Store redirect not working?** Verify that your App Store and Play Store links are configured correctly in [project settings](https://dashboard.linkrunner.io/settings). The Play Store link must include `google.com` in the URL. - -**Deep link not opening the app?** Ensure your app has a custom URI scheme configured and that the Linkrunner SDK is initialized. See [Deep linking setup](/features/deep-linking-setup) for configuration steps. - -**Blank intermediary page?** This usually means the app link or store link failed to load. Check that your custom URI scheme and store links are set correctly in project settings. - -**Attribution not matching?** Make sure the Linkrunner SDK is initialized before calling `getAttributionData()`. The app must be installed through the campaign link — direct store installs cannot be attributed. - -**Desktop users seeing the store instead of your website?** Add a website URL to your campaign or project settings. Without a website configured, Linkrunner falls back to the store link on all platforms. - ---- - - - - Customize the intermediary page for in-app browsers - - - Configure deep links to open specific screens in your app - - - Route users to content after they install your app - - - Show tailored store pages for different campaigns - - - -For any help please reach out to [darshil@linkrunner.io](mailto:darshil@linkrunner.io)