Adjust¶
Herald's Adjust module sends attribution events to Adjust. Adjust only gets the events you choose: an event reaches Adjust only if it has a token from your Adjust dashboard. Purchases carry revenue, and ad impressions go through Adjust's ad-revenue API.
| SDK | Package |
|---|---|
| Android | io.github.mkhytarmkhoian:herald-adjust |
| Flutter | herald_adjust, over adjust_sdk |
| iOS | herald-ios-adjust, module HeraldAdjust, over Adjust's iOS SDK |
| React Native | @herald-analytics/adjust, over react-native-adjust |
Setup¶
You build the AdjustConfig (ADJConfig on iOS): environment, data residency, log level, attribution callbacks.
Herald's start() passes it to initSdk, so don't call initSdk yourself.
val adjust = Adjust.getDefaultInstance()
val config = AdjustConfig(application, appToken, AdjustConfig.ENVIRONMENT_PRODUCTION).apply {
setUrlStrategy(listOf("eu.adjust.com"), true, true) // EU data residency: your setting
setLogLevel(LogLevel.SUPPRESS)
}
val tracker = AdjustAnalyticsTrackerService(
CompositeAdjustEventTrackerFactory(
featureFactories + // your revenue and ad-revenue trackers, among others
TokenAdjustEventTrackerFactory(
tokens = listOf(
AdjustToken<CheckoutCompleted>("abc123"),
AdjustToken<PlanSelected>("def456"),
),
adjust = adjust,
),
),
CompositeAdjustPropertySetterFactory(
GenericAdjustPropertySetterFactory(adjust),
),
)
val service = AdjustAnalyticsService(adjust, config) // start() calls initSdk(config)
val provider = Herald.Provider(
name = "adjust",
events = tracker,
properties = tracker,
identity = service,
lifecycle = service,
consent = service,
)
Adjust's iOS SDK is static functions too, so Herald's iOS classes take no Adjust object. The
service takes your ADJConfig.
// Adjust returns nil for a config it can't use, such as one without an app token.
guard let config = ADJConfig(appToken: "YOUR_APP_TOKEN", environment: ADJEnvironmentProduction)
else {
return nil
}
let tracker = AdjustAnalyticsTrackerService(
eventTrackerFactory: CompositeAdjustEventTrackerFactory(
featureFactories + [ // revenue and custom mappings first
TokenAdjustEventTrackerFactory(tokens: [
AdjustToken(CheckoutCompleted.self, "abc123")
])
]), // nothing at the end: only tokened events are sent
propertySetterFactory: GenericAdjustPropertySetterFactory()
)
// Starts Adjust itself, silent until consent. Don't call Adjust.initSdk yourself.
let service = AdjustAnalyticsService(config: config)
let provider = HeraldProvider(
name: "adjust",
events: tracker,
properties: tracker,
identity: service,
lifecycle: service,
consent: service
)
The Adjust plugin is static functions, so Herald's Flutter classes take no Adjust object.
final config = AdjustConfig('YOUR_APP_TOKEN', AdjustEnvironment.production);
final tracker = AdjustAnalyticsTrackerService(
eventTrackerFactory: CompositeAdjustEventTrackerFactory([
...featureFactories, // revenue and custom mappings first
TokenAdjustEventTrackerFactory([AdjustToken<CheckoutCompleted>('abc123')]),
]), // nothing at the end: only tokened events are sent
propertySetterFactory: CompositeAdjustPropertySetterFactory([
const GenericAdjustPropertySetterFactory(),
]),
);
// Initialises Adjust itself, silent until consent. Don't call Adjust.initSdk yourself.
final service = AdjustAnalyticsService(config);
final provider = HeraldProvider(
name: 'adjust',
events: tracker,
properties: tracker,
identity: service,
lifecycle: service,
consent: service,
);
The Adjust package is static functions too, so Herald's React Native classes take no Adjust
object. The service takes your AdjustConfig.
const config = new AdjustConfig('YOUR_APP_TOKEN', AdjustConfig.EnvironmentProduction);
const tracker = new AdjustAnalyticsTrackerService({
eventTrackerFactory: new CompositeAdjustEventTrackerFactory([
...featureFactories, // revenue and custom mappings first
new TokenAdjustEventTrackerFactory([new AdjustToken(CheckoutCompleted, 'abc123')]),
]), // nothing at the end: only tokened events are sent
propertySetterFactory: new CompositeAdjustPropertySetterFactory([
new GenericAdjustPropertySetterFactory(),
]),
});
// Initialises Adjust itself, silent until consent. Don't call Adjust.initSdk yourself.
const service = new AdjustAnalyticsService(config);
const provider = new HeraldProvider({
name: 'adjust',
events: tracker,
properties: tracker,
identity: service,
lifecycle: service,
consent: service,
});
What reaches Adjust¶
| Herald | Adjust |
|---|---|
| an event with a token | trackEvent(AdjustEvent(token)), with parameters as callback parameters (text) |
| an event without a token | nothing |
an AdjustRevenueEvent |
the same tokened event, plus setRevenue(revenue, currency) and setDeduplicationId |
an AdjustAdRevenueEvent |
trackAdRevenue(AdjustAdRevenue(source)), no token needed |
| a property | addGlobalCallbackParameter(name, value), sent with every later event |
identify / reset |
a user_id global callback parameter / removing it |
start |
disable(), then initSdk(config) |
setEnabled |
enable() / disable() |
Factories and revenue types¶
| Factory | Handles |
|---|---|
TokenAdjustEventTrackerFactory(tokens, adjust); (tokens) on Flutter and React Native; (tokens:) on iOS |
events of a type that has an AdjustToken in the list |
RequireMappedAdjustEventTrackerFactory |
nothing: throws for any event that reaches it |
GenericAdjustPropertySetterFactory |
every property |
There is no generic event factory: an Adjust event without a token doesn't exist.
Revenue types, which your Adjust factory maps your events to (see Revenue):
AdjustRevenueEvent:revenue,currency, and an optionaldeduplicationId. Send it withRevenueEventTracker(revenueEvent, token, adjust), orRevenueAdjustEventTracker(revenueEvent, token)on Flutter, iOS and React Native; the factory passes the token, so the event needs no entry inTokenAdjustEventTrackerFactory.AdjustAdRevenueEvent:source, such asapplovin_max_sdk;revenue;currency; and optional impression count, network, unit and placement. Send it withAdRevenueEventTracker, orAdRevenueAdjustEventTrackeron Flutter, iOS and React Native.
Consent¶
A fresh install stays silent. start() calls disable() before initSdk(), so a disabled
state is the SDK's starting state. The order matters: a disable() issued after initSdk loses
the race with the first session, which then reaches Adjust's servers.
Adjust persists its enabled flag, but start() sets it to disabled on every launch. So re-apply
the stored decision after start-up, as in Consent. Third-party sharing and
other granular consent is set on the Adjust SDK directly.
Identity¶
identify writes the user id as the user_id global callback parameter; pass identityParameter
to AdjustAnalyticsService to use another key. It must match a callback parameter configured in
your Adjust dashboard. Don't give any property that name: it would overwrite the identity, and
reset would then remove the property.
Watch out for¶
- Callback parameters are text. Typed values are flattened with
asString. - On Flutter and React Native, Herald can't see Adjust's own failures. The Adjust package doesn't wait for its native side, so an error there never reaches your error reporter.
- On iOS, an empty token or ad revenue source is reported. Adjust itself would drop the event with only a log line, so Herald refuses it and tells your error reporter.
-
Each
AdjustTokenpairs a token with an event type, not a name, so the compiler checks the list and a renamed event keeps its token. An event that extends the type uses its token too:SDK An AdjustTokenAndroid AdjustToken<SignUpCompleted>("abc123")Flutter AdjustToken<SignUpCompleted>('abc123')iOS AdjustToken(SignUpCompleted.self, "abc123")React Native new AdjustToken(SignUpCompleted, 'abc123')