Adjust GmbH
fb_anon_id
property
In the fb_anon_id
property, Adjust transmits the anon_id
property from the Facebook SDK, which is a unique ID for the device that Facebook generates and persists on the device.
This can be verified by looking at the source code of the Adjust SDK for iOS.
Here, the fb_anon_id
property is set to self.packageParams.fbAnonymousId
(source):
1[ADJPackageBuilder parameters:parameters setString:self.packageParams.fbAnonymousId forKey:@"fb_anon_id"];
self.packageParams
is an instance of the ADJPackageParams
class (source):
1@property (nonatomic, weak) ADJPackageParams *packageParams;
In the constructor of the ADJPackageParams
class, the fbAnonymousId
property is set to the return value of a function call to [ADJUtil fbAnonymousId]
(source):
1self.fbAnonymousId = [ADJUtil fbAnonymousId];
Finally, [ADJUtil fbAnonymousId]
calls the Facebook SDK’s retrievePersistedAnonymousID
function in the FBSDKBasicUtility
(source):
1// post FB SDK v6.0.0
2// return [FBSDKBasicUtility retrievePersistedAnonymousID];
3Class class = nil;
4SEL selGetId = NSSelectorFromString(@"retrievePersistedAnonymousID");
5class = NSClassFromString(@"FBSDKBasicUtility");
6if (class != nil) {
7 if ([class respondsToSelector:selGetId]) {
8#pragma clang diagnostic push
9#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
10 NSString *fbAnonymousId = (NSString *)[class performSelector:selGetId];
11 return fbAnonymousId;
12#pragma clang diagnostic pop
13 }
14}
The retrievePersistedAnonymousID
method returns Facebook’s anon_id
. For more details on that, see our documentation for properties sent to Facebook’s tracking endpoints.
We have only observed this property on iOS, and found no references to it in the source code of the Adjust SDK for Android.
installed_at
property
The installed_at
property holds the date and time of when the app was installed. This can be verified by looking at the source code of Adjust’s SDKs.
In the Adjust SDK for Android, the property installed_at
is set to the value of deviceInfo.appInstallTime
(source):
1PackageBuilder.addString(parameters, "installed_at", deviceInfo.appInstallTime);
The deviceInfo
object is an instance of the DeviceInfo
class (source):
1private DeviceInfo deviceInfo;
In the constructor of the DeviceInfo
class, appInstallTime
is set to the return value of the getAppInstallTime()
function (source):
1appInstallTime = getAppInstallTime(context);
The getAppInstallTime()
function returns a formatted string of the firstInstallTime
property of Android’s PackageInfo
class (source):
1private String getAppInstallTime(Context context) {
2 try {
3 PackageManager packageManager = context.getPackageManager();
4 PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
5
6 String appInstallTime = Util.dateFormatter.format(new Date(packageInfo.firstInstallTime));
7
8 return appInstallTime;
9 } catch (Exception ex) {
10 return null;
11 }
12}
And, according to the Android Developers documentation for PackageInfo
, firstInstallTime
is:
The time at which the app was first installed.
In the Adjust SDK for iOS, the installed_at
property is set to the value of self.packageParams.installedAt
(source):
1[ADJPackageBuilder parameters:parameters setString:self.packageParams.installedAt forKey:@"installed_at"];
self.packageParams
is an instance of the ADJPackageParams
class (source):
1@property (nonatomic, weak) ADJPackageParams *packageParams;
In the constructor of the ADJPackageParams
class, the installedAt
property is set to the return value of a function call to [ADJUtil installedAt]
(source):
1self.installedAt = [ADJUtil installedAt];
Finally, [ADJUtil installedAt]
returns a formatted string of the date and time when the app was installed by looking at the creation date of the app’s files (source):
1+ (NSString *)installedAt {
2 // […]
3 @try {
4 NSArray *paths = NSSearchPathForDirectoriesInDomains(folderToCheck, NSUserDomainMask, YES);
5 if (paths.count > 0) {
6 pathToCheck = [paths objectAtIndex:0];
7 } else {
8 pathToCheck = [[NSBundle mainBundle] bundlePath];
9 }
10
11 __autoreleasing NSError *error;
12 __autoreleasing NSError **errorPointer = &error;
13 Class class = NSClassFromString([NSString adjJoin:@"N", @"S", @"file", @"manager", nil]);
14 if (class != nil) {
15 NSString *keyDm = [NSString adjJoin:@"default", @"manager", nil];
16 SEL selDm = NSSelectorFromString(keyDm);
17 if ([class respondsToSelector:selDm]) {
18#pragma clang diagnostic push
19#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
20 id man = [class performSelector:selDm];
21#pragma clang diagnostic pop
22 NSString *keyChk = [NSString stringWithFormat:@"%@%@",
23 [NSString adjJoin:@"attributes", @"of", @"item", @"at", @"path", @":", nil],
24 [NSString adjJoin:@"error", @":", nil]];
25 SEL selChk = NSSelectorFromString(keyChk);
26 if ([man respondsToSelector:selChk]) {
27 NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[man methodSignatureForSelector:selChk]];
28 [inv setSelector:selChk];
29 [inv setTarget:man];
30 [inv setArgument:&pathToCheck atIndex:2];
31 [inv setArgument:&errorPointer atIndex:3];
32 [inv invoke];
33 NSMutableDictionary * __unsafe_unretained tmpResult;
34 [inv getReturnValue:&tmpResult];
35 NSMutableDictionary *result = tmpResult;
36 CFStringRef *indexRef = dlsym(RTLD_SELF, [[NSString adjJoin:@"N", @"S", @"file", @"creation", @"date", nil] UTF8String]);
37 NSString *ref = (__bridge_transfer id) *indexRef;
38 installTime = result[ref];
39 }
40 }
41 }
42 } @catch (NSException *exception) {
43 [logger error:@"Error while trying to check install date. Exception: %@", exception];
44 return nil;
45 }
46
47 return [ADJUtil formatDate:installTime];
48}
Unique tracking IDs
The android_uuid
, ios_uuid
, persistent_ios_uuid
, and web_uuid
properties are unique IDs for the device that Adjust generates on install and correlates with other device IDs.
According to Adjust’s documentation for iOS (archived):
When users reset their advertising ID, uninstall and reinstall your app, or enable LAT, Adjust will not be able to retrieve their IDFA and/or IDFV. To continuously track users’ in-app sessions, Adjust relies on a permanent, locally generated UUID persisted to the device keychain. […] […] How does Adjust manage UUIDs? Adjust generates a UUID upon install. This is mapped to other device information on our backend.
Further, Adjust’s documentation for iOS (archived) says:
Parameter Description Example persistent_ios_uuid Same as ios_uuid, but saved in Keychain so that re-installed apps will have same value, iOS only 3b35fcfb-6115-4cff-830f-e32a248c487d
And according to Adjust’s documentation for the web (archived):
To identify unique web users, the Adjust web SDK generates a unique web_uuid when it measures a session. The ID is created per subdomain and per browser. This means that if a user switches from Chrome to Safari, the SDK creates 2 web_uuid entries for the device. The identifier follows the Universally Unique Identifier (UUID) format.
- Example: web_uuid=4d1615ab-ee78-49aa-a10f-d57035322a42
Adjust uses IndexedDB to store the web_uuid in the browser, or falls back to localStorage if IndexedDB is not available.
And while the property is not documented for Android, we can verify that the same applies here by looking at the source code for Adjust SDK for Android:
Here, the android_uuid
property is set to activityStateCopy.uuid
(source):
1// Device identifiers.
2deviceInfo.reloadPlayIds(adjustConfig);
3PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid);
activityStateCopy
is an instance of the ActivityStateCopy
class that is passed an instance of the ActivityState
class (source):
1PackageBuilder(AdjustConfig adjustConfig,
2 DeviceInfo deviceInfo,
3 ActivityState activityState,
4 SessionParameters sessionParameters,
5 long createdAt) {
6 // […]
7 this.activityStateCopy = new ActivityStateCopy(activityState);
8 // […]
9}
An ActivityStateCopy
object is just a wrapper around the ActivityState
class, which exposes a few of its properties, including the uuid
property (source):
1ActivityStateCopy(ActivityState activityState) {
2 // […]
3 this.uuid = activityState.uuid;
4 // […]
5}
In an ActivityState
object, the uuid
property is set to the return value of a call to the Util.createUuid()
function (source):
1// create UUID for new devices
2uuid = Util.createUuid();
And the Util.createUuid()
function uses the randomUUID()
of the java.util.UUID
package (documentation) to generate a version 4 UUID (source):
1import java.util.UUID;
2
3// […]
4
5protected static String createUuid() {
6 return UUID.randomUUID().toString();
7}