Skip to content
VU Blog

Web SDK Target Migration Quickstart

Adobe, AEP, Experience Platform, Data Collection, Web SDK, Target, at.js, alloy.js5 min read

Web SDK and Adobe Target Migration Quickstart

This guide assumes familiarity with:

  • Adobe Target
  • HTML and JavaScript

This guide requires access to the following Adobe solutions:

  • Experience Platform
  • Data Collection
  • Target

Web SDK Overview

Web SDK Diagram

  1. The device loads the Platform Web SDK. The Platform Web SDK sends a request to the edge network with XDM data, the Datastreams Environment ID, passed-in parameters, and the Customer ID (optional). Page (or containers) is pre-hidden.
  2. The edge network sends the request to the edge services to enrich it with the Visitor ID, consent, and other visitor context info, such as geolocation and device-friendly names.
  3. The edge network sends the enriched personalization request to the Target edge with the Visitor ID and passed-in parameters.
  4. Profile scripts execute and then feed into Target profile storage. Profile storage fetches segments from the Audience Library (for example, segments shared from Adobe Analytics, Adobe Audience Manager, the Adobe Experience Platform).
  5. Based on URL request parameters and profile data, Target determines which activities and experiences to display for the visitor for the current page view and for future prefetched views. Target then sends this back to the edge network.
  6. Steps:
    • a. The edge network sends the personalization response back to the page, optionally including profile values for additional personalization. Personalized content on the current page is revealed as quickly as possible without flicker of default content.
    • b. Personalized content for views that are shown as a result of user actions in a Single Page Application (SPA) is cached so it can be instantly applied without an additional server call when the views are triggered.
    • c. The edge network sends the Visitor ID and other values in cookies, such as consent, Session ID, identity, cookie check, personalization, and so forth.
  7. The edge network forwards Analytics for Target (A4T) details (activity, experience, and conversion metadata) to the Analytics edge.

See documentation reference

Product Configuration

Configure XDM Schema

Experience Data Model (XDM) schemas are the building blocks, principles, and best practices for composing schemas in Adobe Experience Platform.

Platform Web SDK uses your schema to standardize your web event data, send it to the Platform Edge Network, and ultimately forward the data to any Experience Cloud applications configured in the datastream. This step is critical as it defines a standard data model required for ingesting customer experience data into Experience Platform and enables downstream services and applications built on these standards.

:point_right: Checklist

For Target, add the recommended pre-defined field groups for web data collection:

  1. AEP Web SDK ExperienceEvent
  2. Consumer Experience Event

See documentation reference

Update Audiences and Profile Scripts with XDM Path

When defining your Schema, your data will be passed in the xdm object of payload and visible to all configured Adobe solution. Alternatively, you can pass data to Target only via data object. If Target custom parameters are moved to the XDM Schema, the path in the Audience builder will differ and needs to be updated for Audiences and Profile Scripts. The XDM is serialized using dot notation (for example, web.webPageDetails.name).

:point_right: Checklist
  1. Update Target Audiences with XDM path for custom parameters if needed
  2. Update Profile Scripts with XDM path for custom parameters if needed

Configure Identity Namespace

The Adobe Experience Platform Identity Service sets a common visitor ID across all Adobe solutions in order to power Experience Cloud capabilities such as audience-sharing between solutions. You can also send your own customer IDs to the Service to enable cross-device targeting and integrations with other systems, such as your Customer Relationship Management (CRM) system.

:point_right: Checklist
  1. Add the identityMap object to XDM Schema
  2. To enable a partial website migration to AEP, set the targetMigrationEnabled and idMigrationEnabled parameters to true in the configuration. This helps where some pages still coninue to use Visitor.js and at.js.

Code below sends identity data to AEP:

1alloy("sendEvent", {
2 xdm: {
3 "identityMap": {
4 "ID_NAMESPACE": [
5 {
6 "id": "1234",
7 "authenticatedState": "ambiguous",
8 "primary": true
9 }
10 ]
11 }
12 }
13});

See documentation reference

Configure Datastream

Target must be enabled in the datastream configuration before any Target activities can be delivered by the Platform Web SDK.

:point_right: Checklist
  1. Enable Target in Datastream
  2. Optionally, set Property Token
  3. Optionally, set Target Environment ID
  4. Optionally, set Third Party ID

See documentation reference

Web Configuration

Load and Configure Library

There are three supported ways to use Adobe Experience Platform Web SDK:

  1. The preferred way to use Adobe Experience Platform Web SDK is via the Data Collection UI or Experience Platform UI.
  2. Adobe Experience Platform Web SDK is also available on a content delivery network (CDN) for you to use.
  3. Use the NPM library which exports EcmaScript 5 and EcmaScript 2015 (ES6) modules.

For technical clarification purposes, this guide references the CDN approach even though loading Web SDK via the Data Collection UI would be the most simple and recommended way.

Web SDK's alloy.js can be loaded synchronously or asynchronously.

Synchronous Load

:point_right: Checklist
  1. Implement Web SDK by adding alloy.js JavaScript library, its shim and configurations.
1<script>
2 !function(n,o){o.forEach(function(o){n[o]||((n.__alloyNS=n.__alloyNS||
3 []).push(o),n[o]=function(){var u=arguments;return new Promise(
4 function(i,l){n[o].q.push([i,l,u])})},n[o].q=[])})}
5 (window,["alloy"]);
6</script>
7<script src="https://cdn1.adoberesources.net/alloy/2.6.4/alloy.min.js"></script>
8<script>
9alloy("configure", {
10 "edgeConfigId": "ebebf826-a01f-4458-8cec-ef61de241c93",
11 "orgId":"ADB3LETTERSANDNUMBERS@AdobeOrg",
12 "prehidingStyle": "body { opacity: 0 !important }"
13});
14</script>

It is recommended to set prehidingStyle to body { opacity: 0 !important }. This ensures that the whole page is pre-hidden during personalization call.

Asynchronous Load with Prehiding Snippet

:point_right: Checklist
  1. Implement Web SDK by adding alloy.js JavaScript library with async tag, its shim and configurations.
1<script>
2 !function(n,o){o.forEach(function(o){n[o]||((n.__alloyNS=n.__alloyNS||
3 []).push(o),n[o]=function(){var u=arguments;return new Promise(
4 function(i,l){n[o].q.push([i,l,u])})},n[o].q=[])})}
5 (window,["alloy"]);
6 //Pre-hiding snippet
7 !function(e,a,n,t){
8 if (a) return;
9 var i=e.head;if(i){
10 var o=e.createElement("style");
11 o.id="alloy-prehiding",o.innerText=n,i.appendChild(o),
12 setTimeout(function(){o.parentNode&&o.parentNode.removeChild(o)},t)}}
13 (document, document.location.href.indexOf("adobe_authoring_enabled") !== -1, "body { opacity: 0 !important }", 3000);
14</script>
15<script src="https://cdn1.adoberesources.net/alloy/2.6.4/alloy.min.js" async></script>
16<script>
17alloy("configure", {
18 "edgeConfigId": "ebebf826-a01f-4458-8cec-ef61de241c93",
19 "orgId":"ADB3LETTERSANDNUMBERS@AdobeOrg"
20});
21</script>

See documentation reference

Add renderDecisions to Events

To enable Visual Experience Composer (VEC) experiences delivery, add renderDecisions: true to Web SDK event calls. This also delivers custom code experiences set up via VEC. There is no need to include decisionScopes: __view__ as it is automatically added by the Web SDK. This __view__ scope is a signal to fetch all the page-load activities from Target and prefetch all views.

:point_right: Checklist
  1. Add renderDecisions option for VEC-based Activities.
1alloy("sendEvent", {
2 renderDecisions: true,
3 xmd: {},
4 data: {}
5});

Add Optional decisionScopes to Events

Setting decisionScopes with a list of custom scopes (a.k.a. mboxes or Target Locations in older terms) retrieves qualifying Target Activities created with the form-based composer.

:point_right: Checklist
  1. Add decisionScopes option for the Form-based Activities.
1alloy("sendEvent", {
2 decisionScopes: ["scope1", "scope2"],
3 xmd: {},
4 data: {}
5});

Note that custom scope experiences will need to be rendered manually using code. See more information below.

Pass Data to Visitor Profile

It is advised to move custom parameters to XDM Schema. This also changes how Audiences work because the path to a custom parameter from XDM becomes different (eg., web.webPageDetails.name).

However, free form data is also supported inside data.__adobe.target object:

:point_right: Checklist
  1. Move mbox custom parameters and user profile data to xdm or data objects as needed.
1alloy("sendEvent", {
2 renderDecisions: true,
3 xdm: {},
4 data: {
5 __adobe: {
6 target: {
7 "profile.gender": "female",
8 "entity.id": 1234,
9 "user.categoryId": "outerwear,jackets",
10 "foo": "bar"
11 }
12 }
13 }
14 });

Response Tokens

For response tokens, subscribe to alloy.js sendEvent promise, iterate through propositions and extract the details from items -> meta.

:point_right: Checklist
  1. Extract response token data into local variable
1alloy("sendEvent", {
2 renderDecisions: true,
3 xdm: {},
4 data: {}
5 }).then(function(result) {
6 handleResponseTokens(result); //custom method that processes response tokens, see definition example below
7 });

Recommendations

Recommnedations entity data is sent as custom parameters in data object.

:point_right: Checklist
  1. Add entity.id and any other required entity. data to data.__adobe.target object.
1alloy("sendEvent", {
2 renderDecisions: true,
3 data: {
4 __adobe: {
5 target: {
6 "entity.id": "123",
7 "entity.genre": "Drama"
8 }
9 }
10 }
11 });

See documentation reference

SPA Implementation

Target Views

On the first sendEvent() call, all XDM Views that should be rendered to the end-user will be fetched and cached. Subsequent sendEvent() calls with XDM Views passed in will be read from the cache and rendered without a server call.

:point_right: Checklist
  1. Pass the view name and set to render decisions.
1alloy("sendEvent", {
2 "renderDecisions": true, //<--
3 "xdm": {
4 "web": {
5 "webPageDetails": {
6 "viewName":"home" //<--
7 }
8 }
9 }
10 });

Prefetch and Render Decisions

There may be a case where we want to prefetch content and display on demand

  1. Prefetch and render decisions.
1alloy("sendEvent", {
2 renderDecisions: false,
3}).then(function(result) {
4 return alloy("applyPropositions", {
5 propositions: retrievedPropositions,
6 metadata: getMetadata(scopes)
7 }).then(function(applyPropositionsResult) {
8 alloy("sendEvent", { // Send the display notifications
9 xdm: {
10 eventType: "decisioning.propositionDisplay",
11 _experience: {
12 decisioning: {
13 propositions: applyPropositionsResult.propositions
14 }
15 }
16 }
17 });
18 handleResponseTokens(applyPropositionsResult);
19 });
20});
21
22function getMetadata(scopes){
23 let metadata = {};
24 scopes.forEach(function(scope){
25 metadata[scope] = {
26 selector: "head",
27 actionType: "appendHtml"
28 }
29 });
30 return metadata;
31}

See documentation reference

Prefetch View Scope and Send Notifications

If decisions are not set to render, they are pre-fetched and we would need to apply content manually and send a display notification event.

:point_right: Checklist
  1. Display scope's content and send a notification event.
1function getContentForPropositions(data, props){
2 let content = [];
3 if (data.propositions) {
4 data.propositions.forEach(proposition => {
5 proposition.items.forEach(item => {
6 if (item.schema === "https://ns.adobe.com/personalization/html-content-item") {
7 content.push({
8 scope: "",
9 });
10 }
11 });
12 });
13
14 }
15 return content;
16}
17
18alloy("sendEvent", {
19 xdm: {...},
20 decisionScopes: ["__view__"]
21 }).then(function(result) {
22 getContentForPropositions(result, ["myScope1"]);
23 if (result.propositions) {
24 result.propositions.forEach(proposition => {
25 proposition.items.forEach(item => {
26 if (item.schema === HTML_SCHEMA) {
27 // manually apply offer
28 document.getElementById("form-based-offer-container").innerHTML =
29 item.data.content;
30 const executedPropositions = [
31 {
32 id: proposition.id,
33 scope: proposition.scope,
34 scopeDetails: proposition.scopeDetails
35 }
36 ];
37 // manually send the display notification event, so that Target/Analytics impressions are increased
38 alloy("sendEvent",{
39 "xdm": {
40 "eventType": "decisioning.propositionDisplay",
41 "_experience": {
42 "decisioning": {
43 "propositions": executedPropositions
44 }
45 }
46 }
47 });
48 }
49 });
50 });
51 }
52 });

Prefetch Custom Scopes, Send Notifications, Track Events or User Actions

You can prefetch scopes, send notifications, track events and user actions by calling the sendEvent command, populating the _experience.decisioning.propositions XDM fieldgroup, and setting the eventType to one of 2 values:

  • decisioning.propositionDisplay: Signals the rendering of the Target Activity.
  • decisioning.propositionInteract: Signals a user interaction with the Activity, like a mouse click.

Track a decisioning.propositionDisplay event after rendering an Activity

1alloy("sendEvent", {
2 xdm: {},
3 decisionScopes: ['discount']
4}).then(function(result) {
5 var propositions = result.propositions;
6 var discountProposition;
7 if (propositions) {
8 // Find the discount proposition, if it exists.
9 for (var i = 0; i < propositions.length; i++) {
10 var proposition = propositions[i];
11 if (proposition.scope === "discount") {
12 discountProposition = proposition;
13 break;
14 }
15 }
16 }
17 if (discountProposition) {
18 // Find the item from proposition that should be rendered.
19 // Rather than assuming there a single item that has HTML
20 // content, find the first item whose schema indicates
21 // it contains HTML content.
22 for (var j = 0; j < discountProposition.items.length; j++) {
23 var discountPropositionItem = discountProposition.items[i];
24 if (discountPropositionItem.schema === "https://ns.adobe.com/personalization/html-content-item") {
25 var discountHtml = discountPropositionItem.data.content;
26 // Render the content
27 var dailySpecialElement = document.getElementById("daily-special");
28 dailySpecialElement.innerHTML = discountHtml;
29
30 // For this example, we assume there is only a single place to update in the HTML.
31 break;
32 }
33 }
34 // Send a "decisioning.propositionDisplay" event signaling that the proposition has been rendered.
35 alloy("sendEvent", {
36 xdm: {
37 eventType: "decisioning.propositionDisplay",
38 _experience: {
39 decisioning: {
40 propositions: [
41 {
42 id: discountProposition.id,
43 scope: discountProposition.scope,
44 scopeDetails: discountProposition.scopeDetails
45 }
46 ]
47 }
48 }
49 }
50 });
51 }
52});

Track a decisioning.propositionInteract event after a click metric occurs

1alloy("sendEvent", {
2 xdm: { ...},
3 decisionScopes: ["hero-banner"]
4}).then(function (result) {
5 var propositions = result.propositions;
6
7 if (propositions) {
8 // Find the discount proposition, if it exists.
9 for (var i = 0; i < propositions.length; i++) {
10 var proposition = propositions[i];
11 for (var j = 0; j < proposition.items.length; j++) {
12 var item = proposition.items[j];
13
14 if (item.schema === "https://ns.adobe.com/personalization/measurement") {
15 // add metric to the DOM element
16 const button = document.getElementById("form-based-click-metric");
17
18 button.addEventListener("click", event => {
19 const executedPropositions = [
20 {
21 id: proposition.id,
22 scope: proposition.scope,
23 scopeDetails: proposition.scopeDetails
24 }
25 ];
26 // send the click track event
27 alloy("sendEvent", {
28 "xdm": {
29 "eventType": "decisioning.propositionInteract",
30 "_experience": {
31 "decisioning": {
32 "propositions": executedPropositions
33 }
34 }
35 }
36 });
37 });
38 }
39 }
40 }
41 }
42});

Send Order Confirmation

1alloy("sendEvent", {
2 "documentUnloading": true, // sends as a beacon
3 "xdm": {
4 "eventType": "commerce.purchases",
5 "commerce": {
6 "order": {
7 "purchaseID": "a8g784hjq1mnp3",
8 "purchaseOrderNumber": "VAU3123",
9 "currencyCode": "USD",
10 "priceTotal": 999.98
11 }
12 }
13 }
14});

Send the mbox3rdpartyId to Target

:point_right: Checklist
  1. Send a Third Party ID in Identity Map
1alloy("sendEvent", {
2 xdm: {
3 "identityMap": {
4 "ID_NAMESPACE": [
5 {
6 "id": "1234",
7 "authenticatedState": "authenticated"
8 }
9 ]
10 }
11 }
12 });

See documentation reference

Analytics A4T Integration

The Adobe Experience Platform Web SDK supports two types of Analytics logging for Analytics for Target (A4T) use cases:

  • Server-side Analytics logging All Analytics hits sent through the Edge Network are augmented with Target details on the server side, without having to go through the hit stitching process.
  • Client-side Analytics logging Target data is returned on the client side, allowing you to manually augment and send data to Analytics using the Data Insertion API.
:point_right: Checklist
  1. Confirm Analytics integration is set up and configured. This requires no further implementaiton work for A4T. Otherwise, refer to documentation below to configure it manually if no Analytics set up.

See documentation reference

Manual A4T setup

Modify Event Data Before Send

If you want to add, remove, or modify fields from the event globally, you can configure an onBeforeEventSend callback. This callback is called every time an event is sent. This callback is passed in an event object with an xdm field. Modify content.xdm to change the data that is sent with the event.

1alloy("configure", {
2 "edgeConfigId": "ebebf826-a01f-4458-8cec-ef61de241c93",
3 "orgId": "ADB3LETTERSANDNUMBERS@AdobeOrg",
4 "onBeforeEventSend": function(content) {
5 // ignores events from bots
6 if (MyBotDetector.isABot()) {
7 return false;
8 }
9 // Change existing values
10 content.xdm.web.webPageDetails.URL = xdm.web.webPageDetails.URL.toLowerCase();
11 // Remove existing values
12 delete content.xdm.web.webReferrer.URL;
13 // Or add new values
14 content.xdm._adb3lettersandnumbers.mycustomkey = "value";
15 //sets a query parameter in XDM
16 const queryString = window.location.search;
17 const urlParams = new URLSearchParams(queryString);
18 content.xdm.marketing.trackingCode = urlParams.get('cid')
19 }
20});

Cleanup

Remove at.js JavaScript library if previously used and any references to at.js API functions.

:point_right: Checklist
  1. Remove at.js code
  2. Remove adobe.targe.getOffers and/or adobe.targe.getOffer if any
  3. Remove adobe.target.trackEvent if any
  4. Remove window.targetGlobalSettings if any
  5. Remove window.targetPageParams and/or window.targetPageParamsAll if any
© 2023 by VU Blog. All rights reserved.
Created by Vadym