{"metadata":{"image":[],"title":"","description":""},"api":{"url":"","auth":"required","params":[],"results":{"codes":[]},"settings":"","apiSetting":null},"next":{"description":"","pages":[]},"title":"Collecting User Data","type":"basic","slug":"collecting-user-data","excerpt":"","body":"The strength of Sailthru Mobile's targeting and segmentation relies on knowing the correct information about your users. The more information we know about a user, the better you can target them when you send messages.\n\nWhen a user installs an app, we collect a few attributes automatically. These attributes are helpful for targeting and segmenting your users.\n\n### Automatically Tracked Attributes\n\n- App Version\n- Language\n- Time Zone\n- Badge Number (iOS only)\n- Device ID\n- Device Make & Model\n- Operating System & Version\n- Sailthru Mobile SDK version\n- Location based on IP Address\n- Notifications Allowed\n- Platform\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"Attributes tracked automatically are refreshed at every app load.\"\n}\n[/block]\nBeyond the automatically tracked attributes, Sailthru Mobile also lets you store custom information about a user for further segmenting and targeting. This feature is called [User Attributes](#user-attributes).\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Setting a User ID\"\n}\n[/block]\nIf your app has a login, you can set a unique User ID with Sailthru Mobile.  This allows you to associate multiple devices to a single user when targeting via the API. You may also want to collect the [user's email ](http://docs.mobile.sailthru.com/docs/collecting-user-data#setting-a-user-email) as well. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// setting a User ID after login\\n[[SailthruMobile new] setUserId::::at:::\\\"user_id_1234\\\" withResponse:^(NSError *error) {\\n    NSLog(@\\\"Error setting user id – %@\\\", error.localizedDescription);\\n}];\\n\\n// clearing a User ID after logout\\n[[SailthruMobile new] setUserId:nil withResponse:^(NSError *error) {\\n    \\n}];\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (Objective-C)\"\n    },\n    {\n      \"code\": \"// setting a User ID after login\\nSailthruMobile().setUserId(\\\"user_id_1234\\\") { error in\\n    print(\\\"setUserID returned with possible error: \\\\(error)\\\")\\n}\\n\\n// clearing a User ID after logout\\nSailthruMobile().setUserId(nil) { error in\\n    print(\\\"setUserID returned with possible error: \\\\(error)\\\")\\n}\",\n      \"language\": \"swift\",\n      \"name\": \"iOS (Swift)\"\n    },\n    {\n      \"code\": \"// setting a User ID after login\\nnew SailthruMobile().setUserId(\\\"user_id_1234\\\", new SailthruMobile.SailthruMobileHandler<Void> (){\\n\\n    @Override\\n    public void onSuccess (Void value){\\n        //Do Something\\n    }\\n\\n    @Override\\n    public void onFailure (Error error){\\n        //Do Something\\n    }\\n});\\n\\n\\n// clearing a User ID after logout\\nnew SailthruMobile().setUserId(null, new SailthruMobile.SailthruMobileHandler<Void> (){\\n\\n    @Override\\n    public void onSuccess (Void value){\\n        //Do Something\\n    }\\n\\n    @Override\\n    public void onFailure (Error error){\\n        //Do Something\\n    }\\n});\",\n      \"language\": \"java\",\n      \"name\": \"Android (Java)\"\n    },\n    {\n      \"code\": \"// setting a User ID after login\\nSailthruMobile().setUserId(\\\"user_id_1234\\\", object : SailthruMobileHandler<Void?> {\\n  override fun onSuccess(value: Void?) {\\n    //Do Something\\n  }\\n\\n  override fun onFailure(error: Error?) {\\n    //Do Something\\n  }\\n})\\n\\n// clearing a User ID after logout\\nSailthruMobile().setUserId(null, object : SailthruMobileHandler<Void?> {\\n  override fun onSuccess(value: Void?) {\\n    //Do Something\\n  }\\n\\n  override fun onFailure(error: Error?) {\\n    //Do Something\\n  }\\n})\",\n      \"language\": \"kotlin\",\n      \"name\": \"Android (Kotlin)\"\n    },\n    {\n      \"code\": \"// setting a User ID after login\\nSailthruMobile.setUserId(\\\"user_id_1234\\\");\\n\\n// clearing a User ID after logout\\nSailthruMobile.setUserId(\\\"\\\");\",\n      \"language\": \"javascript\",\n      \"name\": \"React Native (JavaScript)\"\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"Setting a User ID is optional, but it is strongly recommended. It is a prerequisite to use:\\n\\n* Sending notifications to specific users, including using the [Notifications API](/docs/notifications) with `user_id` audiences\\n* [Users API](/docs/users)\\n* [Users Events API](/docs/users-events)\\n* [Audience creation via CSV](https://getstarted.sailthru.com/sailthru-mobile/audiences/creating-mobile-app-audiences/#By_CSV)\\n\\nWithout User ID you will be able to set attributes and events only at the device level.\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Setting a User Email\"\n}\n[/block]\nSetting a user email allows to link a device to an identifier user profile in Sailthru, matching the email you provide with an existing Email ID. This is a required step to leverage omnichannel personalization using interests and other data points from the Sailthru user profile.\n\nWe recommend to collect both User ID and email.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// setting a User Email after login\\n[[SailthruMobile new] setUserEmail:@\\\"[email protected]\\\" withResponse:^(NSError *error) {\\n    NSLog(@\\\"Error setting user email – %@\\\", error.localizedDescription);\\n}];\\n\\n// clearing a User Email after logout\\n[[SailthruMobile new] setUserEmail:nil withResponse:^(NSError *error) {\\n    NSLog(@\\\"Error setting user email – %@\\\", error.localizedDescription);\\n}];\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (Objective-C)\"\n    },\n    {\n      \"code\": \"// setting a User Email after login\\nSailthruMobile().setUserEmail(\\\"[email protected]\\\") { error in\\n    print(\\\"setUserEmail returned with possible error: \\\\(error)\\\")\\n}\\n\\n// clearing a User Email after logout\\nSailthruMobile().setUserEmail(nil) { error in\\n    print(\\\"setUserEmail returned with possible error: \\\\(error)\\\")\\n}\",\n      \"language\": \"swift\",\n      \"name\": \"iOS (Swift)\"\n    },\n    {\n      \"code\": \"// setting a User Email after login\\nnew SailthruMobile().setUserEmail(\\\"[email protected]\\\", new SailthruMobile.SailthruMobileHandler<Void> (){\\n\\n    @Override\\n    public void onSuccess (Void value){\\n        //Do Something\\n    }\\n\\n    @Override\\n    public void onFailure (Error error){\\n        //Do Something\\n    }\\n});\\n\\n\\n// clearing a User Email after logout\\nnew SailthruMobile().setUserEmail(null, new SailthruMobile.SailthruMobileHandler<Void> (){\\n\\n    @Override\\n    public void onSuccess (Void value){\\n        //Do Something\\n    }\\n\\n    @Override\\n    public void onFailure (Error error){\\n        //Do Something\\n    }\\n});\",\n      \"language\": \"java\",\n      \"name\": \"Android (Java)\"\n    },\n    {\n      \"code\": \"// setting a User Email after login\\nSailthruMobile().setUserEmail(\\\"[email protected]\\\", object : SailthruMobileHandler<Void?> {\\n  override fun onSuccess(value: Void?) {\\n    //Do Something\\n  }\\n\\n  override fun onFailure(error: Error?) {\\n    //Do Something\\n  }\\n})\\n\\n\\n// clearing a User Email after logout\\nSailthruMobile().setUserEmail(null, object : SailthruMobileHandler<Void?> {\\n  override fun onSuccess(value: Void?) {\\n    //Do Something\\n  }\\n\\n  override fun onFailure(error: Error?) {\\n    //Do Something\\n  }\\n})\",\n      \"language\": \"kotlin\",\n      \"name\": \"Android (Kotlin)\"\n    },\n    {\n      \"code\": \"// setting a User Email after login\\nSailthruMobile.setUserEmail(\\\"[email protected]\\\");\\n\\n// clearing a User Email after logout\\nSailthruMobile.setUserEmail(\\\"\\\");\",\n      \"language\": \"javascript\",\n      \"name\": \"React Native (JavaScript)\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"User Attributes\"\n}\n[/block]\nUser Attributes provide a powerful & flexible way for developers to store extra metadata for the purposes of grouping, segmenting and targeting users at a later stage.\n\nEach User/Device can have multiple attributes. User Attributes are unique to a device and app, and persist between app opens. They are set on the SDK side and saved back to the Sailthru Mobile platform with the appropriate SDK methods.\n\nEach User Attribute has a name, a type and a value.\n\nFor example;\n\n- `first_name` (String)\n- `lifetime_value` (Float)\n- `number_of_items_purchased` (Integer)\n- `is_premium_subscriber` (Boolean)\n\nThe following attribute datatypes are supported;\n \n * Integer (32 bit)\n * Float\n * Date\n * String\n * Boolean\n * Array (of Integer, Floats, Dates and Strings)\n\n### To set some User attributes from the SDK\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// Construct the object\\nSTMAttributes *attributes  = [[STMAttributes alloc] init];\\n\\n// Set one or more attributes\\n[attributes setString:@\\\"Handbags\\\" forKey:@\\\"last_visited_category\\\"];\\n[attributes setStrings:@[@\\\"world\\\", @\\\"sports\\\"] forKey:@\\\"subscriptions\\\"];\\n[attributes setFloat:104.87 forKey:@\\\"customer_ltv\\\"];\\n[attributes setInteger:3 forKey:@\\\"products_in_cart\\\"];\\n[attributes setFloats:@[@(36.99), @(42.3)] forKey:@\\\"cart_items_unit_price\\\"];\\n[attributes setIntegers:@[@(2), @(1)] forKey:@\\\"cart_item_quantities\\\"];\\n[attributes setBool:YES forKey:@\\\"user_did_use_facebook_login\\\"];\\n[attributes setDates:@[[NSDate date]] forKey:@\\\"checkout_started\\\"];\\n\\n// Optional: choose if you want to add new attributes to the existing (update), or if you want to overwrite the current attributes with the new payload (replace). By default, we update.\\n[attributes setAttributesMergeRule:STMAttributesMergeRuleUpdate];\\n\\nSailthruMobile *sailthruMobile = [SailthruMobile new];\\n\\n// Send to Sailthru Mobile\\n[sailthruMobile setAttributes:attributes withResponse:^(NSError * _Nullable error) {\\n  if (error) {\\n    NSLog(@\\\"Error - %@\\\", [error debugDescription]);\\n  }\\n}];\\n\\n// Remove an attribute\\n[sailthruMobile removeAttributeWithKey:@\\\"products_in_cart\\\" withResponse:nil];\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (Objective-C)\"\n    },\n    {\n      \"code\": \"// Construct the object\\nlet attributes = STMAttributes()\\n\\n// Set one or more attributes\\nattributes.setString(\\\"Handbags\\\", forKey: \\\"last_visited_category\\\")\\nattributes.setStrings([\\\"world\\\", \\\"sports\\\"], forKey: \\\"subscriptions\\\")\\nattributes.setFloat(104.87, forKey: \\\"customer_ltv\\\")\\nattributes.setInteger(3, forKey: \\\"products_in_cart\\\")\\nattributes.setFloats([36.99, 42.3], forKey: \\\"cart_items_unit_price\\\")\\nattributes.setIntegers([2, 1], forKey: \\\"cart_item_quantities\\\")\\nattributes.setBool(true, forKey: \\\"user_did_use_facebook_login\\\")\\nattributes.setDates(NSDate(), forKey: \\\"checkout_started\\\")\\n\\n// Optional: choose if you want to add new attributes to the existing (update), or if you want to overwrite the current attributes with the new payload (replace). By default, we update.\\nattributes.setAttributesMergeRule(.Update)\\n\\nlet sailthruMobile = SailthruMobile()\\n\\n// Send to Sailthru Mobile\\nsailthruMobile.setAttributes(attributes) { error in\\n  print(\\\"setAttributes returned with possible error: \\\\(error)\\\")\\n}\\n\\n// Remove an attribute\\nsailthruMobile.removeAttributeWithKey(\\\"products_in_cart\\\", nil)\",\n      \"language\": \"swift\",\n      \"name\": \"iOS (Swift)\"\n    },\n    {\n      \"code\": \"// Construct the object\\nAttributeMap attributes = new AttributeMap();\\n\\n// Set one or more attributes\\nattributes.putString(\\\"last_visited_category\\\", \\\"Handbags\\\");\\n\\nArrayList<String> subscriptions = new ArrayList<>(Arrays.asList(\\\"world\\\", \\\"sports\\\"));\\nattributes.putStringArray(\\\"subscriptions\\\", subscriptions);\\n\\nattributes.putFloat(\\\"customer_ltv\\\", 104.87f);\\n\\nArrayList<Float> cartItemsUnitPrice = new ArrayList<>(Arrays.asList(36.99f, 42.3f));\\nattributes.putFloatArray(\\\"cart_items_unit_price\\\", cartItemsUnitPrice);\\n\\nattributes.putInt(\\\"products_in_cart\\\", 3);\\n\\nArrayList<Integer> cartItemQuantities = new ArrayList<>(Arrays.asList(2, 1));\\nattributes.putIntArray(\\\"cart_item_quantities\\\", cartItemQuantities);\\n\\nattributes.putBoolean(\\\"user_did_user_facebook_login\\\", true);\\nattributes.putDate(\\\"checkout_started\\\", new Date());\\n\\n// Optional: choose if you want to add new attributes to the existing (update), or if you want to overwrite the current attributes with the new payload (replace). By default, we update.\\nattributes.setMergeRules(AttributeMap.RULE_UPDATE);\\n\\nSailthruMobile sailthruMobile = new SailthruMobile();\\n\\n// Send to Sailthru Mobile\\nsailthruMobile.setAttributes(attributes, new SailthruMobile.AttributesHandler() {\\n  @Override\\n  public void onSuccess() {\\n    // Handle success here\\n  }\\n\\n  @Override\\n  public void onFailure(Error error) {\\n    // Handle failure here\\n    Log.d(\\\"YOUR_LOG_TAG\\\", \\\"setAttributes returned with possible error: \\\" + error.getLocalizedMessage());\\n  }\\n});\\n\\n// Remove an attribute\\nsailthruMobile.removeAttribute(\\\"products_in_cart\\\");\",\n      \"language\": \"java\",\n      \"name\": \"Android (Java)\"\n    },\n    {\n      \"code\": \"// Construct the object\\nval attributes = AttributeMap()\\n\\n// Set one or more attributes\\nattributes.putString(\\\"last_visited_category\\\", \\\"Handbags\\\")\\n\\nval subscriptions: ArrayList<String> = ArrayList(Arrays.asList(\\\"world\\\", \\\"sports\\\"))\\nattributes.putStringArray(\\\"subscriptions\\\", subscriptions)\\n\\nattributes.putFloat(\\\"customer_ltv\\\", 104.87f)\\n\\nval cartItemsUnitPrice: ArrayList<Float> = ArrayList(Arrays.asList(36.99f, 42.3f))\\nattributes.putFloatArray(\\\"cart_items_unit_price\\\", cartItemsUnitPrice)\\n\\nattributes.putInt(\\\"products_in_cart\\\", 3)\\n\\nval cartItemQuantities: ArrayList<Int> = ArrayList(Arrays.asList(2, 1))\\nattributes.putIntArray(\\\"cart_item_quantities\\\", cartItemQuantities)\\n\\nattributes.putBoolean(\\\"user_did_user_facebook_login\\\", true)\\nattributes.putDate(\\\"checkout_started\\\", Date())\\n\\n// Optional: choose if you want to add new attributes to the existing (update), or if you want to overwrite the current attributes with the new payload (replace). By default, we update.\\nattributes.setMergeRules(AttributeMap.RULE_UPDATE)\\n\\nval sailthruMobile = SailthruMobile()\\n\\n// Send to Sailthru Mobile\\nsailthruMobile.setAttributes(attributes, object : SailthruMobile.AttributesHandler {\\n  override fun onSuccess() {\\n    // Handle success here\\n  }\\n\\n  override fun onFailure(error: Error?) {\\n    // Handle failure here\\n    Log.d(\\\"YOUR_LOG_TAG\\\", \\\"setAttributes returned with possible error: \\\" + error!!.localizedMessage)\\n  }\\n})\\n\\n// Remove an attribute\\nsailthruMobile.removeAttribute(\\\"products_in_cart\\\")\",\n      \"language\": \"kotlin\",\n      \"name\": \"Android (Kotlin)\"\n    },\n    {\n      \"code\": \"// Construct the object\\nvar attrMap = new SailthruMobile.AttributeMap();\\n\\n// Set one or more attributes\\nattrMap.setString(\\\"string_key\\\", \\\"This is the string value\\\");\\nattrMap.setStringArray(\\\"strings_key\\\", [\\\"This is first value\\\", \\\"This is the second value\\\"]);\\nattrMap.setDate(\\\"date_key\\\", new Date());\\nattrMap.setDateArray(\\\"dates_key\\\", [new Date(), new Date(), new Date()]);\\nattrMap.setFloat(\\\"float_key\\\", 3.141);\\nattrMap.setFloatArray(\\\"floats_key\\\", [1.1, 2.2, 3.3, 4.4]);\\nattrMap.setInteger(\\\"integer_key\\\", 3);\\nattrMap.setIntegerArray(\\\"integers_key\\\", [1, 2, 3, 4]);\\nattrMap.setBoolean(\\\"boolean_key\\\", true);\\n\\n// Optional: choose if you want to add new attributes to the existing (update), or if you want to overwrite the current attributes with the new payload (replace). By default, we update.\\nattrMap.setMergeRule(attrMap.MergeRules.Update);\\n\\n// Send to Sailthru Mobile\\nSailthruMobile.setAttributes(attrMap).catch(e => {\\n\\t// Handle error\\n});\",\n      \"language\": \"javascript\",\n      \"name\": \"React Native (JavaScript)\"\n    }\n  ]\n}\n[/block]\n### Custom Attribute Limits\nThere are limits in place on the maximum number of custom attributes allowed as well as the length (size) of strings and arrays.\n\n* A maximum of **50** custom attributes is allowed per device. If you exceed this amount any new attributes being set will be discarded.\n* String values that have more than **255** characters will be truncated.\n* Arrays with more than **50** elements will be truncated.\n\n### Key name restrictions\n\n * Only letters, numbers, underscore and dashes are valid characters.\n * Leading spaces will be removed.\n * Invalid characters other than spaces and dots will be removed.\n * Spaces and dots will be replaced for underscores.\n * Keys will be truncated to a maximum of 255 characters.\n * Invalid keys will simply be discarded and no error will be returned.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"Custom attributes are refreshed in real time.\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"title\": \"Sailthru Profile Vars\"\n}\n[/block]\nSailthru Profile Vars can be set and retrieved through the SDK. This makes maintaining state between your email/on-site campaigns and your mobile marketing easy. Note that the use of this feature requires that your app be linked to Sailthru Email/On-Site.\n\nVars should be set in a JSON object format:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// Setup profile vars object\\nNSDictionary *profileVars = @{\\n    @\\\"string_key\\\" : @\\\"string_value\\\",\\n    @\\\"object_key\\\" : @{},\\n    @\\\"boolean_key\\\" : @YES\\n};\\n    \\n// Set profile vars\\n[[SailthruMobile new] setProfileVars:profileVars withResponse:^(NSError * _Nullable error) {\\n    // Check if error is non-nil for result\\n}];\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (Objective-C)\"\n    },\n    {\n      \"code\": \"// Setup profile vars object\\nlet profileVars : [String : Any] = [ \\n  \\t\\\"string_key\\\" : \\\"string_value\\\",\\n\\t\\t\\\"object_key\\\" : [],\\n\\t\\t\\\"boolean_key\\\" : true \\n]\\n\\n// Set profile vars\\nSailthruMobile().setProfileVars(profileVars) { (error : Error?) in\\n\\t\\t// Check if error is non-nil for result\\n}\",\n      \"language\": \"swift\",\n      \"name\": \"iOS (Swift)\"\n    },\n    {\n      \"code\": \"// Setup profile vars object\\nJSONObject profileVars = new JSONObject();\\nprofileVars.put(\\\"string_key\\\", \\\"string_value\\\");\\nprofileVars.put(\\\"object_key\\\", new JSONObject());\\nprofileVars.put(\\\"boolean_key\\\", true);\\n\\n// Set profile vars\\nnew SailthruMobile().setProfileVars(profileVars, new SailthruMobile.SailthruMobileHandler<Void>() {\\n    @Override\\n    public void onSuccess(Void value) {\\n        // Handle success\\n    }\\n\\n    @Override\\n    public void onFailure(Error error) {\\n        // Handle error\\n    }\\n});\",\n      \"language\": \"java\",\n      \"name\": \"Android (Java)\"\n    },\n    {\n      \"code\": \"// Setup profile vars object\\nval profileVars = JSONObject()\\nprofileVars.put(\\\"string_key\\\", \\\"string_value\\\")\\nprofileVars.put(\\\"object_key\\\", JSONObject())\\nprofileVars.put(\\\"boolean_key\\\", true)\\n\\n// Set profile vars\\nSailthruMobile().setProfileVars(profileVars, object : SailthruMobileHandler<Void?> {\\n  override fun onSuccess(value: Void?) {\\n    // Handle success\\n  }\\n\\n  override fun onFailure(error: Error?) {\\n    // Handle error\\n  }\\n})\",\n      \"language\": \"kotlin\",\n      \"name\": \"Android (Kotlin)\"\n    },\n    {\n      \"code\": \"// Setup profile vars object\\nvar profileVars = {\\n\\t\\\"string_key\\\" : \\\"string_value\\\",\\n\\t\\\"object_key\\\" : {},\\n\\t\\\"boolean_key\\\": true\\n};\\n\\n// Set profile vars\\nSailthruMobile.setProfileVars(profileVars).then(result => {\\n  // Handle success\\n}).catch(e => {\\n  // Handle error\\n});\",\n      \"language\": \"javascript\",\n      \"name\": \"React Native (JavaScript)\"\n    }\n  ]\n}\n[/block]\nWhen retrieving vars they will be returned in the same JSON object format:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[[SailthruMobile new] getProfileVarsWithResponse:^(NSDictionary<NSString *,id> * _Nullable profileVars, NSError * _Nullable error) {\\n    // Handle profileVars object or error\\n}];\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (Objective-C)\"\n    },\n    {\n      \"code\": \"SailthruMobile().getProfileVars { (profileVars : [String : Any]?, error : Error?) in\\n\\t\\t// Handle profileVars object or error\\n}\",\n      \"language\": \"swift\",\n      \"name\": \"iOS (Swift)\"\n    },\n    {\n      \"code\": \"new SailthruMobile.getProfileVars(new SailthruMobile.SailthruMobileHandler<JSONObject>() {\\n    @Override\\n    public void onSuccess(JSONObject profileVars) {\\n\\t\\t\\t\\t// Handle profileVars object\\n    }\\n\\n    @Override\\n    public void onFailure(Error error) {\\n        // Handle error\\n    }\\n});\",\n      \"language\": \"java\",\n      \"name\": \"Android (Java)\"\n    },\n    {\n      \"code\": \"SailthruMobile().getProfileVars(object : SailthruMobileHandler<JSONObject?> {\\n  override fun onSuccess(profileVars: JSONObject?) {\\n    // Handle profileVars object\\n  }\\n\\n  override fun onFailure(error: Error?) {\\n    // Handle error\\n  }\\n})\",\n      \"language\": \"kotlin\",\n      \"name\": \"Android (Kotlin)\"\n    },\n    {\n      \"code\": \"SailthruMobile.getProfileVars().then(profileVars => {\\n\\t// Handle profileVars object\\n}).catch(e => {\\n\\t// Handle error\\n});\",\n      \"language\": \"javascript\",\n      \"name\": \"React Native (JavaScript)\"\n    }\n  ]\n}\n[/block]\n## Variable names\n\n* Are case sensitive. For example, if you create a variable named “Survey_Score” it will not be accessible using all lowercase letters.\n* May not start with a number or be only numbers. For example, don’t upload phone numbers using var name “#”.\n* May not contain special characters (such as %, -, or $).  These characters will be scrubbed from variable names upon import.\n* May not contain spaces. If the variable name is submitted with a space, it will be converted to an underscore.\n\n## Date and Time Formats\n\n* In order to maintain strict JSON compatibility, Sailthru vars do not support a native date or time type. Instead, if you use [specific naming and formatting](https://getstarted.sailthru.com/audience/managing-users/set-variables-on-users/#Date_andTime_Formats) conventions, Sailthru will treat these values as dates and times throughout our system, for example, when performing queries in Audience Builder.\n\nFor more information on Vars, see the [User Variables](https://getstarted.sailthru.com/audience/managing-users/set-variables-on-users/) docs\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Custom Events\"\n}\n[/block]\nSailthru Mobile's Custom Events provide a simple event tracking solution for measuring actions in your app. _Events_ can be logged to track actions that users take, such as screen views, or social network shares.  Unlike user attributes, events occur over time and graphs of the events can be seen within the analytics section of the Sailthru Mobile dashboard.  \n\nSailthru Mobile keeps record of the count and the last occurrence of an event for each user, so you can target and segment based on;\n \n- Whether a user has performed this event or not\n- When they last performed this event\n- How often they have performed this event\n\nThese events are also passed through to the Lifecycle Optimiser where they can be used to build powerful workflows for both mobile and email.\n\n### To log a Custom Event\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"SailthruMobile *sailthruMobile = [SailthruMobile new];\\n[sailthruMobile logEvent:@\\\"Checkout started\\\"];\\n[sailthruMobile logEvent:@\\\"Article shared\\\"];\\n\\n// with Vars\\nNSDictionary* eventVars = @{ @\\\"itemCount\\\" : @3 };\\n[sailthruMobile logEvent:@\\\"Checkout started\\\" withVars:eventVars];\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (Objective-C)\"\n    },\n    {\n      \"code\": \"let sailthruMobile = SailthruMobile()\\nsailthruMobile.logEvent(\\\"Checkout started\\\")\\nsailthruMobile.logEvent(\\\"Article shared\\\")\\n\\n// with Vars\\nlet eventVars = [ \\\"itemCount\\\" : 3 ]\\nsailthruMobile.logEvent(\\\"Checkout started\\\", withVars: eventVars)\",\n      \"language\": \"swift\",\n      \"name\": \"iOS (Swift)\"\n    },\n    {\n      \"code\": \"SailthruMobile sailthruMobile = new SailthruMobile();\\nsailthruMobile.logEvent(\\\"Checkout started\\\");\\nsailthruMobile.logEvent(\\\"Article shared\\\");\\n\\n// with Vars\\nJSONObject eventVars = new JSONObject().put(\\\"itemCount\\\", 3);\\nsailthruMobile.logEvent(\\\"Checkout started\\\", eventVars);\",\n      \"language\": \"java\",\n      \"name\": \"Android (Java)\"\n    },\n    {\n      \"code\": \"val sailthruMobile = SailthruMobile()\\nsailthruMobile.logEvent(\\\"Checkout started\\\")\\nsailthruMobile.logEvent(\\\"Article shared\\\")\\n\\n// with Vars\\nval eventVars = JSONObject().put(\\\"itemCount\\\", 3)\\nsailthruMobile.logEvent(\\\"Checkout started\\\", eventVars)\",\n      \"language\": \"kotlin\",\n      \"name\": \"Android (Kotlin)\"\n    },\n    {\n      \"code\": \"SailthruMobile.logEvent(\\\"Checkout started\\\");\\nSailthruMobile.logEvent(\\\"Article shared\\\");\\n\\n// with Vars\\nvar eventVars = {\\n  \\\"itemCount\\\" : 3\\n};\\nSailthruMobile.logEvent(\\\"Checkout started\\\", eventVars);\",\n      \"language\": \"javascript\",\n      \"name\": \"React Native (JavaScript)\"\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"NOTE\",\n  \"body\": \"The maximum amount of unique events which can be registered **per device** is limited to 50. Events are updated in batch, close to real-time, every few seconds.\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Auto-Analytics Tracking\"\n}\n[/block]\n### On iOS\nThe Sailthru Mobile iOS SDK automatically integrates with other analytics providers to capture some analytics. At the moment we capture only event data. This means that if you use the frameworks below to log events, they'll also be logged to Sailthru Mobile as an event also. \n\nThe providers we integrate with are:\n * Google Analytics\n * Mixpanel\n * Adobe Analytics (Formerly Omniture)\n * Localytics\n * Amplitutde\n * Flurry\n \nAuto-Analytics is opt-in. To enable Auto-Analytics, use the enableAutoAnalytics method. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"//Call as early as possible, perhaps straight after startEngine\\n\\n[[SailthruMobile new] enableAutoAnalytics:@[STMAutoAnalyticsSourceGoogleAnalytics, STMAutoAnalyticsSourceAdobe, STMAutoAnalyticsSourceMixpanel, STMAutoAnalyticsSourceLocalytics]];\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (Objective-C)\"\n    },\n    {\n      \"code\": \"//Call as early as possible, perhaps straight after startEngine\\n\\nSailthruMobile().enableAutoAnalytics([STMAutoAnalyticsSourceGoogleAnalytics, STMAutoAnalyticsSourceAdobe, STMAutoAnalyticsSourceMixpanel, STMAutoAnalyticsSourceLocalytics])\",\n      \"language\": \"swift\",\n      \"name\": \"iOS (Swift)\"\n    }\n  ]\n}\n[/block]\n#### Methods captured\n##### Google Analytics\n * `+ (id)createEventWithCategory:(NSString *)category action:(NSString *)action label:(NSString *)label value:(NSString *)value` \n\nWe discard `category`, `label` and `value`, and log a Sailthru Mobile event with the `action` as the `name`.\n\n##### Adobe Analytics\n * `+ (void)trackAction:(NSString *)action data:(id)data`\nWe discard `data` and log a Sailthru Mobile event with the `action` as the `name`.\n\n##### Mixpanel\n * `- (void)track:(NSString *)event properties:(NSString *)properties`\nWe discard `properties` and log a Sailthru Mobile event with the `event` as the `name`.\n\n##### Localytics\n * `- (void)tagEvent:(NSString *)eventName attributes:(NSDictionary *)attributes customerValueIncrease:(NSNumber *)customerValueIncrease;`\n\nWe discard `attributes` and `customerValueIncrease`, and log a Sailthru Mobile event with the `eventName` as the `name`.\n\n##### Flurry\n * `+ (NSInteger)logEvent:(NSString *)eventName withParameters:(NSDictionary *)parameters timed:(BOOL)timed`\n * `+ (NSInteger)logEvent:(NSString *)eventName timed:(BOOL)timed`\n\n\nWe discard `eventName`, `parameters` and `timed`, and log a Sailthru Mobile event with the `eventName` as the `name`.\n\n##### Amplitude\n * `- (void)logEvent:(NSString *)eventType withEventProperties:(NSDictionary *)eventProperties withApiProperties:(NSDictionary *)apiProperties withUserProperties:(NSDictionary *)userProperties withGroups:(NSDictionary *)groups withTimestamp:(NSNumber *)timestamp outOfSession:(BOOL)outOfSession` (Other event methods call this method)\n\n\nWe discard most parameters, and log a Sailthru Mobile event with the `eventType` as the `name`.\n\n\n### On Android\nFor Auto-Analytics Tracking on Android, the `logEvent()` call now takes a source parameter for when forwarding events from other analytics frameworks to Sailthru Mobile. This allows you to target based on events you already track.\n\n```java\nnew SailthruMobile().logEvent(\"source\", \"myEvent\");\n```\n\nA selection of pre-written integrations have been [provided](https://github.com/carnivalmobile/carnival-android-sdk/blob/master/Analytics%20Integration/AnalyticIntegration.java), allowing you to just include one file, replace your event logging calls and then turn on or off the frameworks you want to use by commenting them out in the source file provided.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"User Attributes don't record events that happen over time, and don't appear in graphs in the platform. They are simply metadata for a user. For recording events that happen over time, so you can target users by behavior, you should use our custom events feature.\",\n  \"title\": \"User Attributes or Custom Events?\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Tracking Location\"\n}\n[/block]\nBy default the Sailthru Mobile platform collects a last known IP location for each user.  This can be used for coarse location segmentation and targeting with no extra development effort or permissions in your app.\n\nDepending on local laws, you may need to obtain the express consent from your app users in order to track IP location. You can disabled IP location by default if required:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// must be called before startEngine\\n[[SailthruMobile new] setGeoIPTrackingDefault:NO];\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (Objective-C)\"\n    },\n    {\n      \"code\": \"// must be called before startEngine\\nSailthruMobile().setGeoIPTrackingDefault(false)\",\n      \"language\": \"swift\",\n      \"name\": \"iOS (Swift)\"\n    },\n    {\n      \"code\": \"// must be called before startEngine\\nnew SailthruMobile().setGeoIpTrackingDefault(false);\",\n      \"language\": \"java\",\n      \"name\": \"Android (Java)\"\n    },\n    {\n      \"code\": \"// must be called before startEngine\\nSailthruMobile().setGeoIpTrackingDefault(false)\",\n      \"language\": \"kotlin\",\n      \"name\": \"Android (Kotlin)\"\n    },\n    {\n      \"code\": \"// Set as RCTBridgeDelegate\\nRNSailthruMobileBridge *sailthruMobileBridge = [[RNSailthruMobileBridge alloc]    \\n                                    initWithJSCodeLocation: jsCodeLocation,\\n                                                    appKey: SDK_KEY,\\n                              \\t\\t pushAuthorizationOption: STMPushAuthorizationOptionFull,\\n                                      geoIpTrackingDefault: NO];\",\n      \"language\": \"objectivec\",\n      \"name\": \"React Native - iOS (Objective-C)\"\n    },\n    {\n      \"code\": \"// Set as RCTBridgeDelegate\\nvar sailthruMobileBridge = RNSailthruMobileBridge(jsCodeLocation: jsCodeLocation,\\n                                              \\t\\t\\t      appKey: SDK_KEY,\\n                        \\t\\t \\t\\t\\t\\t\\t\\t pushAuthorizationOption: .full,\\n                                \\t\\t\\t\\t\\t  geoIpTrackingDefault: false)\",\n      \"language\": \"swift\",\n      \"name\": \"React Native - iOS (Swift)\"\n    },\n    {\n      \"code\": \"// Added to list of ReactPackages\\nRNSailthruMobilePackage.Builder.createInstance(getApplicationContext(),\\n                            \\\"ec27b1ca830238179747e2b812ad38bfcd4f9823\\\")\\n                            .setGeoIPTrackingDefault(false)\\n                            .build()\",\n      \"language\": \"java\",\n      \"name\": \"React Native - Android (Java)\"\n    }\n  ]\n}\n[/block]\nYou can also enable or disable it later for an existing device.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[[SailthruMobile new] setGeoIPTrackingEnabled:NO];\\n\\n// with result handler\\n[[SailthruMobile new] setGeoIPTrackingEnabled:NO withResponse:^(NSError * _Nullable error) {\\n    // Check if error is non-nil for result\\n}];\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (Objective-C)\"\n    },\n    {\n      \"code\": \"SailthruMobile().setGeoIPTrackingEnabled(false)\\n\\n// with result handler\\nSailthruMobile().setGeoIPTrackingEnabled(false) { (error : Error?) in\\n    // Check if error is non-nil for result\\n}\",\n      \"language\": \"swift\",\n      \"name\": \"iOS (Swift)\"\n    },\n    {\n      \"code\": \"new SailthruMobile().setGeoIpTrackingEnabled(false);\\n\\n// with result handler\\nnew SailthruMobile().setGeoIpTrackingEnabled(false, new SailthruMobile.SailthruMobileHandler<Void>() {\\n    @Override\\n    public void onSuccess(Void value) {\\n\\t\\t\\t// handle success\\n    }\\n\\n    @Override\\n    public void onFailure(Error error) {\\n\\t\\t\\t// handle error\\n    }\\n});\",\n      \"language\": \"java\",\n      \"name\": \"Android (Java)\"\n    },\n    {\n      \"code\": \"SailthruMobile().setGeoIpTrackingEnabled(false)\\n\\n// with result handler\\nSailthruMobile().setGeoIpTrackingEnabled(false, object : SailthruMobileHandler<Void?> {\\n  override fun onSuccess(value: Void?) {\\n    // handle success\\n  }\\n\\n  override fun onFailure(error: Error?) {\\n    // handle error\\n  }\\n})\",\n      \"language\": \"kotlin\",\n      \"name\": \"Android (Kotlin)\"\n    },\n    {\n      \"code\": \"SailthruMobile.setGeoIPTrackingEnabled(false);\\n\\n// with result handler\\nSailthruMobile.setGeoIPTrackingEnabled(false).then(result => {\\n\\t// Handle success\\n}).catch(e => {\\n\\t// Handle error\\n});\",\n      \"language\": \"javascript\",\n      \"name\": \"React Native (JavaScript)\"\n    }\n  ]\n}\n[/block]\nIn order to support more granular location, it is up to the app to decide and manage the accuracy of capturing location information, while considering the user's battery life. It's best practice to use only the accuracy you need for messaging (Block, City, State, Country).\n\nLocation updates can then be passed through to Sailthru Mobile for segmentation.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// On iOS, using Objective-C\\n[[SailthruMobile new] updateLocation:myLocation]; //Takes an instance of a CLLocation object as a argument.\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (Objectve-C)\"\n    },\n    {\n      \"code\": \"// On iOS, using Swift\\nSailthruMobile().updateLocation(myLocation) //Takes an instance of a CLLocation object as a argument.\",\n      \"language\": \"swift\",\n      \"name\": \"iOS (Swift)\"\n    },\n    {\n      \"code\": \"// On Android, using Java\\nnew SailthruMobile().updateLocation(myLocation); //Takes an instance of a Location object as a argument.\",\n      \"language\": \"java\",\n      \"name\": \"Android (Java)\"\n    },\n    {\n      \"code\": \"// On Android, using Kotlin\\nSailthruMobile().updateLocation(myLocation) //Takes an instance of a Location object as a argument.\",\n      \"language\": \"kotlin\",\n      \"name\": \"Android (Kotlin)\"\n    },\n    {\n      \"code\": \"// On React Native, using JavaScript\\nSailthruMobile.updateLocation(lat, lon); //Takes lattitude and longitude as arguments\",\n      \"language\": \"javascript\",\n      \"name\": \"React Native (JavaScript)\"\n    }\n  ]\n}\n[/block]\nBelow are some short tutorials for collecting a user's location on Both iOS and Android:\n\n* [Location Tracking on iOS](doc:location-tracking-on-ios) \n* [Location Tracking on Android](https://developer.android.com/training/location/index.html)\n[block:api-header]\n{\n  \"title\": \"Getting the Device ID\"\n}\n[/block]\nYou can retrieve the device ID from the SDK if you would like to use it in your app. The device ID will be returned as a string in an asynchronous operation.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[[SailthruMobile new] deviceID:^(NSString * _Nullable deviceID, NSError * _Nullable error) {\\n    if(error) {\\n        // Handle error\\n        return;\\n    }\\n    // Handle deviceID\\n}];\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (Objective-C)\"\n    },\n    {\n      \"code\": \"SailthruMobile().deviceID { (deviceID, errorOrNil) in\\n\\t  if let error = errorOrNil {\\n\\t\\t    // Handle error\\n\\t\\t    return\\n\\t\\t}\\n\\t\\t// Handle deviceID\\n}\",\n      \"language\": \"swift\",\n      \"name\": \"iOS (Swift)\"\n    },\n    {\n      \"code\": \"new SailthruMobile().getDeviceId(new SailthruMobile.SailthruMobileHandler<String>() {\\n    @Override\\n    public void onSuccess(String deviceID) {\\n        // Handle deviceID\\n    }\\n\\n    @Override\\n    public void onFailure(Error error) {\\n        // Handle error\\n    }\\n});\",\n      \"language\": \"java\",\n      \"name\": \"Android (Java)\"\n    },\n    {\n      \"code\": \"SailthruMobile().getDeviceId(object : SailthruMobileHandler<String?> {\\n  override fun onSuccess(deviceID: String?) {\\n    // Handle deviceID\\n  }\\n\\n  override fun onFailure(error: Error?) {\\n    // Handle error\\n  }\\n})\",\n      \"language\": \"kotlin\",\n      \"name\": \"Android (Kotlin)\"\n    },\n    {\n      \"code\": \"SailthruMobile.getDeviceID().then(function(deviceID) {\\n    // Handle device ID\\n}, function(error){\\n    // Handle error\\n});\",\n      \"language\": \"javascript\",\n      \"name\": \"React Native (JavaScript)\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Clearing Device Data\"\n}\n[/block]\nAt times, such as a logging out flow or a user settings screen, you might want to clear device data. You're able to clear data for Events, Custom Attributes and Message Stream.\n\nWarning: By clearing events or custom attributes, the device may become eligible for an automated message triggered based on leaving an audience. Double check your set up before using this method. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[[SailthruMobile new] clearDeviceData:STMDeviceDataTypeEvents | STMDeviceDataTypeAttributes | STMDeviceDataTypeMessageStream withResponse:^(NSError * _Nullable error) { \\n  // Possible error here\\n}];\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (Objective-C)\"\n    },\n    {\n      \"code\": \"  SailthruMobile().clear([.attributes, .messageStream, .events]) { (error) in\\n      // Possible error here\\n  }\",\n      \"language\": \"swift\",\n      \"name\": \"iOS (Swift)\"\n    },\n    {\n      \"code\": \"//SailthruMobile.ATTRIBUTES|SailthruMobile.MESSAGE_STREAM|SailthruMobile.EVENTS\\nnew SailthruMobile().clearDevice(SailthruMobile.CLEAR_ALL, new SailthruMobile.SailthruMobileHandler<Void>() {\\n    @Override\\n    public void onSuccess(Void value) {\\n\\n    }\\n\\n    @Override\\n    public void onFailure(Error error) {\\n\\n    }\\n});\",\n      \"language\": \"java\",\n      \"name\": \"Android (Java)\"\n    },\n    {\n      \"code\": \"//SailthruMobile.ATTRIBUTES|SailthruMobile.MESSAGE_STREAM|SailthruMobile.EVENTS\\nSailthruMobile().clearDevice(SailthruMobile.CLEAR_ALL, object : SailthruMobileHandler<Void?> {\\n  override fun onSuccess(value: Void?) {\\n\\n  }\\n\\n  override fun onFailure(error: Error?) {\\n\\n  }\\n})\",\n      \"language\": \"kotlin\",\n      \"name\": \"Android (Kotlin)\"\n    },\n    {\n      \"code\": \"// Clear one or more types. Specify one or more of these values.\\nSailthruMobile.clearDevice(\\n  SailthruMobile.DeviceValues.Attributes | \\n  SailthruMobile.DeviceValues.MessageStream |\\n  SailthruMobile.DeviceValues.Events);\\n\\n// Clear all device data\\nSailthruMobile.clearDevice(SailthruMobile.DeviceValues.ClearAll);\",\n      \"language\": \"javascript\",\n      \"name\": \"React Native (JavaScript)\"\n    }\n  ]\n}\n[/block]","updates":["5601e23ffb9f160d00f29875","56b27e0d2d964617005992ba","582488e6d90fa027009b2590"],"order":5,"isReference":false,"hidden":false,"sync_unique":"","link_url":"","link_external":false,"_id":"5e6156bf5e4a51006dcd812e","user":"55d2bd8e2463351700f67dd7","version":{"version":"1.5","version_clean":"1.5.0","codename":"ST Rebrand","is_stable":true,"is_beta":false,"is_hidden":false,"is_deprecated":false,"categories":["5e6156bf5e4a51006dcd8120","5e6156bf5e4a51006dcd8121","5e6156bf5e4a51006dcd8122","5e6156bf5e4a51006dcd8123","5e6156bf5e4a51006dcd8124","561c61b4ad272c0d00a892df","586c014c0abf1d0f000d04d4","58991d2ad207df0f0002186b","5e6156bf5e4a51006dcd8125","5e6156bf5e4a51006dcd8126","5af0fe494ca2730003cbc98a","5af0fe55ec80af0003804ca2","5e69868cbd5dcb006b35867b","5e6986ca2c6652006791b6e8"],"_id":"5e6156bf5e4a51006dcd818c","project":"55e67aaa9cc7c62b00c4a1ea","__v":2,"forked_from":"5b720760c44b7600034b7a08","createdAt":"2015-09-02T04:27:23.612Z","releaseDate":"2015-09-02T04:27:23.612Z"},"category":{"sync":{"isSync":false,"url":""},"pages":["5e6156bf5e4a51006dcd812a","5e6156bf5e4a51006dcd812c","5e6156bf5e4a51006dcd812d","5e6156bf5e4a51006dcd812e","55e682b7de6fef23009480dc","5e6156bf5e4a51006dcd812f","5e6156bf5e4a51006dcd8130","5e6156bf5e4a51006dcd8131","5e6156bf5e4a51006dcd8132","5e6156bf5e4a51006dcd8133","5e6156bf5e4a51006dcd8134","5b720760c44b7600034b79bc","5e6156bf5e4a51006dcd8135","5e6156bf5e4a51006dcd8148","5e6156bf5e4a51006dcd8149","5e6156bf5e4a51006dcd814a","5e6156bf5e4a51006dcd814b","5e6156bf5e4a51006dcd814c","5e6156bf5e4a51006dcd814f","5e6156bf5e4a51006dcd8150","5e6156bf5e4a51006dcd8152","561c6ca0be5fb20d00077754","5e6156bf5e4a51006dcd8157","5e6156bf5e4a51006dcd8158","5b720760c44b7600034b79e2","5e6156bf5e4a51006dcd8159","5e6156bf5e4a51006dcd815a","5e6156bf5e4a51006dcd815b","5e6156bf5e4a51006dcd815c","56cfa5386c5d7a13005eec0f","56e73d86555c030e00a52a73","56e7460c9000b120000ffe2e","56e8c19e99c6400e003820cf","56e8c53fc88bf80e00f8bed8","56f06ff4d386ce0e008e9b21"],"title":"Install in your app","slug":"install-in-your-app","order":1,"from_sync":false,"reference":false,"_id":"5e6156bf5e4a51006dcd8121","__v":35,"createdAt":"2015-09-02T04:30:13.305Z","project":"55e67aaa9cc7c62b00c4a1ea","version":"5e6156bf5e4a51006dcd818c"},"githubsync":"","__v":117,"createdAt":"2015-09-02T04:53:53.688Z","parentDoc":null,"project":"55e67aaa9cc7c62b00c4a1ea"}

Collecting User Data


The strength of Sailthru Mobile's targeting and segmentation relies on knowing the correct information about your users. The more information we know about a user, the better you can target them when you send messages. When a user installs an app, we collect a few attributes automatically. These attributes are helpful for targeting and segmenting your users. ### Automatically Tracked Attributes - App Version - Language - Time Zone - Badge Number (iOS only) - Device ID - Device Make & Model - Operating System & Version - Sailthru Mobile SDK version - Location based on IP Address - Notifications Allowed - Platform [block:callout] { "type": "info", "body": "Attributes tracked automatically are refreshed at every app load." } [/block] Beyond the automatically tracked attributes, Sailthru Mobile also lets you store custom information about a user for further segmenting and targeting. This feature is called [User Attributes](#user-attributes). [block:api-header] { "type": "basic", "title": "Setting a User ID" } [/block] If your app has a login, you can set a unique User ID with Sailthru Mobile. This allows you to associate multiple devices to a single user when targeting via the API. You may also want to collect the [user's email ](http://docs.mobile.sailthru.com/docs/collecting-user-data#setting-a-user-email) as well. [block:code] { "codes": [ { "code": "// setting a User ID after login\n[[SailthruMobile new] setUserId:@\"user_id_1234\" withResponse:^(NSError *error) {\n NSLog(@\"Error setting user id – %@\", error.localizedDescription);\n}];\n\n// clearing a User ID after logout\n[[SailthruMobile new] setUserId:nil withResponse:^(NSError *error) {\n \n}];", "language": "objectivec", "name": "iOS (Objective-C)" }, { "code": "// setting a User ID after login\nSailthruMobile().setUserId(\"user_id_1234\") { error in\n print(\"setUserID returned with possible error: \\(error)\")\n}\n\n// clearing a User ID after logout\nSailthruMobile().setUserId(nil) { error in\n print(\"setUserID returned with possible error: \\(error)\")\n}", "language": "swift", "name": "iOS (Swift)" }, { "code": "// setting a User ID after login\nnew SailthruMobile().setUserId(\"user_id_1234\", new SailthruMobile.SailthruMobileHandler<Void> (){\n\n @Override\n public void onSuccess (Void value){\n //Do Something\n }\n\n @Override\n public void onFailure (Error error){\n //Do Something\n }\n});\n\n\n// clearing a User ID after logout\nnew SailthruMobile().setUserId(null, new SailthruMobile.SailthruMobileHandler<Void> (){\n\n @Override\n public void onSuccess (Void value){\n //Do Something\n }\n\n @Override\n public void onFailure (Error error){\n //Do Something\n }\n});", "language": "java", "name": "Android (Java)" }, { "code": "// setting a User ID after login\nSailthruMobile().setUserId(\"user_id_1234\", object : SailthruMobileHandler<Void?> {\n override fun onSuccess(value: Void?) {\n //Do Something\n }\n\n override fun onFailure(error: Error?) {\n //Do Something\n }\n})\n\n// clearing a User ID after logout\nSailthruMobile().setUserId(null, object : SailthruMobileHandler<Void?> {\n override fun onSuccess(value: Void?) {\n //Do Something\n }\n\n override fun onFailure(error: Error?) {\n //Do Something\n }\n})", "language": "kotlin", "name": "Android (Kotlin)" }, { "code": "// setting a User ID after login\nSailthruMobile.setUserId(\"user_id_1234\");\n\n// clearing a User ID after logout\nSailthruMobile.setUserId(\"\");", "language": "javascript", "name": "React Native (JavaScript)" } ] } [/block] [block:callout] { "type": "info", "body": "Setting a User ID is optional, but it is strongly recommended. It is a prerequisite to use:\n\n* Sending notifications to specific users, including using the [Notifications API](/docs/notifications) with `user_id` audiences\n* [Users API](/docs/users)\n* [Users Events API](/docs/users-events)\n* [Audience creation via CSV](https://getstarted.sailthru.com/sailthru-mobile/audiences/creating-mobile-app-audiences/#By_CSV)\n\nWithout User ID you will be able to set attributes and events only at the device level." } [/block] [block:api-header] { "type": "basic", "title": "Setting a User Email" } [/block] Setting a user email allows to link a device to an identifier user profile in Sailthru, matching the email you provide with an existing Email ID. This is a required step to leverage omnichannel personalization using interests and other data points from the Sailthru user profile. We recommend to collect both User ID and email. [block:code] { "codes": [ { "code": "// setting a User Email after login\n[[SailthruMobile new] setUserEmail:@\"[email protected]\" withResponse:^(NSError *error) {\n NSLog(@\"Error setting user email – %@\", error.localizedDescription);\n}];\n\n// clearing a User Email after logout\n[[SailthruMobile new] setUserEmail:nil withResponse:^(NSError *error) {\n NSLog(@\"Error setting user email – %@\", error.localizedDescription);\n}];", "language": "objectivec", "name": "iOS (Objective-C)" }, { "code": "// setting a User Email after login\nSailthruMobile().setUserEmail(\"[email protected]\") { error in\n print(\"setUserEmail returned with possible error: \\(error)\")\n}\n\n// clearing a User Email after logout\nSailthruMobile().setUserEmail(nil) { error in\n print(\"setUserEmail returned with possible error: \\(error)\")\n}", "language": "swift", "name": "iOS (Swift)" }, { "code": "// setting a User Email after login\nnew SailthruMobile().setUserEmail(\"[email protected]\", new SailthruMobile.SailthruMobileHandler<Void> (){\n\n @Override\n public void onSuccess (Void value){\n //Do Something\n }\n\n @Override\n public void onFailure (Error error){\n //Do Something\n }\n});\n\n\n// clearing a User Email after logout\nnew SailthruMobile().setUserEmail(null, new SailthruMobile.SailthruMobileHandler<Void> (){\n\n @Override\n public void onSuccess (Void value){\n //Do Something\n }\n\n @Override\n public void onFailure (Error error){\n //Do Something\n }\n});", "language": "java", "name": "Android (Java)" }, { "code": "// setting a User Email after login\nSailthruMobile().setUserEmail(\"[email protected]\", object : SailthruMobileHandler<Void?> {\n override fun onSuccess(value: Void?) {\n //Do Something\n }\n\n override fun onFailure(error: Error?) {\n //Do Something\n }\n})\n\n\n// clearing a User Email after logout\nSailthruMobile().setUserEmail(null, object : SailthruMobileHandler<Void?> {\n override fun onSuccess(value: Void?) {\n //Do Something\n }\n\n override fun onFailure(error: Error?) {\n //Do Something\n }\n})", "language": "kotlin", "name": "Android (Kotlin)" }, { "code": "// setting a User Email after login\nSailthruMobile.setUserEmail(\"[email protected]\");\n\n// clearing a User Email after logout\nSailthruMobile.setUserEmail(\"\");", "language": "javascript", "name": "React Native (JavaScript)" } ] } [/block] [block:api-header] { "type": "basic", "title": "User Attributes" } [/block] User Attributes provide a powerful & flexible way for developers to store extra metadata for the purposes of grouping, segmenting and targeting users at a later stage. Each User/Device can have multiple attributes. User Attributes are unique to a device and app, and persist between app opens. They are set on the SDK side and saved back to the Sailthru Mobile platform with the appropriate SDK methods. Each User Attribute has a name, a type and a value. For example; - `first_name` (String) - `lifetime_value` (Float) - `number_of_items_purchased` (Integer) - `is_premium_subscriber` (Boolean) The following attribute datatypes are supported; * Integer (32 bit) * Float * Date * String * Boolean * Array (of Integer, Floats, Dates and Strings) ### To set some User attributes from the SDK [block:code] { "codes": [ { "code": "// Construct the object\nSTMAttributes *attributes = [[STMAttributes alloc] init];\n\n// Set one or more attributes\n[attributes setString:@\"Handbags\" forKey:@\"last_visited_category\"];\n[attributes setStrings:@[@\"world\", @\"sports\"] forKey:@\"subscriptions\"];\n[attributes setFloat:104.87 forKey:@\"customer_ltv\"];\n[attributes setInteger:3 forKey:@\"products_in_cart\"];\n[attributes setFloats:@[@(36.99), @(42.3)] forKey:@\"cart_items_unit_price\"];\n[attributes setIntegers:@[@(2), @(1)] forKey:@\"cart_item_quantities\"];\n[attributes setBool:YES forKey:@\"user_did_use_facebook_login\"];\n[attributes setDates:@[[NSDate date]] forKey:@\"checkout_started\"];\n\n// Optional: choose if you want to add new attributes to the existing (update), or if you want to overwrite the current attributes with the new payload (replace). By default, we update.\n[attributes setAttributesMergeRule:STMAttributesMergeRuleUpdate];\n\nSailthruMobile *sailthruMobile = [SailthruMobile new];\n\n// Send to Sailthru Mobile\n[sailthruMobile setAttributes:attributes withResponse:^(NSError * _Nullable error) {\n if (error) {\n NSLog(@\"Error - %@\", [error debugDescription]);\n }\n}];\n\n// Remove an attribute\n[sailthruMobile removeAttributeWithKey:@\"products_in_cart\" withResponse:nil];", "language": "objectivec", "name": "iOS (Objective-C)" }, { "code": "// Construct the object\nlet attributes = STMAttributes()\n\n// Set one or more attributes\nattributes.setString(\"Handbags\", forKey: \"last_visited_category\")\nattributes.setStrings([\"world\", \"sports\"], forKey: \"subscriptions\")\nattributes.setFloat(104.87, forKey: \"customer_ltv\")\nattributes.setInteger(3, forKey: \"products_in_cart\")\nattributes.setFloats([36.99, 42.3], forKey: \"cart_items_unit_price\")\nattributes.setIntegers([2, 1], forKey: \"cart_item_quantities\")\nattributes.setBool(true, forKey: \"user_did_use_facebook_login\")\nattributes.setDates(NSDate(), forKey: \"checkout_started\")\n\n// Optional: choose if you want to add new attributes to the existing (update), or if you want to overwrite the current attributes with the new payload (replace). By default, we update.\nattributes.setAttributesMergeRule(.Update)\n\nlet sailthruMobile = SailthruMobile()\n\n// Send to Sailthru Mobile\nsailthruMobile.setAttributes(attributes) { error in\n print(\"setAttributes returned with possible error: \\(error)\")\n}\n\n// Remove an attribute\nsailthruMobile.removeAttributeWithKey(\"products_in_cart\", nil)", "language": "swift", "name": "iOS (Swift)" }, { "code": "// Construct the object\nAttributeMap attributes = new AttributeMap();\n\n// Set one or more attributes\nattributes.putString(\"last_visited_category\", \"Handbags\");\n\nArrayList<String> subscriptions = new ArrayList<>(Arrays.asList(\"world\", \"sports\"));\nattributes.putStringArray(\"subscriptions\", subscriptions);\n\nattributes.putFloat(\"customer_ltv\", 104.87f);\n\nArrayList<Float> cartItemsUnitPrice = new ArrayList<>(Arrays.asList(36.99f, 42.3f));\nattributes.putFloatArray(\"cart_items_unit_price\", cartItemsUnitPrice);\n\nattributes.putInt(\"products_in_cart\", 3);\n\nArrayList<Integer> cartItemQuantities = new ArrayList<>(Arrays.asList(2, 1));\nattributes.putIntArray(\"cart_item_quantities\", cartItemQuantities);\n\nattributes.putBoolean(\"user_did_user_facebook_login\", true);\nattributes.putDate(\"checkout_started\", new Date());\n\n// Optional: choose if you want to add new attributes to the existing (update), or if you want to overwrite the current attributes with the new payload (replace). By default, we update.\nattributes.setMergeRules(AttributeMap.RULE_UPDATE);\n\nSailthruMobile sailthruMobile = new SailthruMobile();\n\n// Send to Sailthru Mobile\nsailthruMobile.setAttributes(attributes, new SailthruMobile.AttributesHandler() {\n @Override\n public void onSuccess() {\n // Handle success here\n }\n\n @Override\n public void onFailure(Error error) {\n // Handle failure here\n Log.d(\"YOUR_LOG_TAG\", \"setAttributes returned with possible error: \" + error.getLocalizedMessage());\n }\n});\n\n// Remove an attribute\nsailthruMobile.removeAttribute(\"products_in_cart\");", "language": "java", "name": "Android (Java)" }, { "code": "// Construct the object\nval attributes = AttributeMap()\n\n// Set one or more attributes\nattributes.putString(\"last_visited_category\", \"Handbags\")\n\nval subscriptions: ArrayList<String> = ArrayList(Arrays.asList(\"world\", \"sports\"))\nattributes.putStringArray(\"subscriptions\", subscriptions)\n\nattributes.putFloat(\"customer_ltv\", 104.87f)\n\nval cartItemsUnitPrice: ArrayList<Float> = ArrayList(Arrays.asList(36.99f, 42.3f))\nattributes.putFloatArray(\"cart_items_unit_price\", cartItemsUnitPrice)\n\nattributes.putInt(\"products_in_cart\", 3)\n\nval cartItemQuantities: ArrayList<Int> = ArrayList(Arrays.asList(2, 1))\nattributes.putIntArray(\"cart_item_quantities\", cartItemQuantities)\n\nattributes.putBoolean(\"user_did_user_facebook_login\", true)\nattributes.putDate(\"checkout_started\", Date())\n\n// Optional: choose if you want to add new attributes to the existing (update), or if you want to overwrite the current attributes with the new payload (replace). By default, we update.\nattributes.setMergeRules(AttributeMap.RULE_UPDATE)\n\nval sailthruMobile = SailthruMobile()\n\n// Send to Sailthru Mobile\nsailthruMobile.setAttributes(attributes, object : SailthruMobile.AttributesHandler {\n override fun onSuccess() {\n // Handle success here\n }\n\n override fun onFailure(error: Error?) {\n // Handle failure here\n Log.d(\"YOUR_LOG_TAG\", \"setAttributes returned with possible error: \" + error!!.localizedMessage)\n }\n})\n\n// Remove an attribute\nsailthruMobile.removeAttribute(\"products_in_cart\")", "language": "kotlin", "name": "Android (Kotlin)" }, { "code": "// Construct the object\nvar attrMap = new SailthruMobile.AttributeMap();\n\n// Set one or more attributes\nattrMap.setString(\"string_key\", \"This is the string value\");\nattrMap.setStringArray(\"strings_key\", [\"This is first value\", \"This is the second value\"]);\nattrMap.setDate(\"date_key\", new Date());\nattrMap.setDateArray(\"dates_key\", [new Date(), new Date(), new Date()]);\nattrMap.setFloat(\"float_key\", 3.141);\nattrMap.setFloatArray(\"floats_key\", [1.1, 2.2, 3.3, 4.4]);\nattrMap.setInteger(\"integer_key\", 3);\nattrMap.setIntegerArray(\"integers_key\", [1, 2, 3, 4]);\nattrMap.setBoolean(\"boolean_key\", true);\n\n// Optional: choose if you want to add new attributes to the existing (update), or if you want to overwrite the current attributes with the new payload (replace). By default, we update.\nattrMap.setMergeRule(attrMap.MergeRules.Update);\n\n// Send to Sailthru Mobile\nSailthruMobile.setAttributes(attrMap).catch(e => {\n\t// Handle error\n});", "language": "javascript", "name": "React Native (JavaScript)" } ] } [/block] ### Custom Attribute Limits There are limits in place on the maximum number of custom attributes allowed as well as the length (size) of strings and arrays. * A maximum of **50** custom attributes is allowed per device. If you exceed this amount any new attributes being set will be discarded. * String values that have more than **255** characters will be truncated. * Arrays with more than **50** elements will be truncated. ### Key name restrictions * Only letters, numbers, underscore and dashes are valid characters. * Leading spaces will be removed. * Invalid characters other than spaces and dots will be removed. * Spaces and dots will be replaced for underscores. * Keys will be truncated to a maximum of 255 characters. * Invalid keys will simply be discarded and no error will be returned. [block:callout] { "type": "info", "body": "Custom attributes are refreshed in real time." } [/block] [block:api-header] { "title": "Sailthru Profile Vars" } [/block] Sailthru Profile Vars can be set and retrieved through the SDK. This makes maintaining state between your email/on-site campaigns and your mobile marketing easy. Note that the use of this feature requires that your app be linked to Sailthru Email/On-Site. Vars should be set in a JSON object format: [block:code] { "codes": [ { "code": "// Setup profile vars object\nNSDictionary *profileVars = @{\n @\"string_key\" : @\"string_value\",\n @\"object_key\" : @{},\n @\"boolean_key\" : @YES\n};\n \n// Set profile vars\n[[SailthruMobile new] setProfileVars:profileVars withResponse:^(NSError * _Nullable error) {\n // Check if error is non-nil for result\n}];", "language": "objectivec", "name": "iOS (Objective-C)" }, { "code": "// Setup profile vars object\nlet profileVars : [String : Any] = [ \n \t\"string_key\" : \"string_value\",\n\t\t\"object_key\" : [],\n\t\t\"boolean_key\" : true \n]\n\n// Set profile vars\nSailthruMobile().setProfileVars(profileVars) { (error : Error?) in\n\t\t// Check if error is non-nil for result\n}", "language": "swift", "name": "iOS (Swift)" }, { "code": "// Setup profile vars object\nJSONObject profileVars = new JSONObject();\nprofileVars.put(\"string_key\", \"string_value\");\nprofileVars.put(\"object_key\", new JSONObject());\nprofileVars.put(\"boolean_key\", true);\n\n// Set profile vars\nnew SailthruMobile().setProfileVars(profileVars, new SailthruMobile.SailthruMobileHandler<Void>() {\n @Override\n public void onSuccess(Void value) {\n // Handle success\n }\n\n @Override\n public void onFailure(Error error) {\n // Handle error\n }\n});", "language": "java", "name": "Android (Java)" }, { "code": "// Setup profile vars object\nval profileVars = JSONObject()\nprofileVars.put(\"string_key\", \"string_value\")\nprofileVars.put(\"object_key\", JSONObject())\nprofileVars.put(\"boolean_key\", true)\n\n// Set profile vars\nSailthruMobile().setProfileVars(profileVars, object : SailthruMobileHandler<Void?> {\n override fun onSuccess(value: Void?) {\n // Handle success\n }\n\n override fun onFailure(error: Error?) {\n // Handle error\n }\n})", "language": "kotlin", "name": "Android (Kotlin)" }, { "code": "// Setup profile vars object\nvar profileVars = {\n\t\"string_key\" : \"string_value\",\n\t\"object_key\" : {},\n\t\"boolean_key\": true\n};\n\n// Set profile vars\nSailthruMobile.setProfileVars(profileVars).then(result => {\n // Handle success\n}).catch(e => {\n // Handle error\n});", "language": "javascript", "name": "React Native (JavaScript)" } ] } [/block] When retrieving vars they will be returned in the same JSON object format: [block:code] { "codes": [ { "code": "[[SailthruMobile new] getProfileVarsWithResponse:^(NSDictionary<NSString *,id> * _Nullable profileVars, NSError * _Nullable error) {\n // Handle profileVars object or error\n}];", "language": "objectivec", "name": "iOS (Objective-C)" }, { "code": "SailthruMobile().getProfileVars { (profileVars : [String : Any]?, error : Error?) in\n\t\t// Handle profileVars object or error\n}", "language": "swift", "name": "iOS (Swift)" }, { "code": "new SailthruMobile.getProfileVars(new SailthruMobile.SailthruMobileHandler<JSONObject>() {\n @Override\n public void onSuccess(JSONObject profileVars) {\n\t\t\t\t// Handle profileVars object\n }\n\n @Override\n public void onFailure(Error error) {\n // Handle error\n }\n});", "language": "java", "name": "Android (Java)" }, { "code": "SailthruMobile().getProfileVars(object : SailthruMobileHandler<JSONObject?> {\n override fun onSuccess(profileVars: JSONObject?) {\n // Handle profileVars object\n }\n\n override fun onFailure(error: Error?) {\n // Handle error\n }\n})", "language": "kotlin", "name": "Android (Kotlin)" }, { "code": "SailthruMobile.getProfileVars().then(profileVars => {\n\t// Handle profileVars object\n}).catch(e => {\n\t// Handle error\n});", "language": "javascript", "name": "React Native (JavaScript)" } ] } [/block] ## Variable names * Are case sensitive. For example, if you create a variable named “Survey_Score” it will not be accessible using all lowercase letters. * May not start with a number or be only numbers. For example, don’t upload phone numbers using var name “#”. * May not contain special characters (such as %, -, or $). These characters will be scrubbed from variable names upon import. * May not contain spaces. If the variable name is submitted with a space, it will be converted to an underscore. ## Date and Time Formats * In order to maintain strict JSON compatibility, Sailthru vars do not support a native date or time type. Instead, if you use [specific naming and formatting](https://getstarted.sailthru.com/audience/managing-users/set-variables-on-users/#Date_andTime_Formats) conventions, Sailthru will treat these values as dates and times throughout our system, for example, when performing queries in Audience Builder. For more information on Vars, see the [User Variables](https://getstarted.sailthru.com/audience/managing-users/set-variables-on-users/) docs [block:api-header] { "type": "basic", "title": "Custom Events" } [/block] Sailthru Mobile's Custom Events provide a simple event tracking solution for measuring actions in your app. _Events_ can be logged to track actions that users take, such as screen views, or social network shares. Unlike user attributes, events occur over time and graphs of the events can be seen within the analytics section of the Sailthru Mobile dashboard. Sailthru Mobile keeps record of the count and the last occurrence of an event for each user, so you can target and segment based on; - Whether a user has performed this event or not - When they last performed this event - How often they have performed this event These events are also passed through to the Lifecycle Optimiser where they can be used to build powerful workflows for both mobile and email. ### To log a Custom Event [block:code] { "codes": [ { "code": "SailthruMobile *sailthruMobile = [SailthruMobile new];\n[sailthruMobile logEvent:@\"Checkout started\"];\n[sailthruMobile logEvent:@\"Article shared\"];\n\n// with Vars\nNSDictionary* eventVars = @{ @\"itemCount\" : @3 };\n[sailthruMobile logEvent:@\"Checkout started\" withVars:eventVars];", "language": "objectivec", "name": "iOS (Objective-C)" }, { "code": "let sailthruMobile = SailthruMobile()\nsailthruMobile.logEvent(\"Checkout started\")\nsailthruMobile.logEvent(\"Article shared\")\n\n// with Vars\nlet eventVars = [ \"itemCount\" : 3 ]\nsailthruMobile.logEvent(\"Checkout started\", withVars: eventVars)", "language": "swift", "name": "iOS (Swift)" }, { "code": "SailthruMobile sailthruMobile = new SailthruMobile();\nsailthruMobile.logEvent(\"Checkout started\");\nsailthruMobile.logEvent(\"Article shared\");\n\n// with Vars\nJSONObject eventVars = new JSONObject().put(\"itemCount\", 3);\nsailthruMobile.logEvent(\"Checkout started\", eventVars);", "language": "java", "name": "Android (Java)" }, { "code": "val sailthruMobile = SailthruMobile()\nsailthruMobile.logEvent(\"Checkout started\")\nsailthruMobile.logEvent(\"Article shared\")\n\n// with Vars\nval eventVars = JSONObject().put(\"itemCount\", 3)\nsailthruMobile.logEvent(\"Checkout started\", eventVars)", "language": "kotlin", "name": "Android (Kotlin)" }, { "code": "SailthruMobile.logEvent(\"Checkout started\");\nSailthruMobile.logEvent(\"Article shared\");\n\n// with Vars\nvar eventVars = {\n \"itemCount\" : 3\n};\nSailthruMobile.logEvent(\"Checkout started\", eventVars);", "language": "javascript", "name": "React Native (JavaScript)" } ] } [/block] [block:callout] { "type": "info", "title": "NOTE", "body": "The maximum amount of unique events which can be registered **per device** is limited to 50. Events are updated in batch, close to real-time, every few seconds." } [/block] [block:api-header] { "type": "basic", "title": "Auto-Analytics Tracking" } [/block] ### On iOS The Sailthru Mobile iOS SDK automatically integrates with other analytics providers to capture some analytics. At the moment we capture only event data. This means that if you use the frameworks below to log events, they'll also be logged to Sailthru Mobile as an event also. The providers we integrate with are: * Google Analytics * Mixpanel * Adobe Analytics (Formerly Omniture) * Localytics * Amplitutde * Flurry Auto-Analytics is opt-in. To enable Auto-Analytics, use the enableAutoAnalytics method. [block:code] { "codes": [ { "code": "//Call as early as possible, perhaps straight after startEngine\n\n[[SailthruMobile new] enableAutoAnalytics:@[STMAutoAnalyticsSourceGoogleAnalytics, STMAutoAnalyticsSourceAdobe, STMAutoAnalyticsSourceMixpanel, STMAutoAnalyticsSourceLocalytics]];", "language": "objectivec", "name": "iOS (Objective-C)" }, { "code": "//Call as early as possible, perhaps straight after startEngine\n\nSailthruMobile().enableAutoAnalytics([STMAutoAnalyticsSourceGoogleAnalytics, STMAutoAnalyticsSourceAdobe, STMAutoAnalyticsSourceMixpanel, STMAutoAnalyticsSourceLocalytics])", "language": "swift", "name": "iOS (Swift)" } ] } [/block] #### Methods captured ##### Google Analytics * `+ (id)createEventWithCategory:(NSString *)category action:(NSString *)action label:(NSString *)label value:(NSString *)value` We discard `category`, `label` and `value`, and log a Sailthru Mobile event with the `action` as the `name`. ##### Adobe Analytics * `+ (void)trackAction:(NSString *)action data:(id)data` We discard `data` and log a Sailthru Mobile event with the `action` as the `name`. ##### Mixpanel * `- (void)track:(NSString *)event properties:(NSString *)properties` We discard `properties` and log a Sailthru Mobile event with the `event` as the `name`. ##### Localytics * `- (void)tagEvent:(NSString *)eventName attributes:(NSDictionary *)attributes customerValueIncrease:(NSNumber *)customerValueIncrease;` We discard `attributes` and `customerValueIncrease`, and log a Sailthru Mobile event with the `eventName` as the `name`. ##### Flurry * `+ (NSInteger)logEvent:(NSString *)eventName withParameters:(NSDictionary *)parameters timed:(BOOL)timed` * `+ (NSInteger)logEvent:(NSString *)eventName timed:(BOOL)timed` We discard `eventName`, `parameters` and `timed`, and log a Sailthru Mobile event with the `eventName` as the `name`. ##### Amplitude * `- (void)logEvent:(NSString *)eventType withEventProperties:(NSDictionary *)eventProperties withApiProperties:(NSDictionary *)apiProperties withUserProperties:(NSDictionary *)userProperties withGroups:(NSDictionary *)groups withTimestamp:(NSNumber *)timestamp outOfSession:(BOOL)outOfSession` (Other event methods call this method) We discard most parameters, and log a Sailthru Mobile event with the `eventType` as the `name`. ### On Android For Auto-Analytics Tracking on Android, the `logEvent()` call now takes a source parameter for when forwarding events from other analytics frameworks to Sailthru Mobile. This allows you to target based on events you already track. ```java new SailthruMobile().logEvent("source", "myEvent"); ``` A selection of pre-written integrations have been [provided](https://github.com/carnivalmobile/carnival-android-sdk/blob/master/Analytics%20Integration/AnalyticIntegration.java), allowing you to just include one file, replace your event logging calls and then turn on or off the frameworks you want to use by commenting them out in the source file provided. [block:callout] { "type": "info", "body": "User Attributes don't record events that happen over time, and don't appear in graphs in the platform. They are simply metadata for a user. For recording events that happen over time, so you can target users by behavior, you should use our custom events feature.", "title": "User Attributes or Custom Events?" } [/block] [block:api-header] { "type": "basic", "title": "Tracking Location" } [/block] By default the Sailthru Mobile platform collects a last known IP location for each user. This can be used for coarse location segmentation and targeting with no extra development effort or permissions in your app. Depending on local laws, you may need to obtain the express consent from your app users in order to track IP location. You can disabled IP location by default if required: [block:code] { "codes": [ { "code": "// must be called before startEngine\n[[SailthruMobile new] setGeoIPTrackingDefault:NO];", "language": "objectivec", "name": "iOS (Objective-C)" }, { "code": "// must be called before startEngine\nSailthruMobile().setGeoIPTrackingDefault(false)", "language": "swift", "name": "iOS (Swift)" }, { "code": "// must be called before startEngine\nnew SailthruMobile().setGeoIpTrackingDefault(false);", "language": "java", "name": "Android (Java)" }, { "code": "// must be called before startEngine\nSailthruMobile().setGeoIpTrackingDefault(false)", "language": "kotlin", "name": "Android (Kotlin)" }, { "code": "// Set as RCTBridgeDelegate\nRNSailthruMobileBridge *sailthruMobileBridge = [[RNSailthruMobileBridge alloc] \n initWithJSCodeLocation: jsCodeLocation,\n appKey: SDK_KEY,\n \t\t pushAuthorizationOption: STMPushAuthorizationOptionFull,\n geoIpTrackingDefault: NO];", "language": "objectivec", "name": "React Native - iOS (Objective-C)" }, { "code": "// Set as RCTBridgeDelegate\nvar sailthruMobileBridge = RNSailthruMobileBridge(jsCodeLocation: jsCodeLocation,\n \t\t\t appKey: SDK_KEY,\n \t\t \t\t\t\t\t\t pushAuthorizationOption: .full,\n \t\t\t\t\t geoIpTrackingDefault: false)", "language": "swift", "name": "React Native - iOS (Swift)" }, { "code": "// Added to list of ReactPackages\nRNSailthruMobilePackage.Builder.createInstance(getApplicationContext(),\n \"ec27b1ca830238179747e2b812ad38bfcd4f9823\")\n .setGeoIPTrackingDefault(false)\n .build()", "language": "java", "name": "React Native - Android (Java)" } ] } [/block] You can also enable or disable it later for an existing device. [block:code] { "codes": [ { "code": "[[SailthruMobile new] setGeoIPTrackingEnabled:NO];\n\n// with result handler\n[[SailthruMobile new] setGeoIPTrackingEnabled:NO withResponse:^(NSError * _Nullable error) {\n // Check if error is non-nil for result\n}];", "language": "objectivec", "name": "iOS (Objective-C)" }, { "code": "SailthruMobile().setGeoIPTrackingEnabled(false)\n\n// with result handler\nSailthruMobile().setGeoIPTrackingEnabled(false) { (error : Error?) in\n // Check if error is non-nil for result\n}", "language": "swift", "name": "iOS (Swift)" }, { "code": "new SailthruMobile().setGeoIpTrackingEnabled(false);\n\n// with result handler\nnew SailthruMobile().setGeoIpTrackingEnabled(false, new SailthruMobile.SailthruMobileHandler<Void>() {\n @Override\n public void onSuccess(Void value) {\n\t\t\t// handle success\n }\n\n @Override\n public void onFailure(Error error) {\n\t\t\t// handle error\n }\n});", "language": "java", "name": "Android (Java)" }, { "code": "SailthruMobile().setGeoIpTrackingEnabled(false)\n\n// with result handler\nSailthruMobile().setGeoIpTrackingEnabled(false, object : SailthruMobileHandler<Void?> {\n override fun onSuccess(value: Void?) {\n // handle success\n }\n\n override fun onFailure(error: Error?) {\n // handle error\n }\n})", "language": "kotlin", "name": "Android (Kotlin)" }, { "code": "SailthruMobile.setGeoIPTrackingEnabled(false);\n\n// with result handler\nSailthruMobile.setGeoIPTrackingEnabled(false).then(result => {\n\t// Handle success\n}).catch(e => {\n\t// Handle error\n});", "language": "javascript", "name": "React Native (JavaScript)" } ] } [/block] In order to support more granular location, it is up to the app to decide and manage the accuracy of capturing location information, while considering the user's battery life. It's best practice to use only the accuracy you need for messaging (Block, City, State, Country). Location updates can then be passed through to Sailthru Mobile for segmentation. [block:code] { "codes": [ { "code": "// On iOS, using Objective-C\n[[SailthruMobile new] updateLocation:myLocation]; //Takes an instance of a CLLocation object as a argument.", "language": "objectivec", "name": "iOS (Objectve-C)" }, { "code": "// On iOS, using Swift\nSailthruMobile().updateLocation(myLocation) //Takes an instance of a CLLocation object as a argument.", "language": "swift", "name": "iOS (Swift)" }, { "code": "// On Android, using Java\nnew SailthruMobile().updateLocation(myLocation); //Takes an instance of a Location object as a argument.", "language": "java", "name": "Android (Java)" }, { "code": "// On Android, using Kotlin\nSailthruMobile().updateLocation(myLocation) //Takes an instance of a Location object as a argument.", "language": "kotlin", "name": "Android (Kotlin)" }, { "code": "// On React Native, using JavaScript\nSailthruMobile.updateLocation(lat, lon); //Takes lattitude and longitude as arguments", "language": "javascript", "name": "React Native (JavaScript)" } ] } [/block] Below are some short tutorials for collecting a user's location on Both iOS and Android: * [Location Tracking on iOS](doc:location-tracking-on-ios) * [Location Tracking on Android](https://developer.android.com/training/location/index.html) [block:api-header] { "title": "Getting the Device ID" } [/block] You can retrieve the device ID from the SDK if you would like to use it in your app. The device ID will be returned as a string in an asynchronous operation. [block:code] { "codes": [ { "code": "[[SailthruMobile new] deviceID:^(NSString * _Nullable deviceID, NSError * _Nullable error) {\n if(error) {\n // Handle error\n return;\n }\n // Handle deviceID\n}];", "language": "objectivec", "name": "iOS (Objective-C)" }, { "code": "SailthruMobile().deviceID { (deviceID, errorOrNil) in\n\t if let error = errorOrNil {\n\t\t // Handle error\n\t\t return\n\t\t}\n\t\t// Handle deviceID\n}", "language": "swift", "name": "iOS (Swift)" }, { "code": "new SailthruMobile().getDeviceId(new SailthruMobile.SailthruMobileHandler<String>() {\n @Override\n public void onSuccess(String deviceID) {\n // Handle deviceID\n }\n\n @Override\n public void onFailure(Error error) {\n // Handle error\n }\n});", "language": "java", "name": "Android (Java)" }, { "code": "SailthruMobile().getDeviceId(object : SailthruMobileHandler<String?> {\n override fun onSuccess(deviceID: String?) {\n // Handle deviceID\n }\n\n override fun onFailure(error: Error?) {\n // Handle error\n }\n})", "language": "kotlin", "name": "Android (Kotlin)" }, { "code": "SailthruMobile.getDeviceID().then(function(deviceID) {\n // Handle device ID\n}, function(error){\n // Handle error\n});", "language": "javascript", "name": "React Native (JavaScript)" } ] } [/block] [block:api-header] { "type": "basic", "title": "Clearing Device Data" } [/block] At times, such as a logging out flow or a user settings screen, you might want to clear device data. You're able to clear data for Events, Custom Attributes and Message Stream. Warning: By clearing events or custom attributes, the device may become eligible for an automated message triggered based on leaving an audience. Double check your set up before using this method. [block:code] { "codes": [ { "code": "[[SailthruMobile new] clearDeviceData:STMDeviceDataTypeEvents | STMDeviceDataTypeAttributes | STMDeviceDataTypeMessageStream withResponse:^(NSError * _Nullable error) { \n // Possible error here\n}];", "language": "objectivec", "name": "iOS (Objective-C)" }, { "code": " SailthruMobile().clear([.attributes, .messageStream, .events]) { (error) in\n // Possible error here\n }", "language": "swift", "name": "iOS (Swift)" }, { "code": "//SailthruMobile.ATTRIBUTES|SailthruMobile.MESSAGE_STREAM|SailthruMobile.EVENTS\nnew SailthruMobile().clearDevice(SailthruMobile.CLEAR_ALL, new SailthruMobile.SailthruMobileHandler<Void>() {\n @Override\n public void onSuccess(Void value) {\n\n }\n\n @Override\n public void onFailure(Error error) {\n\n }\n});", "language": "java", "name": "Android (Java)" }, { "code": "//SailthruMobile.ATTRIBUTES|SailthruMobile.MESSAGE_STREAM|SailthruMobile.EVENTS\nSailthruMobile().clearDevice(SailthruMobile.CLEAR_ALL, object : SailthruMobileHandler<Void?> {\n override fun onSuccess(value: Void?) {\n\n }\n\n override fun onFailure(error: Error?) {\n\n }\n})", "language": "kotlin", "name": "Android (Kotlin)" }, { "code": "// Clear one or more types. Specify one or more of these values.\nSailthruMobile.clearDevice(\n SailthruMobile.DeviceValues.Attributes | \n SailthruMobile.DeviceValues.MessageStream |\n SailthruMobile.DeviceValues.Events);\n\n// Clear all device data\nSailthruMobile.clearDevice(SailthruMobile.DeviceValues.ClearAll);", "language": "javascript", "name": "React Native (JavaScript)" } ] } [/block]