Skip to content
VU Blog

Mobile AEP SDK and Adobe Target Server-Side Implementation

Adobe, AEP, AEP SDK, Mobile, Server-side, Proxy4 min read

Mobile AEP SDK and Adobe Target Server-Side Implementation

Intro

During my consulting practice, I am often asked to share best practices on how Adobe Target can work outside of mobile AEP SDK in the apps. The reason is that some enterprise apps are architectured in a way where content is fully or partially driven by a web server API - the external server that delivers content. Therefore, implementing AEP SDK client-side in the app is not an option, even though Adobe recommends client-side implementaiton as a best practice. To implement Target server-side, we need to let SDK generate and pass Target-related data into an external API service.

This document describes how Adobe Target can operate in the mobile app where Target calls are re-routed to a server-side API service responsible for communicating with Target edge network.

Technical requirements:

The following technical requirements must be met to leverage Target solution via server-side implementation.

  1. AEP SDK
    • Mobile AEP SDK must be initialized in the app and have Adobe Target and Analytics solutions enabled.
  2. Target Delivery API
    • The web server must route all Target calls to the Delivery API (http://developers.adobetarget.com/api/delivery-api/)

Note that legacy Target API does not support A4T integration so it cannot be used. Use the Delivery API only.

Extracting Identifiers for Target from AEP SDK

The key to this implementation is to extract Target functionality from the AEP SDK running client-side into an external server-side API service, or Proxy service. Because this is not a recommended approach, we must be careful about what information is being passed to the Proxy server. SDK generates all necessary data about the visitor to correctly pass it to Target and other Adobe solutions. Passing incorrect data will result in product malfunction.

Here is a list of identifiers required for all Target calls:

  1. Your Customer ID with authenticated state, if known
  2. ECID
  3. TNT ID
  4. Session ID
  5. Edge Host

Getting Customer ID

Your organization Customer ID with an authenticated state, if known, is superior to any other ID such as ECID and TNT ID. However, it is only known when visitor logs in to authenticate. Get and pass it to the Proxy call every time when it is known together with the user authenticated state.

IMPORTANT: if multiple Customer IDs are set, Target only supports the first authenticated ID on the list.

1Identity.getIdentifiers { customerIds, error in
2 if let firstCustomerId = customerIds.first {
3 print("Visitor ID : \(firstCustomerId)")
4 }
5}

Getting ECID or Experience Cloud ID

Known as ECID, Experience Cloud ID or formerly Marketing Cloud ID, this identifier is used across multiple Adobe solutions and is considered the most important ID when your Customer ID is unknown. Target call without ECID may result in unexpected behavior. Getting ECID can be achieved using this method:

1Identity.getExperienceCloudId { (ecid, error) in
2 print("ECID is: \(ecid)")
3}

Getting TNT ID

TNT ID is the key identifier for Target. Passing it is required. However, when ECID is available, and in most cases it will be, the TNT ID would only be an alias ID. Note, that the very first call to Target may omit TNT ID, in which case Target will generate a new TNT ID and send it back in response. This new TNT ID will need to be used for all future Target calls. AEP SDK handles this automatically.

TNT ID also contains mbox edge number, which is important for routing to the nearest edge location.

1Target.getTntId({ tntId, error in
2 print("TNT ID is \(tntId)")
3})

Getting Session ID

Session ID is required for constructing a Target request. Passing inconsistent session ID would result in duplicate visitor sessions and, in return, incorrectly personalized experience.

1Target.getSessionId { (sessionId, err) in
2 print("Session ID is \(sessionId)")
3}

Extracting Mbox Edge Host

Mbox edge host allows routing Target call to the nearest edge location. It looks like mboxedgeNN.tt.omtrdc.net where NN is the edge number.

The very first request to Target Delivery API has the following URL where mbox host is replaced by client code:

https://<CLIENT_CODE>.tt.omtrdc.net/rest/v1/delivery/

After the initial Target response, SDK starts using the nearest mbox edge to route new calls to. It will then look like below.

https://mboxedge34.tt.omtrdc.net/rest/v1/delivery/

mboxedge34 is now the nearest mbox edge host. Mbox host can be retrieved from TNT ID. For example, TNT ID "B70FF281-E87D-4FAC-9D5E-E84E53242D9C.34_0" contains 34 for mbox edge hint that will become mboxedge34.

Extract TNT ID and parse it to get your edge hint and pass it to the Proxy call. Mbox edge must always be consistent when known or, otherwise, connecting to a different edge would result in duplicate visitor profile and inconsistant personalized experience.

If mbox edge host is unknown, pass client code instead.

Constructing Target Request with Delivery API

Adobe Target Delivery API is to be used for this server-side implementation. The Delivery API also supports A4T integration so Target Activities can report to Analytics.

Target has 2 content delivery methods: execute and prefetch. The server-side implementation works best with the execute method. Here is an example of the app-generated Target call specific to mobile environment:

1curl -H 'Host: mboxedge34.tt.omtrdc.net' -H 'accept: */*' -H 'content-type: application/json' -H 'user-agent: Mozilla/5.0 (iPhone; CPU OS 14_5_1 like Mac OS X; en_US)' -H 'accept-language: en-us' --data-binary '{
2 "execute" : {
3 "mboxes" : [
4 {
5 "parameters" : {
6 "a.HourOfDay" : "12",
7 "a.CarrierName" : "AT&T",
8 "a.CrashEvent" : "CrashEvent",
9 "a.DeviceName" : "iPhone10,6",
10 "previousosversion" : "iOS 14.5.1",
11 "a.Resolution" : "1125x2436",
12 "a.locale" : "en-US",
13 "mycustomdata" : "ASUDYTF67WEUYSGYDVWE6TFWES",
14 "a.AppID" : "AEP Demo 1.0 (1)",
15 "a.RunMode" : "Application",
16 "a.DaysSinceFirstUse" : "243",
17 "previousappid" : "AEP Demo 1.0 (1)",
18 "type" : "gold",
19 "a.DaysSinceLastUse" : "0",
20 "a.OSVersion" : "iOS 14.5.1",
21 "a.LaunchEvent" : "LaunchEvent",
22 "page" : "GlobalPage",
23 "a.ignoredSessionLength" : "-1623862502",
24 "a.DayOfWeek" : "4",
25 "a.Launches" : "3"
26 },
27 "profileParameters" : {
28 "extraPrefetchProfileKey" : "extraPrefetchProfileValue"
29 },
30 "name" : "sdk-demo-4",
31 "index" : 0
32 }
33 ]
34 },
35 "experienceCloud" : {
36 "audienceManager" : {
37 "blob" : "j8Odv6LonN4r3an7LhD3WZrU1bUpAkFkkiY1ncBR96t2PTI",
38 "locationHint" : "7"
39 },
40 "analytics" : {
41 "logging" : "client_side"
42 }
43 },
44 "id" : {
45 "tntId" : "74BEFBA7-819A-4D99-9D6A-F64011FB2654.34_0",
46 "marketingCloudVisitorId" : "10238278281262063009146396392721108540",
47 "customerIds" : [
48 {
49 "id" : "146396392721108345",
50 "authenticatedState" : "authenticated",
51 "integrationCode" : "guid"
52 },
53 {
54 "id" : "827828126206300914",
55 "authenticatedState" : "authenticated",
56 "integrationCode" : "hhid"
57 }
58 ]
59 },
60 "property" : {
61 "token" : "4b962579-c709-d8e0-2752-c2ef3c9ed3ea"
62 },
63 "context" : {
64 "screen" : {
65 "colorDepth" : 32,
66 "height" : 2436,
67 "width" : 1125,
68 "orientation" : "portrait"
69 },
70 "mobilePlatform" : {
71 "deviceName" : "iPhone10,6",
72 "deviceType" : "phone",
73 "platformType" : "ios"
74 },
75 "timeOffsetInMinutes" : 27064379.699999999,
76 "application" : {
77 "id" : "com.vues.aep-demo",
78 "name" : "AEP Demo",
79 "version" : "1"
80 },
81 "channel" : "mobile",
82 "userAgent" : "Mozilla\/5.0 (iPhone; CPU OS 14_5_1 like Mac OS X; en_US)"
83 },
84 "environmentId" : 5062
85}' --compressed 'https://mboxedge34.tt.omtrdc.net/rest/v1/delivery/?client=adobeinternalags300&sessionId=74BEFBA7-819A-4D99-9D6A-F64011FB2654'

Here is Response for the above Request.

1{
2 "status": 200,
3 "requestId": "0ad6de40-f953-46e9-83f4-9e484c5cbc09",
4 "client": "adobeinternalags300",
5 "id": {
6 "tntId": "74BEFBA7-819A-4D99-9D6A-F64011FB2654.34_0",
7 "marketingCloudVisitorId": "10238278281262063009146396392721108540"
8 },
9 "edgeHost": "mboxedge34.tt.omtrdc.net",
10 "execute": {
11 "mboxes": [{
12 "index": 0,
13 "name": "sdk-demo-4",
14 "state": "cWPpH5/slkSPMe...ZNNk8Ba6QQPVmUUGyVdI=",
15 "options": [{
16 "content": {
17 "exp": "B"
18 },
19 "type": "json",
20 "eventToken": "pIe/Ag35pmQBL7O...rWQTvE54PwSXpSSS2Q==",
21 "responseTokens": {
22 "experience.id": "1",
23 "offer.name": "/app_prod_dealsscreengrossordersa4t92721aacopy/experiences/1/pages/0/zones/0/1634149051932",
24 "activity.name": "HP - Banner - PROD",
25 "activity.id": "590517",
26 "option.name": "Offer3",
27 "experience.name": "Experience B",
28 "option.id": "3",
29 "offer.id": "736344"
30 },
31 "sourceType": "target"
32 }],
33 "analytics": {
34 "payload": {
35 "pe": "tnt",
36 "tnta": "590517:1:0|2,590517:1:0|1"
37 }
38 }
39 }]
40 }
41}

Adobe mobile AEP SDK passes a lot of useful data to Target as seen above. Request parameters contain lifecycle events prefixed with "a.". This data is not available for extraction so some server-side functionality may be limited when re-routing Target calls to a Proxy.

See Lifecycle metrics for awareness.

This Target Request may be the bare minimum template for HTTP Request to Target Delivery API:

1curl -H 'Host: mboxedge34.tt.omtrdc.net' -H 'accept: */*' -H 'content-type: application/json' -H 'user-agent: Mozilla/5.0 (iPhone; CPU OS 14_5_1 like Mac OS X; en_US)' -H 'accept-language: en-us' --data-binary '{
2 "execute" : {
3 "mboxes" : [
4 {
5 "parameters" : {
6 "<ANY_CUSTOM_PARAM>" : "<ANY_CUSTOM_VALUE>"
7 }
8 "name" : "<ANY_LOCATION_NAME>",
9 "index" : 0
10 }
11 ]
12 },
13 "experienceCloud" : {
14 "analytics" : {
15 "logging" : "client_side"
16 }
17 },
18 "id" : {
19 "tntId" : "<TNT_ID_EXTRACTED_FROM_SDK>",
20 "marketingCloudVisitorId" : "ECID_EXTRACTED_FROM_SDK",
21 "customerIds" : [
22 {
23 "id" : "<AUTHENTICATED_CUSTOMER_ID>",
24 "authenticatedState" : "authenticated",
25 "integrationCode" : "<CUSTOMER_ID_CODE>"
26 }
27 ]
28 },
29 "property" : {
30 "token" : "<PROPERTY_TOKEN_IF_KNOWN>"
31 },
32 "context" : {
33 "channel" : "mobile"
34 },
35 "environmentId" : <TARGET_ENVIRONMENT_ID>
36}' --compressed 'https://<CLIENT_CODE_OR_MBOX_HOST>.tt.omtrdc.net/rest/v1/delivery/?client=<CLIENT_CODE>&sessionId=<SESSION_ID>'

In the next sections we will review how to:

  1. Send personalized experiences from HTTP Response and
  2. Send A4T call to Analytics

Passing Target Response to the App

After sending the Target HTTP Request as shown above, the Response may contain personalized experiences that can be retrieved from this path:

1execute -> mboxes -> [<ARRAY_INDEX>] -> options -> content

Content will contain the Target Offer, or experience, which will need to be sent back and applied to the app's view as needed. It is developer's responsibility to parse, extract and apply the experience in the app from Target Response.

Your Target experience may be any object: JSON, HTML, or text. JSON is more common for mobile apps. Often, developers use feature flag approach where Target experience carries a flag with what UI change is required. It may also contain the entire meaningful component that app will consume as expected.

Analytics A4T Call with Data Insertion API

If Adobe customer is using A4T (Analytics for Target) to report Target Activities to Analytics, it is developer's responsibility to extract Analytics Payload from Target Response and send it to Analytics using Data Insertion API.

Note that A4T calls are service calls and do not count towards billable quota.

1https://<DATA_COLLECTION_HOST>.sc.omtrdc.net/b/ss/<RSID>/0/<CODEVERSION>?pe=tnt&tnta=<ANALYTICS_PAYLOAD_FROM_TARGET_RESPONSE>&mid=<ECID>&vid=<VID>&aid=<AID>

Sample A4T Data Insertion HTTP Get Call

1https://demo.sc.omtrdc.net/b/ss/myCustomRsid/0/MOBILE-1.0?pe=tnt&tnta=285408:0:0|2&mid=2304820394812039

References and Useful Links

https://developers.adobetarget.com/api/delivery-api/ https://developer.adobe.com/target/implement/server-side/sdk-guides/integration-with-experience-cloud/a4t-reporting/ https://developer.adobe.com/target/implement/server-side/sdk-guides/integration-with-experience-cloud/a4t-reporting/#query-string-parameters-and-variables https://github.com/AdobeDocs/analytics-1.4-apis/blob/master/docs/data-insertion-api/sample_code/r_sample_http_get.md https://github.com/AdobeDocs/analytics-1.4-apis/blob/master/docs/data-insertion-api/reference/r_supported_tags.md https://www.softcrylic.com/blogs/adobe-analytics-for-target-a4t-a-look-under-the-hood/

© 2023 by VU Blog. All rights reserved.
Created by Vadym