Attribution & Analytics
ChottuLink gives you full-funnel visibility into how users discover, install, and engage with your app. There are three layers:
- Install Attribution — at first launch, the SDK determines whether the install was organic or came from a ChottuLink click (
ATTRIBUTED). It captures the originating link, UTM parameters, and match type, and makes this data available instantly viagetAttributionData(). - Event Analytics — after attribution, you can identify users, track signups, record revenue conversions, and send custom events. All events are queued locally and uploaded in batches, surviving network outages and app restarts.
- Dashboard & Reporting — view every click, first open, lead, and conversion in the ChottuLink Events dashboard, and trace each attributed install to a customer record.
What is Attribution?
Attribution answers the question: "Which link caused this user to install my app?" It also helps answer: "How many signups, conversions, and how much revenue did that link generate?"
When a user installs your app, ChottuLink checks whether they previously clicked a ChottuLink link before the install.
There are two possible outcomes:
- ORGANIC — no matching ChottuLink click was found. The user found and installed your app through another channel (App Store search, word of mouth, etc.).
- ATTRIBUTED — the install is linked to a specific ChottuLink click. The originating link's data — including the short URL, destination URL, and any UTM parameters — is attached to the install record.
Why it matters: Attribution connects your marketing spend to real outcomes. Instead of guessing which campaigns drive installs, you can see exactly which links, UTM sources, and creatives are working — and which aren't. You can then tie post-install actions (signups, purchases) back to the original campaign that acquired the user.
SDK Reference
The following methods are available in the ChottuLink SDK for reading attribution data and tracking post-install events.
getAttributionData()
Returns the cached attribution result for the current install. This is a synchronous call — no network request is made.
Call getAttributionData() after SDK initialization — typically when your app's first screen becomes visible.
On subsequent app launches the result is a fast, cached read. On the very first launch, the async attribution fetch runs in the background and may not have completed in the first second or two. If the method returns nil immediately after a cold start:
- Retry once after a 1–2 second delay, or
- Use your SDK's initialization callback, which fires after attribution is available — see your platform's setup guide.
Returns nil / null / the platform equivalent if:
- The SDK has not been initialized
- The user has opted out of tracking via
optOut(true) - Attribution has not yet completed on this launch (rare — only possible in the very first seconds after a cold start before the async fetch finishes)
- iOS
- Android
- Flutter
- React Native
- Capacitor
- Unity
import ChottuLinkSDK
if let attribution = ChottuLink.getAttributionData() {
if attribution.isAttributed {
// Install came from a ChottuLink click
print("Attribution type: \(attribution.attributionType)") // "ATTRIBUTED"
print("Clicked link: \(attribution.clickedShortUrl ?? "N/A")")
print("Destination: \(attribution.destinationUrl ?? "N/A")")
// UTM parameters
print("UTM Source: \(attribution.utmSource ?? "N/A")")
print("UTM Medium: \(attribution.utmMedium ?? "N/A")")
print("UTM Campaign: \(attribution.utmCampaign ?? "N/A")")
} else {
// Organic install — no matching ChottuLink click found
print("Attribution type: \(attribution.attributionType)") // "ORGANIC"
}
} else {
// SDK not initialized, or user has opted out
print("Attribution data not available")
}
Return type: CLAttributionData?
CLAttributionData properties
| Property | Type | Description |
|---|---|---|
attributionType | String | "ORGANIC" or "ATTRIBUTED" |
isAttributed | Bool | true when attributionType == "ATTRIBUTED" |
matchFound | Bool | Whether a matching click was found |
installId | String? | Server-assigned install ID |
shortUrl | String? | Canonical short URL clicked |
clickedShortUrl | String? | Raw clicked URL with query params intact |
destinationUrl | String? | Final destination URL |
destinationWithUtm | String? | Destination URL with UTM params appended |
utmSource | String? | UTM source |
utmMedium | String? | UTM medium |
utmCampaign | String? | UTM campaign |
utmTerm | String? | UTM term |
utmContent | String? | UTM content |
import android.util.Log;
import com.chottulink.lib.ChottuLink;
// After SDK initialization — typically in onCreate of your main Activity
ChottuLink.AttributionData attribution = ChottuLink.getAttributionData();
if (attribution != null) {
if (attribution.isAttributed()) {
// Install came from a ChottuLink click
Log.d("App", "Attribution type: " + attribution.getAttributionType()); // "ATTRIBUTED"
Log.d("App", "Clicked link: " + attribution.getClickedShortUrl());
Log.d("App", "Destination: " + attribution.getDestinationUrl());
// UTM parameters
Log.d("App", "UTM Source: " + attribution.getUtmSource());
Log.d("App", "UTM Medium: " + attribution.getUtmMedium());
Log.d("App", "UTM Campaign: " + attribution.getUtmCampaign());
} else {
// Organic install — no matching ChottuLink click found
Log.d("App", "Attribution type: " + attribution.getAttributionType()); // "ORGANIC"
}
} else {
// SDK not initialized, or user has opted out
Log.d("App", "Attribution data not available");
}
Return type: ChottuLink.AttributionData (returns null if the SDK is not initialized, attribution is not yet available, or the user has opted out)
AttributionData methods
| Method | Return type | Description |
|---|---|---|
getAttributionType() | String | "ORGANIC" or "ATTRIBUTED" |
isAttributed() | boolean | true when attributionType == "ATTRIBUTED" |
isMatchFound() | boolean | Whether a matching click was found |
getInstallId() | String | Server-assigned install ID |
getShortUrl() | String | Canonical short URL clicked |
getClickedShortUrl() | String | Raw clicked URL with query params intact |
getDestinationUrl() | String | Final destination URL |
getDestinationWithUtm() | String | Destination URL with UTM params appended |
getUtmSource() | String | UTM source |
getUtmMedium() | String | UTM medium |
getUtmCampaign() | String | UTM campaign |
getUtmTerm() | String | UTM term |
getUtmContent() | String | UTM content |
getAttributionData() is synchronous — no network request is made. String fields return null when the data is not present; always null-check before use.
import 'package:chottu_link/chottu_link.dart';
final attribution = await ChottuLink.getAttributionData();
if (attribution != null) {
if (attribution.isAttributed) {
// Install came from a ChottuLink click
print('Attribution type: ${attribution.attributionType}'); // "ATTRIBUTED"
print('Clicked link: ${attribution.clickedShortUrl ?? 'N/A'}');
print('Destination: ${attribution.destinationUrl ?? 'N/A'}');
// UTM parameters
print('UTM Source: ${attribution.utmSource ?? 'N/A'}');
print('UTM Medium: ${attribution.utmMedium ?? 'N/A'}');
print('UTM Campaign: ${attribution.utmCampaign ?? 'N/A'}');
} else {
// Organic install — no matching ChottuLink click found
print('Attribution type: ${attribution.attributionType}'); // "ORGANIC"
}
} else {
// SDK not initialized, or user has opted out
print('Attribution data not available');
}
Return type: Future<AttributionData?>
AttributionData properties
| Property | Type | Description |
|---|---|---|
attributionType | String? | "ORGANIC" or "ATTRIBUTED" |
isAttributed | bool | true when attributionType == "ATTRIBUTED" |
matchFound | bool | Whether a matching click was found |
installId | String? | Server-assigned install ID |
shortUrl | String? | Canonical short URL clicked |
clickedShortUrl | String? | Raw clicked URL with query params intact |
destinationUrl | String? | Final destination URL |
destinationWithUtm | String? | Destination URL with UTM params appended |
utmSource | String? | UTM source |
utmMedium | String? | UTM medium |
utmCampaign | String? | UTM campaign |
utmTerm | String? | UTM term |
utmContent | String? | UTM content |
import { ChottuLink } from 'react-native-chottulink-sdk';
const attribution = await ChottuLink.getAttributionData();
if (attribution) {
if (attribution.isAttributed) {
// Install came from a ChottuLink click
console.log('Attribution type:', attribution.attributionType); // "ATTRIBUTED"
console.log('Clicked link:', attribution.clickedShortUrl ?? 'N/A');
console.log('Destination:', attribution.destinationUrl ?? 'N/A');
// UTM parameters
console.log('UTM Source:', attribution.utmSource ?? 'N/A');
console.log('UTM Medium:', attribution.utmMedium ?? 'N/A');
console.log('UTM Campaign:', attribution.utmCampaign ?? 'N/A');
} else {
// Organic install — no matching ChottuLink click found
console.log('Attribution type:', attribution.attributionType); // "ORGANIC"
}
} else {
// SDK not initialized, opted out, or attribution not yet available
console.log('Attribution data not available');
}
Return type: Promise<RnCLAttributionData | null>
RnCLAttributionData properties
| Property | Type | Description |
|---|---|---|
attributionType | string | "ORGANIC" or "ATTRIBUTED" |
isAttributed | boolean | true when attributionType === "ATTRIBUTED" |
matchFound | boolean | Whether a matching click was found |
installId | string | null | Server-assigned install ID |
shortUrl | string | null | Canonical short URL clicked |
clickedShortUrl | string | null | Raw clicked URL with query params intact |
destinationUrl | string | null | Final destination URL |
destinationWithUtm | string | null | Destination URL with UTM params appended |
utmSource | string | null | UTM source |
utmMedium | string | null | UTM medium |
utmCampaign | string | null | UTM campaign |
utmTerm | string | null | UTM term |
utmContent | string | null | UTM content |
import { ChottuLinkIonicSDK } from 'capacitor-chottulink-sdk';
const attribution = await ChottuLinkIonicSDK.getAttributionData();
if (attribution) {
if (attribution.isAttributed) {
// Install came from a ChottuLink click
console.log('Attribution type:', attribution.attributionType); // "ATTRIBUTED"
console.log('Clicked link:', attribution.clickedShortUrl ?? 'N/A');
console.log('Destination:', attribution.destinationUrl ?? 'N/A');
// UTM parameters
console.log('UTM Source:', attribution.utmSource ?? 'N/A');
console.log('UTM Medium:', attribution.utmMedium ?? 'N/A');
console.log('UTM Campaign:', attribution.utmCampaign ?? 'N/A');
} else {
// Organic install — no matching ChottuLink click found
console.log('Attribution type:', attribution.attributionType); // "ORGANIC"
}
} else {
// SDK not initialized, opted out, or attribution not yet available
console.log('Attribution data not available');
}
Return type: Promise<CLAttributionData | null>
CLAttributionData properties
| Property | Type | Description |
|---|---|---|
attributionType | string | "ORGANIC" or "ATTRIBUTED" |
isAttributed | boolean | true when attributionType === "ATTRIBUTED" |
matchFound | boolean | Whether a matching click was found |
installId | string | null | Server-assigned install ID |
shortUrl | string | null | Canonical short URL clicked |
clickedShortUrl | string | null | Raw clicked URL with query params intact |
destinationUrl | string | null | Final destination URL |
destinationWithUtm | string | null | Destination URL with UTM params appended |
utmSource | string | null | UTM source |
utmMedium | string | null | UTM medium |
utmCampaign | string | null | UTM campaign |
utmTerm | string | null | UTM term |
utmContent | string | null | UTM content |
using UnityEngine;
// Get attribution data — result delivered via onSuccess callback
ChottuLink.GetAttributionData(
onSuccess: attribution =>
{
if (attribution.isAttributed)
{
// Install came from a ChottuLink click
Debug.Log("Attribution type: " + attribution.attributionType); // "ATTRIBUTED"
Debug.Log("Clicked link: " + (attribution.clickedShortUrl ?? "N/A"));
Debug.Log("Destination: " + (attribution.destinationUrl ?? "N/A"));
// UTM parameters
Debug.Log("UTM Source: " + (attribution.utmSource ?? "N/A"));
Debug.Log("UTM Medium: " + (attribution.utmMedium ?? "N/A"));
Debug.Log("UTM Campaign: " + (attribution.utmCampaign ?? "N/A"));
}
else
{
// Organic install — no matching ChottuLink click found
Debug.Log("Attribution type: " + attribution.attributionType); // "ORGANIC"
}
},
onError: error =>
{
// SDK not initialized, user opted out, or attribution not yet available
Debug.LogWarning("Attribution data not available: " + error);
}
);
Signature: GetAttributionData(Action<AttributionData> onSuccess, Action<string> onError)
AttributionData fields
| Field | Type | Description |
|---|---|---|
attributionType | string | "ORGANIC" or "ATTRIBUTED" |
isAttributed | bool | true when attributionType == "ATTRIBUTED" |
matchFound | bool | Whether a matching click was found |
installId | string | Server-assigned install ID |
shortUrl | string | Canonical short URL clicked |
clickedShortUrl | string | Raw clicked URL with query params intact |
destinationUrl | string | Final destination URL |
destinationWithUtm | string | Destination URL with UTM params appended |
utmSource | string | UTM source |
utmMedium | string | UTM medium |
utmCampaign | string | UTM campaign |
utmTerm | string | UTM term |
utmContent | string | UTM content |
String fields ( installId, shortUrl, etc.) are null when not present — check before use. The onError callback fires if the SDK is not initialised, the user has opted out, or attribution is not yet available.
identify()
Links the anonymous device to a known user in your system. Call this after a user logs in or signs up. The customer ID is persisted locally and included in all subsequent tracked events, enabling you to connect attribution and event data to real users in your analytics.
The id field is required and must be non-empty. Calls with an empty or blank id are silently ignored.
- iOS
- Android
- Flutter
- React Native
- Capacitor
- Unity
import ChottuLinkSDK
// Minimal — only the user ID is required
ChottuLink.identify(CLCustomerMeta(id: "user_123"))
// Full — with all optional fields
ChottuLink.identify(CLCustomerMeta(
id: "user_123",
name: "Jane Doe",
email: "jane@example.com",
phone: "+14155550100",
emailSha256: "b4c9a...", // Optionally share SHA-256 hash of the email instead of raw email
phoneSha256: "e3d8f..." // Optionally share SHA-256 hash of the phone instead of raw phone
))
CLCustomerMeta parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | String | ✅ Yes | Your system's unique identifier for this user. |
name | String? | No | User's display name. |
email | String? | No | User's email address. |
phone | String? | No | User's phone number. |
emailSha256 | String? | No | Optionally share SHA-256 hash of the email instead of raw email |
phoneSha256 | String? | No | Optionally share SHA-256 hash of the phone instead of raw phone. |
import com.chottulink.lib.ChottuLink;
// Minimal — only the user ID is required
ChottuLink.identify(
new ChottuLink.CustomerMeta.Builder()
.setId("user_123")
.build()
);
// Full — with all optional fields
ChottuLink.identify(
new ChottuLink.CustomerMeta.Builder()
.setId("user_123")
.setName("Jane Doe")
.setEmail("jane@example.com")
.setPhone("+14155550100")
.setEmailSha256("b4c9a...") // Optionally share SHA-256 hash of the email instead of raw email
.setPhoneSha256("e3d8f...") // Optionally share SHA-256 hash of the phone instead of raw phone
.build()
);
CustomerMeta.Builder methods
| Method | Parameter type | Required | Description |
|---|---|---|---|
setId(String) | String | ✅ Yes | Your system's unique identifier for this user. |
setName(String) | String | No | User's display name. |
setEmail(String) | String | No | User's email address. |
setPhone(String) | String | No | User's phone number. |
setEmailSha256(String) | String | No | Optionally share SHA-256 hash of the email instead of raw email |
setPhoneSha256(String) | String | No | Optionally share SHA-256 hash of the phone instead of raw phone. |
import 'package:chottu_link/chottu_link.dart';
import 'package:chottu_link/model/customer_meta.dart';
// Minimal — only the user ID is required
await ChottuLink.identify(const CustomerMeta(id: 'user_123'));
// Full — with all optional fields
await ChottuLink.identify(const CustomerMeta(
id: 'user_123',
name: 'Jane Doe',
email: 'jane@example.com',
phone: '+14155550100',
emailSha256: 'b4c9a...', // Optionally share SHA-256 hash of the email instead of raw email
phoneSha256: 'e3d8f...', // Optionally share SHA-256 hash of the phone instead of raw phone
));
Return type: Future<void>
CustomerMeta parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | String | ✅ Yes | Your system's unique identifier for this user. |
name | String? | No | User's display name. |
email | String? | No | User's email address. |
phone | String? | No | User's phone number. |
emailSha256 | String? | No | Optionally share SHA-256 hash of the email instead of raw email |
phoneSha256 | String? | No | Optionally share SHA-256 hash of the phone instead of raw phone. |
import { ChottuLink } from 'react-native-chottulink-sdk';
// Minimal — only the user ID is required
await ChottuLink.identify({ id: 'user_123' });
// Full — with all optional fields
await ChottuLink.identify({
id: 'user_123',
name: 'Jane Doe',
email: 'jane@example.com',
phone: '+14155550100',
emailSha256: 'b4c9a...', // Optionally share SHA-256 hash of the email instead of raw email
phoneSha256: 'e3d8f...', // Optionally share SHA-256 hash of the phone instead of raw phone
});
Return type: Promise<boolean>
RnCLCustomerMeta parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | ✅ Yes | Your system's unique identifier for this user. |
name | string | No | User's display name. |
email | string | No | User's email address. |
phone | string | No | User's phone number. |
emailSha256 | string | No | Optionally share SHA-256 hash of the email instead of raw email |
phoneSha256 | string | No | Optionally share SHA-256 hash of the phone instead of raw phone. |
import { ChottuLinkIonicSDK } from 'capacitor-chottulink-sdk';
// Minimal — only the user ID is required
await ChottuLinkIonicSDK.identify({ customer: { id: 'user_123' } });
// Full — with all optional fields
await ChottuLinkIonicSDK.identify({
customer: {
id: 'user_123',
name: 'Jane Doe',
email: 'jane@example.com',
phone: '+14155550100',
emailSha256: 'b4c9a...', // Optionally share SHA-256 hash of the email instead of raw email
phoneSha256: 'e3d8f...', // Optionally share SHA-256 hash of the phone instead of raw phone
},
});
Return type: Promise<void>
CLCustomerMeta parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | ✅ Yes | Your system's unique identifier for this user. |
name | string | No | User's display name. |
email | string | No | User's email address. |
phone | string | No | User's phone number. |
emailSha256 | string | No | Optionally share SHA-256 hash of the email instead of raw email |
phoneSha256 | string | No | Optionally share SHA-256 hash of the phone instead of raw phone. |
using UnityEngine;
// Minimal — only the user ID is required
ChottuLink.Identify(
new CustomerMeta { id = "user_123" },
onSuccess: _ => Debug.Log("Identified successfully"),
onError: error => Debug.LogWarning("Identify failed: " + error)
);
// Full — with all optional fields
ChottuLink.Identify(
new CustomerMeta
{
id = "user_123",
name = "Jane Doe",
email = "jane@example.com",
phone = "+14155550100",
emailSha256 = "b4c9a...", // Optionally share SHA-256 hash of the email instead of raw email
phoneSha256 = "e3d8f..." // Optionally share SHA-256 hash of the phone instead of raw phone
},
onSuccess: _ => Debug.Log("Identified successfully"),
onError: error => Debug.LogWarning("Identify failed: " + error)
);
Signature: Identify(CustomerMeta customerMeta, Action<string> onSuccess, Action<string> onError)
CustomerMeta fields
| Field | Type | Required | Description |
|---|---|---|---|
id | string | ✅ Yes | Your system's unique identifier for this user. |
name | string | No | User's display name. |
email | string | No | User's email address. |
phone | string | No | User's phone number. |
emailSha256 | string | No | Optionally share SHA-256 hash of the email instead of raw email |
phoneSha256 | string | No | Optionally share SHA-256 hash of the phone instead of raw phone. |
trackLead()
Tracks a lead or registration event. Use this when a user signs up, starts a trial, or completes any top-of-funnel action.
- iOS
- Android
- Flutter
- React Native
- Capacitor
- Unity
import ChottuLinkSDK
// Minimal — records a default "signup" event
ChottuLink.trackLead(nil)
// With a custom event name
ChottuLink.trackLead(CLLeadMeta(eventName: "trial_started"))
// With a custom event name and metadata
ChottuLink.trackLead(CLLeadMeta(
eventName: "trial_started",
metadata: [
"plan": "pro",
"referral_code": "FRIEND25"
]
))
CLLeadMeta parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
eventName | String? | No | Name of the event. Defaults to "signup" when nil. |
metadata | [String: Any]? | No | Arbitrary key-value data attached to the event. |
import com.chottulink.lib.ChottuLink;
import java.util.HashMap;
import java.util.Map;
// Minimal — records a default "signup" event
ChottuLink.trackLead(new ChottuLink.LeadMeta.Builder().build());
// With a custom event name
ChottuLink.trackLead(
new ChottuLink.LeadMeta.Builder()
.setEventName("trial_started")
.build()
);
// With a custom event name and metadata
Map<String, Object> metadata = new HashMap<>();
metadata.put("plan", "pro");
metadata.put("referral_code", "FRIEND25");
ChottuLink.trackLead(
new ChottuLink.LeadMeta.Builder()
.setEventName("trial_started")
.setMetadata(metadata)
.build()
);
LeadMeta.Builder methods
| Method | Parameter type | Required | Description |
|---|---|---|---|
setEventName(String) | String | No | Name of the event. Defaults to "signup" when null. |
setMetadata(Map<String, Object>) | Map<String, Object> | No | Arbitrary key-value data attached to the event. |
import 'package:chottu_link/chottu_link.dart';
import 'package:chottu_link/model/lead_meta.dart';
// Minimal — records a default "signup" event
await ChottuLink.trackLead(const LeadMeta());
// With a custom event name
await ChottuLink.trackLead(const LeadMeta(eventName: 'trial_started'));
// With a custom event name and metadata
await ChottuLink.trackLead(LeadMeta(
eventName: 'trial_started',
metadata: {
'plan': 'pro',
'referral_code': 'FRIEND25',
},
));
Return type: Future<void>
LeadMeta parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
eventName | String? | No | Name of the event. Defaults to "signup" when null. |
metadata | Map<String, dynamic>? | No | Arbitrary key-value data attached to the event. |
import { ChottuLink } from 'react-native-chottulink-sdk';
// Minimal — records a default "signup" event
await ChottuLink.trackLead();
// With a custom event name
await ChottuLink.trackLead({ eventName: 'trial_started' });
// With a custom event name and metadata
await ChottuLink.trackLead({
eventName: 'trial_started',
metadata: {
plan: 'pro',
referral_code: 'FRIEND25',
},
});
Return type: Promise<boolean>
RnCLLeadMeta parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
eventName | string | No | Name of the event. Defaults to "signup" when omitted or null. |
metadata | Record<string, unknown> | No | Arbitrary key-value data attached to the event. |
import { ChottuLinkIonicSDK } from 'capacitor-chottulink-sdk';
// Minimal — records a default "signup" event
await ChottuLinkIonicSDK.trackLead();
// With a custom event name
await ChottuLinkIonicSDK.trackLead({ meta: { eventName: 'trial_started' } });
// With a custom event name and metadata
await ChottuLinkIonicSDK.trackLead({
meta: {
eventName: 'trial_started',
metadata: {
plan: 'pro',
referral_code: 'FRIEND25',
},
},
});
Return type: Promise<void>
The Capacitor SDK wraps the lead data in a meta key: trackLead({ meta: { eventName: '...' } }). Calling trackLead() with no arguments records the default "signup" event.
CLLeadMeta parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
eventName | string | No | Name of the event. Defaults to "signup" when omitted. |
metadata | Record<string, any> | No | Arbitrary key-value data attached to the event. |
using System.Collections.Generic;
using UnityEngine;
// Minimal — records a default "signup" event
ChottuLink.TrackLead(
new LeadMeta(),
onSuccess: _ => Debug.Log("Lead tracked"),
onError: error => Debug.LogWarning("TrackLead failed: " + error)
);
// With a custom event name
ChottuLink.TrackLead(
new LeadMeta { eventName = "trial_started" },
onSuccess: _ => Debug.Log("Lead tracked"),
onError: error => Debug.LogWarning("TrackLead failed: " + error)
);
// With a custom event name and metadata
ChottuLink.TrackLead(
new LeadMeta
{
eventName = "trial_started",
metadata = new Dictionary<string, object>
{
{ "plan", "pro" },
{ "referral_code", "FRIEND25" }
}
},
onSuccess: _ => Debug.Log("Lead tracked"),
onError: error => Debug.LogWarning("TrackLead failed: " + error)
);
Signature: TrackLead(LeadMeta leadMeta, Action<string> onSuccess, Action<string> onError)
LeadMeta fields
| Field | Type | Required | Description |
|---|---|---|---|
eventName | string | No | Name of the event. Defaults to "signup" when null. |
metadata | Dictionary<string, object> | No | Arbitrary key-value data attached to the event. |
trackConversion()
Tracks a revenue or conversion event. Use this for purchases, subscription upgrades, in-app purchases, or any bottom-of-funnel action that has a monetary value. Events are deduplicated on the server using transactionId.
Calls with revenue <= 0 are silently ignored. Always pass a positive value.
- iOS
- Android
- Flutter
- React Native
- Capacitor
- Unity
import ChottuLinkSDK
// Minimal — revenue is the only required field
ChottuLink.trackConversion(CLConversionMeta(revenue: 29.99))
// Full — with all optional fields
ChottuLink.trackConversion(CLConversionMeta(
revenue: 29.99,
currency: "USD", // ISO 4217 currency code
eventName: "subscription", // defaults to "purchase" when nil
productId: "pro_monthly",
transactionId: "txn_abc123", // strongly recommended for server-side deduplication
metadata: [
"trial_converted": true,
"promo_code": "SUMMER25"
]
))
CLConversionMeta parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
revenue | Double | ✅ Yes | Revenue amount. Must be greater than 0. |
currency | String? | No | ISO 4217 currency code (e.g. "USD", "EUR"). Defaults to your organisation's base currency when nil. |
eventName | String? | No | Name of the event. Defaults to "purchase" when nil. |
productId | String? | No | The product or SKU identifier associated with this conversion. |
transactionId | String? | No | A unique transaction ID used for server-side deduplication. Strongly recommended for purchase events. |
metadata | [String: Any]? | No | Arbitrary key-value data attached to the event. |
import com.chottulink.lib.ChottuLink;
import java.util.HashMap;
import java.util.Map;
// Minimal — revenue is the only required field
ChottuLink.trackConversion(
new ChottuLink.ConversionMeta.Builder()
.setRevenue(29.99)
.build()
);
// Full — with all optional fields
Map<String, Object> metadata = new HashMap<>();
metadata.put("trial_converted", true);
metadata.put("promo_code", "SUMMER25");
ChottuLink.trackConversion(
new ChottuLink.ConversionMeta.Builder()
.setRevenue(29.99)
.setCurrency("USD") // ISO 4217 currency code
.setEventName("subscription") // defaults to "purchase" when null
.setProductId("pro_monthly")
.setTransactionId("txn_abc123") // strongly recommended for server-side deduplication
.setMetadata(metadata)
.build()
);
ConversionMeta.Builder methods
| Method | Parameter type | Required | Description |
|---|---|---|---|
setRevenue(double) | double | ✅ Yes | Revenue amount. Calls where setRevenue() was not called are silently ignored. |
setCurrency(String) | String | No | ISO 4217 currency code (e.g. "USD", "EUR"). Defaults to your organisation's base currency when null. |
setEventName(String) | String | No | Name of the event. Defaults to "purchase" when null. |
setProductId(String) | String | No | The product or SKU identifier associated with this conversion. |
setTransactionId(String) | String | No | A unique transaction ID used for server-side deduplication. Strongly recommended for purchase events. |
setMetadata(Map<String, Object>) | Map<String, Object> | No | Arbitrary key-value data attached to the event. |
trackConversion() calls where setRevenue() was not called on the builder are silently ignored by the SDK. Always call setRevenue() before calling build().
import 'package:chottu_link/chottu_link.dart';
import 'package:chottu_link/model/conversion_meta.dart';
// Minimal — revenue is the only required field
await ChottuLink.trackConversion(const ConversionMeta(revenue: 29.99));
// Full — with all optional fields
await ChottuLink.trackConversion(ConversionMeta(
revenue: 29.99,
currency: 'USD', // ISO 4217 currency code
eventName: 'subscription', // defaults to "purchase" when null
productId: 'pro_monthly',
transactionId: 'txn_abc123', // strongly recommended for server-side deduplication
metadata: {
'trial_converted': true,
'promo_code': 'SUMMER25',
},
));
Return type: Future<void>
ConversionMeta parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
revenue | double | ✅ Yes | Revenue amount. Must be greater than 0. |
currency | String? | No | ISO 4217 currency code (e.g. "USD", "EUR"). Defaults to your organisation's base currency when null. |
eventName | String? | No | Name of the event. Defaults to "purchase" when null. |
productId | String? | No | The product or SKU identifier associated with this conversion. |
transactionId | String? | No | A unique transaction ID used for server-side deduplication. Strongly recommended for purchase events. |
metadata | Map<String, dynamic>? | No | Arbitrary key-value data attached to the event. |
import { ChottuLink } from 'react-native-chottulink-sdk';
// Minimal — revenue is the only required field
await ChottuLink.trackConversion({ revenue: 29.99 });
// Full — with all optional fields
await ChottuLink.trackConversion({
revenue: 29.99,
currency: 'USD', // ISO 4217 currency code
eventName: 'subscription', // defaults to "purchase" when omitted
productId: 'pro_monthly',
transactionId: 'txn_abc123', // strongly recommended for server-side deduplication
metadata: {
trial_converted: true,
promo_code: 'SUMMER25',
},
});
Return type: Promise<boolean>
RnCLConversionMeta parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
revenue | number | ✅ Yes | Revenue amount. Must be greater than 0. |
currency | string | No | ISO 4217 currency code (e.g. "USD", "EUR"). Defaults to your organisation's base currency when omitted. |
eventName | string | No | Name of the event. Defaults to "purchase" when omitted. |
productId | string | No | The product or SKU identifier associated with this conversion. |
transactionId | string | No | A unique transaction ID used for server-side deduplication. Strongly recommended for purchase events. |
metadata | Record<string, unknown> | No | Arbitrary key-value data attached to the event. |
import { ChottuLinkIonicSDK } from 'capacitor-chottulink-sdk';
// Minimal — revenue is the only required field
await ChottuLinkIonicSDK.trackConversion({ meta: { revenue: 29.99 } });
// Full — with all optional fields
await ChottuLinkIonicSDK.trackConversion({
meta: {
revenue: 29.99,
currency: 'USD', // ISO 4217 currency code
eventName: 'subscription', // defaults to "purchase" when omitted
productId: 'pro_monthly',
transactionId: 'txn_abc123', // strongly recommended for server-side deduplication
metadata: {
trial_converted: true,
promo_code: 'SUMMER25',
},
},
});
Return type: Promise<void>
The Capacitor SDK wraps the conversion data in a meta key: trackConversion({ meta: { revenue: 29.99 } }).
CLConversionMeta parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
revenue | number | ✅ Yes | Revenue amount. Must be greater than 0. |
currency | string | No | ISO 4217 currency code (e.g. "USD", "EUR"). Defaults to your organisation's base currency when omitted. |
eventName | string | No | Name of the event. Defaults to "purchase" when omitted. |
productId | string | No | The product or SKU identifier associated with this conversion. |
transactionId | string | No | A unique transaction ID used for server-side deduplication. Strongly recommended for purchase events. |
metadata | Record<string, any> | No | Arbitrary key-value data attached to the event. |
using System.Collections.Generic;
using UnityEngine;
// Minimal — revenue is the only required field
ChottuLink.TrackConversion(
new ConversionMeta { revenue = 29.99 },
onSuccess: _ => Debug.Log("Conversion tracked"),
onError: error => Debug.LogWarning("TrackConversion failed: " + error)
);
// Full — with all optional fields
ChottuLink.TrackConversion(
new ConversionMeta
{
revenue = 29.99,
currency = "USD", // ISO 4217 currency code
eventName = "subscription", // defaults to "purchase" when null
productId = "pro_monthly",
transactionId = "txn_abc123", // strongly recommended for server-side deduplication
metadata = new Dictionary<string, object>
{
{ "trial_converted", true },
{ "promo_code", "SUMMER25" }
}
},
onSuccess: _ => Debug.Log("Conversion tracked"),
onError: error => Debug.LogWarning("TrackConversion failed: " + error)
);
Signature: TrackConversion(ConversionMeta conversionMeta, Action<string> onSuccess, Action<string> onError)
ConversionMeta fields
| Field | Type | Required | Description |
|---|---|---|---|
revenue | double | ✅ Yes | Revenue amount. Must be greater than 0. |
currency | string | No | ISO 4217 currency code (e.g. "USD", "EUR"). Defaults to your organisation's base currency when null. |
eventName | string | No | Name of the event. Defaults to "purchase" when null. |
productId | string | No | The product or SKU identifier associated with this conversion. |
transactionId | string | No | A unique transaction ID used for server-side deduplication. Strongly recommended for purchase events. |
metadata | Dictionary<string, object> | No | Arbitrary key-value data attached to the event. |
trackEvent()
Tracks any custom business event. Use this for anything that doesn't fit trackLead or trackConversion — tutorial steps, feature usage, content views, social shares, and so on.
- iOS
- Android
- Flutter
- React Native
- Capacitor
- Unity
import ChottuLinkSDK
// Simple — no extra data
ChottuLink.trackEvent(name: "tutorial_completed", data: nil)
// With metadata
ChottuLink.trackEvent(
name: "feature_used",
data: [
"feature": "qr_code_scanner",
"duration_seconds": 45,
"success": true
]
)
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
name | String | ✅ Yes | The event name (e.g. "tutorial_completed", "item_viewed"). |
data | [String: Any]? | No | Arbitrary key-value metadata. Values should be String, Int, Double, or Bool. |
import com.chottulink.lib.ChottuLink;
import java.util.HashMap;
import java.util.Map;
// Simple — no extra data
ChottuLink.trackEvent("tutorial_completed", null);
// With metadata
Map<String, Object> eventData = new HashMap<>();
eventData.put("feature", "qr_code_scanner");
eventData.put("duration_seconds", 45);
eventData.put("success", true);
ChottuLink.trackEvent("feature_used", eventData);
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
eventName | String | ✅ Yes | The event name (e.g. "tutorial_completed", "item_viewed"). |
eventData | Map<String, Object> | No | Arbitrary key-value metadata. Values should be String, Integer, Double, or Boolean. Pass null when not needed. |
import 'package:chottu_link/chottu_link.dart';
// Simple — no extra data
await ChottuLink.trackEvent('tutorial_completed');
// With metadata
await ChottuLink.trackEvent(
'feature_used',
eventData: {
'feature': 'qr_code_scanner',
'duration_seconds': 45,
'success': true,
},
);
Return type: Future<void>
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
eventName | String | ✅ Yes | The event name (e.g. "tutorial_completed", "item_viewed"). |
eventData | Map<String, dynamic>? | No | Arbitrary key-value metadata. Values should be String, int, double, or bool. |
import { ChottuLink } from 'react-native-chottulink-sdk';
// Simple — no extra data
await ChottuLink.trackEvent('tutorial_completed');
// With metadata
await ChottuLink.trackEvent('feature_used', {
feature: 'qr_code_scanner',
duration_seconds: 45,
success: true,
});
Return type: Promise<boolean>
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | ✅ Yes | The event name (e.g. "tutorial_completed", "item_viewed"). |
data | Record<string, unknown> | No | Arbitrary key-value metadata. Values should be string, number, or boolean. |
import { ChottuLinkIonicSDK } from 'capacitor-chottulink-sdk';
// Simple — no extra data
await ChottuLinkIonicSDK.trackEvent({ name: 'tutorial_completed' });
// With metadata
await ChottuLinkIonicSDK.trackEvent({
name: 'feature_used',
data: {
feature: 'qr_code_scanner',
duration_seconds: 45,
success: true,
},
});
Return type: Promise<void>
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | ✅ Yes | The event name (e.g. "tutorial_completed", "item_viewed"). |
data | Record<string, any> | No | Arbitrary key-value metadata. Values should be string, number, or boolean. |
using System.Collections.Generic;
using UnityEngine;
// Simple — no extra data
ChottuLink.TrackEvent(
"tutorial_completed",
null,
onSuccess: _ => Debug.Log("Event tracked"),
onError: error => Debug.LogWarning("TrackEvent failed: " + error)
);
// With metadata
ChottuLink.TrackEvent(
"feature_used",
new Dictionary<string, object>
{
{ "feature", "qr_code_scanner" },
{ "duration_seconds", 45 },
{ "success", true }
},
onSuccess: _ => Debug.Log("Event tracked"),
onError: error => Debug.LogWarning("TrackEvent failed: " + error)
);
Signature: TrackEvent(string eventName, Dictionary<string, object> metadata, Action<string> onSuccess, Action<string> onError)
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
eventName | string | ✅ Yes | The event name (e.g. "tutorial_completed", "item_viewed"). |
metadata | Dictionary<string, object> | No | Arbitrary key-value metadata. Values should be string, int, double, or bool. Pass null when not needed. |
logout()
Call this when the user logs out of your app. The anonymous device ID is preserved — only the customer linkage is removed.
- iOS
- Android
- Flutter
- React Native
- Capacitor
- Unity
import ChottuLinkSDK
ChottuLink.logout()
After logout():
- All pending events are uploaded immediately
- The customer ID is cleared from local storage
- Subsequent
identify()calls will establish a new customer linkage - The anonymous device ID remains unchanged
import com.chottulink.lib.ChottuLink;
ChottuLink.logout();
After logout():
- All pending events are uploaded immediately (best-effort flush)
- The customer ID is cleared from local storage (SharedPreferences)
- Subsequent
identify()calls will establish a new customer linkage - The anonymous device ID remains unchanged
import 'package:chottu_link/chottu_link.dart';
await ChottuLink.logout();
Return type: Future<void>
After logout():
- All pending events are uploaded immediately (best-effort flush)
- The customer ID is cleared from local storage
- Subsequent
identify()calls will establish a new customer linkage - The anonymous device ID remains unchanged
import { ChottuLink } from 'react-native-chottulink-sdk';
await ChottuLink.logout();
Return type: Promise<boolean>
After logout():
- All pending events are uploaded immediately (best-effort flush)
- The customer ID is cleared from local storage
- Subsequent
identify()calls will establish a new customer linkage - The anonymous device ID remains unchanged
import { ChottuLinkIonicSDK } from 'capacitor-chottulink-sdk';
await ChottuLinkIonicSDK.logout();
Return type: Promise<void>
After logout():
- All pending events are uploaded immediately (best-effort flush)
- The customer ID is cleared from local storage
- Subsequent
identify()calls will establish a new customer linkage - The anonymous device ID remains unchanged
using UnityEngine;
ChottuLink.Logout(
onSuccess: _ => Debug.Log("Logged out"),
onError: error => Debug.LogWarning("Logout failed: " + error)
);
Signature: Logout(Action<string> onSuccess, Action<string> onError)
After Logout():
- All pending events are uploaded immediately (best-effort flush)
- The customer ID is cleared from local storage
- Subsequent
Identify()calls will establish a new customer linkage - The anonymous device ID remains unchanged
optOut()
Opts the user in or out of all SDK tracking. When opted out, all tracking methods (identify, trackLead, trackConversion, trackEvent) become no-ops and getAttributionData() returns nil. The preference is persisted across app launches.
When optOut(true) is active, no events are queued or sent and attribution data is not surfaced. Events are not buffered for later delivery — they are dropped. Call optOut(false) to re-enable tracking.
- iOS
- Android
- Flutter
- React Native
- Capacitor
- Unity
import ChottuLinkSDK
// Opt the user OUT of all tracking
ChottuLink.optOut(true)
// Opt the user back IN
ChottuLink.optOut(false)
// Read the current opt-out state
if ChottuLink.isOptedOut {
print("User has opted out of tracking")
}
Parameters
| Parameter | Type | Description |
|---|---|---|
enabled | Bool | true to opt out (disable all tracking). false to opt back in (re-enable tracking). |
import android.util.Log;
import com.chottulink.lib.ChottuLink;
// Opt the user OUT of all tracking
ChottuLink.optOut(true);
// Opt the user back IN
ChottuLink.optOut(false);
// Read the current opt-out state
if (ChottuLink.isOptedOut()) {
Log.d("App", "User has opted out of tracking");
}
Parameters
| Parameter | Type | Description |
|---|---|---|
optOut | boolean | true to opt out (disable all tracking). false to opt back in (re-enable tracking). |
import 'package:chottu_link/chottu_link.dart';
// Opt the user OUT of all tracking
await ChottuLink.optOut(true);
// Opt the user back IN
await ChottuLink.optOut(false);
// Read the current opt-out state
final isOptedOut = await ChottuLink.isOptedOut();
if (isOptedOut) {
print('User has opted out of tracking');
}
Return types: optOut → Future<void> · isOptedOut → Future<bool>
optOut parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
optOut | bool | ✅ Yes | true to opt out (disable all tracking). false to opt back in (re-enable tracking). |
The React Native SDK splits the iOS optOut(Bool) method into two separate functions: setOptOut(enabled) to write the preference and getIsOptedOut() to read it.
import { ChottuLink } from 'react-native-chottulink-sdk';
// Opt the user OUT of all tracking
await ChottuLink.setOptOut(true);
// Opt the user back IN
await ChottuLink.setOptOut(false);
// Read the current opt-out state
const isOptedOut = await ChottuLink.getIsOptedOut();
if (isOptedOut) {
console.log('User has opted out of tracking');
}
Return types: setOptOut → Promise<boolean> · getIsOptedOut → Promise<boolean>
setOptOut parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
enabled | boolean | ✅ Yes | true to opt out (disable all tracking). false to opt back in (re-enable tracking). |
Like React Native, the Capacitor SDK splits the iOS optOut(Bool) method into two separate functions: optOut({ enabled }) to write the preference and isOptedOut() to read it.
import { ChottuLinkIonicSDK } from 'capacitor-chottulink-sdk';
// Opt the user OUT of all tracking
await ChottuLinkIonicSDK.optOut({ enabled: true });
// Opt the user back IN
await ChottuLinkIonicSDK.optOut({ enabled: false });
// Read the current opt-out state
const { isOptedOut } = await ChottuLinkIonicSDK.isOptedOut();
if (isOptedOut) {
console.log('User has opted out of tracking');
}
Return types: optOut → Promise<void> · isOptedOut → Promise<{ isOptedOut: boolean }>
optOut parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
enabled | boolean | ✅ Yes | true to opt out (disable all tracking). false to opt back in (re-enable tracking). |
The Unity SDK splits optOut into two separate methods: OptOut(bool, ...) to write the preference and IsOptedOut(...) to read it. Both deliver results via callbacks.
using UnityEngine;
// Opt the user OUT of all tracking
ChottuLink.OptOut(
true,
onSuccess: _ => Debug.Log("Opted out"),
onError: error => Debug.LogWarning("OptOut failed: " + error)
);
// Opt the user back IN
ChottuLink.OptOut(
false,
onSuccess: _ => Debug.Log("Opted back in"),
onError: error => Debug.LogWarning("OptOut failed: " + error)
);
// Read the current opt-out state
ChottuLink.IsOptedOut(
onSuccess: isOptedOut =>
{
if (isOptedOut) Debug.Log("User has opted out of tracking");
},
onError: error => Debug.LogWarning("IsOptedOut failed: " + error)
);
Signatures:
OptOut(bool enabled, Action<string> onSuccess, Action<string> onError)IsOptedOut(Action<bool> onSuccess, Action<string> onError)
OptOut parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
enabled | bool | ✅ Yes | true to opt out (disable all tracking). false to opt back in (re-enable tracking). |