AppsFlyer and Adjust postbacks
Report installs to Rovenue server to server from AppsFlyer's Push API or an Adjust callback, as a backup for the in-app setAttribution hand-off.
The in-app setAttribution call can be lost
(app killed, offline, callback never fired). A server-to-server postback from the
MMP is the backup: AppsFlyer or Adjust tells Rovenue about the install directly.
Both feed the same write-once attribution record, so using both is safe.
To send Rovenue's revenue back out to Advenue instead, see the Advenue integration.
URLs
Owners copy both URLs from Acquisition › Settings after saving:
| MMP | Route | Method |
|---|---|---|
| AppsFlyer | /webhooks/attribution/appsflyer/:token | POST (JSON) |
| Adjust | /webhooks/attribution/adjust/:token | GET or POST |
The token in the path is the credential. Rotating the URLs invalidates the old
ones immediately; an unknown token answers 404. Only install events are used;
other events are acknowledged and skipped.
AppsFlyer
Add a Push API endpoint (Integration › Push API, account owner) with the AppsFlyer push URL, and select the install event. The dashboard path and the Push API field names here are taken from third-party integration guides; AppsFlyer's own support article could not be fetched, so check them against AppsFlyer's current Push API documentation.
Adjust
In AppView, set the Adjust callback URL as the server callback for installs.
The generated URL already carries the placeholders Rovenue reads, all from
Adjust's placeholder list:
activity_kind, adid, tracker_name, network_name, campaign_name,
adgroup_name, creative_name, environment and is_organic. Adjust drops a
placeholder it has no value for.
Adjust also has network-specific id placeholders. Rovenue requests them all and reads only those of the callback's own network, so an ad's ids key the campaign tree while the names stay names:
| Network | Campaign id | Ad set id | Ad id |
|---|---|---|---|
| Google Ads | google_ads_campaign_id | google_ads_adgroup_id | google_ads_creative_id |
| TikTok | tiktok_campaign_id | tiktok_adgroup_id | tiktok_ad_id |
| Snapchat | none | none | snapchat_ad_id |
Adjust publishes no such id placeholders for Meta, so a Meta install keys by
campaign name. is_organic set to true or 1 records the install as organic.
Identity
Rovenue has to know which subscriber the install belongs to.
- AppsFlyer: set
customerUserIDto the Rovenue id at AppsFlyer init. Read it fromcurrentUser().rovenueId(see the snippets below for where it comes from on each platform). The Push API then carries it ascustomer_user_id. - Adjust: add a global callback parameter named
rovenue_idcarrying the Rovenue id. Do it right after Rovenue is configured and before Adjust starts tracking, so the parameter rides on the install callback:
// iOS (Adjust SDK v5).
let rovenueId = await Rovenue.shared.currentUser().rovenueId
Adjust.addGlobalCallbackParameter(rovenueId, forKey: "rovenue_id")// Android (Adjust SDK v5), inside a coroutine
val rovenueId = Rovenue.shared.currentUser().rovenueId
Adjust.addGlobalCallbackParameter("rovenue_id", rovenueId)// React Native
import { Adjust } from 'react-native-adjust';
import { Rovenue } from '@rovenue/react-native-sdk';
const { rovenueId } = await Rovenue.currentUser();
Adjust.addGlobalCallbackParameter('rovenue_id', rovenueId);// Flutter
final user = await Rovenue.instance.currentUser();
Adjust.addGlobalCallbackParameter('rovenue_id', user.rovenueId);- Fallback: if no Rovenue id is present, Rovenue matches the vendor device
id (
appsflyer_id/ Adjustadid) against the$appsflyerId/$adjustIdsubscriber attributes.- Adjust:
$adjustIdis filled for you when the data you pass tosetAttributioncarriesadid(see the hand-off snippets): it is mirrored onto the subscriber. - AppsFlyer: the conversion data has no
appsflyer_id, so set$appsflyerIdyourself from AppsFlyer's SDK, or rely oncustomer_user_idabove:
- Adjust:
// iOS
try await Rovenue.shared.setAttributes([
"$appsflyerId": AppsFlyerLib.shared().getAppsFlyerUID(),
])// Android, inside a coroutine
AppsFlyerLib.getInstance().getAppsFlyerUID(context)?.let { uid ->
Rovenue.shared.setAttributes(mapOf("\$appsflyerId" to uid))
}// React Native
import appsFlyer from 'react-native-appsflyer';
import { Rovenue } from '@rovenue/react-native-sdk';
appsFlyer.getAppsFlyerUID((error, uid) => {
if (!error && uid) void Rovenue.setAttributes({ $appsflyerId: uid });
});// Flutter (appsflyer_sdk)
final uid = await appsflyerSdk.getAppsFlyerUID();
if (uid != null) {
await Rovenue.instance.setAttributes({r'$appsflyerId': uid});
}A postback that names no known subscriber is acknowledged with 202 and
dropped; there is no pending queue.
Unfilled Adjust placeholders are ignored: Adjust drops a placeholder it has no value for, and Rovenue skips any field that arrives empty.