{"_id":"5b720760c44b7600034b7a02","project":"55e67aaa9cc7c62b00c4a1ea","version":{"_id":"5b720760c44b7600034b7a08","project":"55e67aaa9cc7c62b00c4a1ea","__v":0,"forked_from":"5b1f2cbdfd653400031d8d9f","createdAt":"2015-09-02T04:27:23.612Z","releaseDate":"2015-09-02T04:27:23.612Z","categories":["5b720760c44b7600034b79a7","5b720760c44b7600034b79a8","5b720760c44b7600034b79a9","5b720760c44b7600034b79aa","5b720760c44b7600034b79ab","561c61b4ad272c0d00a892df","586c014c0abf1d0f000d04d4","58991d2ad207df0f0002186b","5b720760c44b7600034b79ac","5b720760c44b7600034b79ad","5af0fe494ca2730003cbc98a","5af0fe55ec80af0003804ca2"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"API V6","version_clean":"1.4.0","version":"1.4"},"category":{"_id":"5b720760c44b7600034b79ac","project":"55e67aaa9cc7c62b00c4a1ea","__v":0,"version":"5b720760c44b7600034b7a08","sync":{"url":"","isSync":false},"reference":false,"createdAt":"2017-02-08T21:31:11.878Z","from_sync":false,"order":7,"slug":"advanced-techniques","title":"Advanced Techniques"},"user":"587fed3d9efedf3b00200366","githubsync":"","__v":0,"parentDoc":null,"updates":[],"next":{"pages":[],"description":""},"createdAt":"2018-03-14T01:45:58.524Z","link_external":false,"link_url":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","apiSetting":null,"auth":"required","params":[],"url":""},"isReference":false,"order":7,"body":"You can use Sailthru's Site Personalization Manager (SPM) to send personalized content to your users across channels - Onsite, Email and Mobile. \n\nOn mobile this is dead simple, and similar to implementing our JavaScript Client Library in Custom Mode.\n\nThis guide assumes that you've set up SPM on the web.\n\n# Tracking Content Metrics\n## Content Metrics overview\nWhen providing personalized content, tracking a user's interests is of great importance. Interest tracking allows you to recommend items or articles to the user that they actually care about, making them more likely to convert through your recommended content. SPM provides three different types of tracking metrics:\n- A __pageview__ is an indication that a user has seen a given item of content's detail view - for example, a page for a certain product in an online store, or a full news article in a news site. \n- An __impression__ is a reasonable assumption that a user has seen a given piece of content - maybe they've scrolled past it in a list view, or seen it in a \"Recommended\" panel on another content item. \n- A __click__ is exactly what it sounds like: it means that a user has clicked - or in this case tapped -  on a given piece of content to learn more. This usually, but not always, means that a user will now transition to that content's detail view.\n\n## Implementing Content Metrics\n\n### Tracking Pageviews\nSailthru's `trackPageview` method should be passed a URL corresponding to the web URL of the content being viewed, as well as an array of tags. If the tags array is empty or null, Sailthru will use any tags for this page stored in your content library - otherwise, those stored tags will be overridden by any passed to `trackPageview`.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"ArrayList<String> tags = new ArrayList(Arrays.asList(\\\"blazer\\\", \\\"beige\\\", \\\"tan\\\"));\\nURI contentUrl = URI.create(\\\"https://varickandvandam.com/products/1153128\\\");\\n\\nCarnival.trackPageview(contentUrl, tags, new Carnival.TrackHandler() {\\n  :::at:::Override\\n  public void onSuccess() {\\n\\t\\t// We're good\\n  }\\n\\n  @Override\\n  public void onFailure(Error error) {\\n\\t\\t// Handle errors here\\n  }\\n});\\n\\n// Alternatively, if we don't mind too much if the track request fails, use a null handler:\\nCarnival.trackPageview(contentUrl, tags, null)\",\n      \"language\": \"java\",\n      \"name\": \"Android (Java)\"\n    },\n    {\n      \"code\": \"let tags = [\\\"blazer\\\", \\\"beige\\\", \\\"tan\\\"]\\nlet contentUrl = URL(string: \\\"https://varickandvandam.com/products/1153128\\\")\\n\\nCarnival.trackPageview(withUrl: contentUrl, andTags: tags) { (errorOrNil) in\\n    if let error = errorOrnil {\\n        print(error)\\n        return\\n    }\\n    \\n    // Track success! ๐Ÿ™Œ\\n}\\n\\n// Alternatively, if we don't mind too much if the track request fails, just omit the block:\\nCarnival.trackPageview(withUrl: contentUrl, andTags: tags)\",\n      \"language\": \"swift\",\n      \"name\": \"iOS (Swift)\"\n    },\n    {\n      \"code\": \"NSArray<NSString*> *tags = @[@\\\"blazer\\\", @\\\"beige\\\", @\\\"tan\\\"];\\nNSURL *contentUrl = [NSURL URLWithString:@\\\"https://varickandvandam.com/products/1153128\\\"];\\n\\n[Carnival trackPageviewWithUrl: contentUrl, andTags: tags, andResponse: ^(NSError *error) {\\n  if (error) {\\n\\t\\t// Handle error case\\n  } else {\\n    // Things went right, hooray!\\n  }\\n}];\\n\\n// Alternatively, if we don't mind too much if the track request fails, use a nil block:\\n[Carnival trackPageviewWithUrl: contentUrl, andTags: tags, andResponse: nil]\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (ObjC)\"\n    }\n  ]\n}\n[/block]\nWe recommend tracking pageviews as views within your app are being initialized. For example, on Android, you might call `trackPageview` in a Fragment's `onCreateView` method, whereas on iOS you might place it in a ViewController's `viewDidAppear` method.\n\n### Tracking Impressions\nAn impression should be tracked when a section of recommended content is seen by a user. Sailthru's `trackImpression` method takes a SPM Section ID as its first argument, and a list of URLs corresponding to the URLs of the items in the section.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"ArrayList<URI> urls = new ArrayList(Arrays.asList(\\n  URI.create(\\\"https://varickandvandam.com/products/1153128\\\"),\\n  URI.create(\\\"https://varickandvandam.com/products/1098230\\\"), \\n\\tURI.create(\\\"https://varickandvandam.com/products/1078590\\\")\\n));\\nString sectionID = \\\"a very real section ID\\\";\\n\\nCarnival.trackImpression(sectionID, urls, new Carnival.TrackHandler() {\\n  @Override\\n  public void onSuccess() {\\n\\t\\t// We're good\\n  }\\n\\n  @Override\\n  public void onFailure(Error error) {\\n\\t\\t// Handle errors here\\n  }\\n});\\n\\n// Alternatively, if we don't mind too much if the track request fails, use a null handler:\\nCarnival.trackImpression(sectionID, urls, null)\",\n      \"language\": \"java\",\n      \"name\": \"Android (Java)\"\n    },\n    {\n      \"code\": \"let urls = [\\n  URL(\\\"https://varickandvandam.com/products/1153128\\\"),\\n  URL(\\\"https://varickandvandam.com/products/1098230\\\"), \\n\\tURL(\\\"https://varickandvandam.com/products/1078590\\\")\\n]\\nlet sectionID = \\\"a very real section ID\\\"\\n\\nCarnival.trackImpression(withSection: sectionID, andUrls: urls) { (errorOrNil) in\\n    if let error = errorOrnil {\\n        print(error)\\n        return\\n    }\\n    \\n    // Track success! ๐Ÿ™Œ\\n}\\n\\n// Alternatively, if we don't mind too much if the track request fails, just omit the block:\\nCarnival.trackImpression(withSection: sectionID, andUrls: urls)\",\n      \"language\": \"swift\",\n      \"name\": \"iOS (Swift)\"\n    },\n    {\n      \"code\": \"NSArray<NSURL*> *urls = @[\\n  [NSURL URLWithString:@\\\"https://varickandvandam.com/products/1153128\\\"],\\n  [NSURL URLWithString:@\\\"https://varickandvandam.com/products/1098230\\\"],\\n  [NSURL URLWithString:@\\\"https://varickandvandam.com/products/1078590\\\"]\\n];\\nNSString *sectionID = @\\\"A very real section ID\\\";\\n\\n[Carnival trackImpressionWithSession: sectionID, andUrls: urls, andResponse: ^(NSError *error) {\\n  if (error) {\\n\\t\\t// Handle error case\\n  } else {\\n    // Things went right, hooray!\\n  }\\n}];\\n\\n// Alternatively, if we don't mind too much if the track request fails, use a nil block:\\n[Carnival trackImpressionWithSession: sectionID, andUrls: urls, andResponse: nil]\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (ObjC)\"\n    }\n  ]\n}\n[/block]\nWe recommend that you call `trackImpression` as a recommendation section enters the user's viewport on their device. On Android, you might do this by attaching an [OnChildAttachStateChangeListener](https://developer.android.com/reference/android/support/v7/widget/RecyclerView.OnChildAttachStateChangeListener.html) to a RecyclerView, and placing a call to `trackImpression` in the body of its `onChildViewAttachedToWindow` method. On iOS, you might consider calling `trackImpression` in the `UITableViewDelegate` method [tableView:willDisplayCell](https://developer.apple.com/documentation/uikit/uitableviewdelegate/1614883-tableview).\n\n### Tracking Clicks\nA click should be tracked when a user clicks on an item present in a section of recommendations, passing the section ID as the first argument, and the URL of the item being navigated to as the second argument. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"URI url = URI.create(\\\"https://varickandvandam.com/products/1078590\\\");\\nString sectionID = \\\"a very real section ID\\\";\\n\\nCarnival.trackClick(sectionID, url, new Carnival.TrackHandler() {\\n  @Override\\n  public void onSuccess() {\\n\\t\\t// We're good\\n  }\\n\\n  @Override\\n  public void onFailure(Error error) {\\n\\t\\t// Handle errors here\\n  }\\n});\\n\\n// Alternatively, if we don't mind too much if the track request fails, use a null handler:\\nCarnival.trackImpression(sectionID, url, null)\",\n      \"language\": \"java\",\n      \"name\": \"Android (Java)\"\n    },\n    {\n      \"code\": \"let url = URL(\\\"https://varickandvandam.com/products/1153128\\\")\\nlet sectionID = \\\"a very real section ID\\\"\\n\\nCarnival.trackClick(withSection: sectionID, andUrl: url) { (errorOrNil) in\\n    if let error = errorOrnil {\\n        print(error)\\n        return\\n    }\\n    \\n    // Track success! ๐Ÿ™Œ\\n}\\n\\n// Alternatively, if we don't mind too much if the track request fails, just omit the block:\\nCarnival.trackClick(withSection: sectionID, andUrl: url)\",\n      \"language\": \"swift\",\n      \"name\": \"iOS (Swift)\"\n    },\n    {\n      \"code\": \"NSURL *url = [NSURL URLWithString:@\\\"https://varickandvandam.com/products/1153128\\\"];\\nNSString *sectionID = @\\\"A very real section ID\\\";\\n\\n[Carnival trackClickWithSession: sectionID, andUrl: url, andResponse: ^(NSError *error) {\\n  if (error) {\\n\\t\\t// Handle error case\\n  } else {\\n    // Things went right, hooray!\\n  }\\n}];\\n\\n// Alternatively, if we don't mind too much if the track request fails, use a nil block:\\n[Carnival trackClickWithSession: sectionID, andUrl: url, andResponse: nil]\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (ObjC)\"\n    }\n  ]\n}\n[/block]","excerpt":"","slug":"using-spm-on-mobile","type":"basic","title":"Using SPM on Mobile"}

Using SPM on Mobile


You can use Sailthru's Site Personalization Manager (SPM) to send personalized content to your users across channels - Onsite, Email and Mobile. On mobile this is dead simple, and similar to implementing our JavaScript Client Library in Custom Mode. This guide assumes that you've set up SPM on the web. # Tracking Content Metrics ## Content Metrics overview When providing personalized content, tracking a user's interests is of great importance. Interest tracking allows you to recommend items or articles to the user that they actually care about, making them more likely to convert through your recommended content. SPM provides three different types of tracking metrics: - A __pageview__ is an indication that a user has seen a given item of content's detail view - for example, a page for a certain product in an online store, or a full news article in a news site. - An __impression__ is a reasonable assumption that a user has seen a given piece of content - maybe they've scrolled past it in a list view, or seen it in a "Recommended" panel on another content item. - A __click__ is exactly what it sounds like: it means that a user has clicked - or in this case tapped - on a given piece of content to learn more. This usually, but not always, means that a user will now transition to that content's detail view. ## Implementing Content Metrics ### Tracking Pageviews Sailthru's `trackPageview` method should be passed a URL corresponding to the web URL of the content being viewed, as well as an array of tags. If the tags array is empty or null, Sailthru will use any tags for this page stored in your content library - otherwise, those stored tags will be overridden by any passed to `trackPageview`. [block:code] { "codes": [ { "code": "ArrayList<String> tags = new ArrayList(Arrays.asList(\"blazer\", \"beige\", \"tan\"));\nURI contentUrl = URI.create(\"https://varickandvandam.com/products/1153128\");\n\nCarnival.trackPageview(contentUrl, tags, new Carnival.TrackHandler() {\n @Override\n public void onSuccess() {\n\t\t// We're good\n }\n\n @Override\n public void onFailure(Error error) {\n\t\t// Handle errors here\n }\n});\n\n// Alternatively, if we don't mind too much if the track request fails, use a null handler:\nCarnival.trackPageview(contentUrl, tags, null)", "language": "java", "name": "Android (Java)" }, { "code": "let tags = [\"blazer\", \"beige\", \"tan\"]\nlet contentUrl = URL(string: \"https://varickandvandam.com/products/1153128\")\n\nCarnival.trackPageview(withUrl: contentUrl, andTags: tags) { (errorOrNil) in\n if let error = errorOrnil {\n print(error)\n return\n }\n \n // Track success! ๐Ÿ™Œ\n}\n\n// Alternatively, if we don't mind too much if the track request fails, just omit the block:\nCarnival.trackPageview(withUrl: contentUrl, andTags: tags)", "language": "swift", "name": "iOS (Swift)" }, { "code": "NSArray<NSString*> *tags = @[@\"blazer\", @\"beige\", @\"tan\"];\nNSURL *contentUrl = [NSURL URLWithString:@\"https://varickandvandam.com/products/1153128\"];\n\n[Carnival trackPageviewWithUrl: contentUrl, andTags: tags, andResponse: ^(NSError *error) {\n if (error) {\n\t\t// Handle error case\n } else {\n // Things went right, hooray!\n }\n}];\n\n// Alternatively, if we don't mind too much if the track request fails, use a nil block:\n[Carnival trackPageviewWithUrl: contentUrl, andTags: tags, andResponse: nil]", "language": "objectivec", "name": "iOS (ObjC)" } ] } [/block] We recommend tracking pageviews as views within your app are being initialized. For example, on Android, you might call `trackPageview` in a Fragment's `onCreateView` method, whereas on iOS you might place it in a ViewController's `viewDidAppear` method. ### Tracking Impressions An impression should be tracked when a section of recommended content is seen by a user. Sailthru's `trackImpression` method takes a SPM Section ID as its first argument, and a list of URLs corresponding to the URLs of the items in the section. [block:code] { "codes": [ { "code": "ArrayList<URI> urls = new ArrayList(Arrays.asList(\n URI.create(\"https://varickandvandam.com/products/1153128\"),\n URI.create(\"https://varickandvandam.com/products/1098230\"), \n\tURI.create(\"https://varickandvandam.com/products/1078590\")\n));\nString sectionID = \"a very real section ID\";\n\nCarnival.trackImpression(sectionID, urls, new Carnival.TrackHandler() {\n @Override\n public void onSuccess() {\n\t\t// We're good\n }\n\n @Override\n public void onFailure(Error error) {\n\t\t// Handle errors here\n }\n});\n\n// Alternatively, if we don't mind too much if the track request fails, use a null handler:\nCarnival.trackImpression(sectionID, urls, null)", "language": "java", "name": "Android (Java)" }, { "code": "let urls = [\n URL(\"https://varickandvandam.com/products/1153128\"),\n URL(\"https://varickandvandam.com/products/1098230\"), \n\tURL(\"https://varickandvandam.com/products/1078590\")\n]\nlet sectionID = \"a very real section ID\"\n\nCarnival.trackImpression(withSection: sectionID, andUrls: urls) { (errorOrNil) in\n if let error = errorOrnil {\n print(error)\n return\n }\n \n // Track success! ๐Ÿ™Œ\n}\n\n// Alternatively, if we don't mind too much if the track request fails, just omit the block:\nCarnival.trackImpression(withSection: sectionID, andUrls: urls)", "language": "swift", "name": "iOS (Swift)" }, { "code": "NSArray<NSURL*> *urls = @[\n [NSURL URLWithString:@\"https://varickandvandam.com/products/1153128\"],\n [NSURL URLWithString:@\"https://varickandvandam.com/products/1098230\"],\n [NSURL URLWithString:@\"https://varickandvandam.com/products/1078590\"]\n];\nNSString *sectionID = @\"A very real section ID\";\n\n[Carnival trackImpressionWithSession: sectionID, andUrls: urls, andResponse: ^(NSError *error) {\n if (error) {\n\t\t// Handle error case\n } else {\n // Things went right, hooray!\n }\n}];\n\n// Alternatively, if we don't mind too much if the track request fails, use a nil block:\n[Carnival trackImpressionWithSession: sectionID, andUrls: urls, andResponse: nil]", "language": "objectivec", "name": "iOS (ObjC)" } ] } [/block] We recommend that you call `trackImpression` as a recommendation section enters the user's viewport on their device. On Android, you might do this by attaching an [OnChildAttachStateChangeListener](https://developer.android.com/reference/android/support/v7/widget/RecyclerView.OnChildAttachStateChangeListener.html) to a RecyclerView, and placing a call to `trackImpression` in the body of its `onChildViewAttachedToWindow` method. On iOS, you might consider calling `trackImpression` in the `UITableViewDelegate` method [tableView:willDisplayCell](https://developer.apple.com/documentation/uikit/uitableviewdelegate/1614883-tableview). ### Tracking Clicks A click should be tracked when a user clicks on an item present in a section of recommendations, passing the section ID as the first argument, and the URL of the item being navigated to as the second argument. [block:code] { "codes": [ { "code": "URI url = URI.create(\"https://varickandvandam.com/products/1078590\");\nString sectionID = \"a very real section ID\";\n\nCarnival.trackClick(sectionID, url, new Carnival.TrackHandler() {\n @Override\n public void onSuccess() {\n\t\t// We're good\n }\n\n @Override\n public void onFailure(Error error) {\n\t\t// Handle errors here\n }\n});\n\n// Alternatively, if we don't mind too much if the track request fails, use a null handler:\nCarnival.trackImpression(sectionID, url, null)", "language": "java", "name": "Android (Java)" }, { "code": "let url = URL(\"https://varickandvandam.com/products/1153128\")\nlet sectionID = \"a very real section ID\"\n\nCarnival.trackClick(withSection: sectionID, andUrl: url) { (errorOrNil) in\n if let error = errorOrnil {\n print(error)\n return\n }\n \n // Track success! ๐Ÿ™Œ\n}\n\n// Alternatively, if we don't mind too much if the track request fails, just omit the block:\nCarnival.trackClick(withSection: sectionID, andUrl: url)", "language": "swift", "name": "iOS (Swift)" }, { "code": "NSURL *url = [NSURL URLWithString:@\"https://varickandvandam.com/products/1153128\"];\nNSString *sectionID = @\"A very real section ID\";\n\n[Carnival trackClickWithSession: sectionID, andUrl: url, andResponse: ^(NSError *error) {\n if (error) {\n\t\t// Handle error case\n } else {\n // Things went right, hooray!\n }\n}];\n\n// Alternatively, if we don't mind too much if the track request fails, use a nil block:\n[Carnival trackClickWithSession: sectionID, andUrl: url, andResponse: nil]", "language": "objectivec", "name": "iOS (ObjC)" } ] } [/block]