From de11801ddccd465d88b20022f84b8d8a33351b98 Mon Sep 17 00:00:00 2001 From: Spoorthi Pujari <63024083+spoorthipujariadobe@users.noreply.github.com> Date: Mon, 5 Aug 2024 11:54:09 -0700 Subject: [PATCH 1/3] Add tracking of content cards in tutorial --- gatsby-config.js | 2 +- .../code-based/api-reference.md | 9 +- .../code-based/index.md | 11 +- .../code-based/tabs/tutorial.md | 135 ++++++++++++++---- .../code-based/tutorial.md | 39 +++-- 5 files changed, 143 insertions(+), 53 deletions(-) diff --git a/gatsby-config.js b/gatsby-config.js index da24c2ebbb..c273e818cd 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -248,7 +248,7 @@ module.exports = { path: "/edge/adobe-journey-optimizer/code-based/api-reference" }, { - title: "Code-based Tutorial", + title: "Code-based experiences & Content Cards tutorial", path: "/edge/adobe-journey-optimizer/code-based/tutorial" } ] diff --git a/src/pages/edge/adobe-journey-optimizer/code-based/api-reference.md b/src/pages/edge/adobe-journey-optimizer/code-based/api-reference.md index a67ad2a49a..78e6963a59 100644 --- a/src/pages/edge/adobe-journey-optimizer/code-based/api-reference.md +++ b/src/pages/edge/adobe-journey-optimizer/code-based/api-reference.md @@ -1,18 +1,19 @@ --- -title: Code-based Experiences - API Reference -description: This document lists the public APIs available in the Messaging extension for implementing code-based experiences. +title: Code-based Experiences & Content Cards - API Reference +description: This document lists the public APIs available in the Messaging extension for implementing code-based experiences and content cards. keywords: - Adobe Journey Optimizer - API reference - Messaging - Code-based Experiences +- Content Cards --- import Tabs from './tabs/api-reference.md' -# Code-based Experiences - API reference +# Code-based Experiences & Content Cards - API reference -This document lists the public APIs available in the Messaging extension for implementing code-based experiences. +This document lists the public APIs available in the Messaging extension for implementing code-based experiences and content cards. ## getPropositionsForSurfaces diff --git a/src/pages/edge/adobe-journey-optimizer/code-based/index.md b/src/pages/edge/adobe-journey-optimizer/code-based/index.md index 876d919ede..34f2816ab4 100644 --- a/src/pages/edge/adobe-journey-optimizer/code-based/index.md +++ b/src/pages/edge/adobe-journey-optimizer/code-based/index.md @@ -1,19 +1,20 @@ --- -title: Code-based Experiences -description: This document guides you to integrating code-based experiences in your application. +title: Code-based Experiences & Content Cards +description: This document guides you to integrating code-based experiences and content cards in your application. keywords: - Adobe Journey Optimizer - Guide - Code-based experiences +- Content Cards --- -# Code-based Experiences +# Code-based Experiences & Content Cards -This document guides you to integrating code-based experiences in your application. +This document guides you through integrating code-based experiences and content cards in your application. ## API reference -* [Code-based Experiences APIs](./api-reference.md) +* [Code-based Experiences & Content Cards APIs](./api-reference.md) ## Public Classes and Enums diff --git a/src/pages/edge/adobe-journey-optimizer/code-based/tabs/tutorial.md b/src/pages/edge/adobe-journey-optimizer/code-based/tabs/tutorial.md index b8e16714e9..3d1b892075 100644 --- a/src/pages/edge/adobe-journey-optimizer/code-based/tabs/tutorial.md +++ b/src/pages/edge/adobe-journey-optimizer/code-based/tabs/tutorial.md @@ -129,18 +129,29 @@ Messaging.getPropositionsForSurfaces([surface1, surface2]) { propositionsDict, e #### Kotlin ```kotlin -// get the propositions for surface1 +// get the HTML propositions for surface1 // bail early if no propositions are found for surface1 if (propositionsForSurface1 == null || propositionsForSurface1.isEmpty()) return -// iterate through items in proposition -for (propositionItem in propositionsForSurface1.first()::items) { - if (propositionItem.schema == SchemaType.HTML_CONTENT) { +val propositionItem1 = propositionsForSurface1.first().items[0] +if (propositionItem1.schema == SchemaType.HTML_CONTENT) { // retrieve the HTML content - val htmlContent = propositionItem.htmlContent + val htmlContent:String? = propositionItem1.htmlContent // use retrieved html content - } +} + + +// get the content card propositions for surface2 +// bail early if no propositions are found for surface2 +if (propositionsForSurface2 == null || propositionsForSurface2.isEmpty()) return + +val propositionItem2 = propositionsForSurface2.first().items[0] +if (propositionItem2.schema == SchemaType.CONTENT_CARD) { + // retrieve the HTML content + val contentCard: ContentCard? = propositionItem2.contentCardSchemaData?.contentCard + + // use retrieved content card } ``` @@ -153,14 +164,25 @@ if (propositionsForSurface1 == null || propositionsForSurface1.isEmpty()) { return; } -// iterate through items in proposition -for (final PropositionItem propositionItem: propositionsForSurface1.get(0).getItems()) { - if (propositionItem.getSchema() == SchemaType.HTML_CONTENT) { - // retrieve the HTML content - final String htmlContent = propositionItem.getHtmlContent(); +final PropositionItem propositionItem1 = propositionsForSurface1.get(0).getItems().get(0); +if (propositionItem1.getSchema() == SchemaType.HTML_CONTENT) { + // retrieve the HTML content + final String htmlContent = propositionItem1.getHtmlContent(); - // use retrieved html content - } + // use retrieved html content +} + +if (propositionsForSurface2 == null || propositionsForSurface2.isEmpty()) { + // bail early if no propositions are found for surface2 + return; +} + +final PropositionItem propositionItem2 = propositionsForSurface2.get(0).getItems().get(0); +if (propositionItem2.getSchema() == SchemaType.CONTENT_CARD) { + // retrieve the content card + final ContentCard contentCard = propositionItem2.getContentCardSchemaData().getContentCard(); + + // use retrieved content card } ``` @@ -169,16 +191,27 @@ for (final PropositionItem propositionItem: propositionsForSurface1.get(0).getIt #### Swift ```swift -/// get the propositions for surface1 -if let codePropositions: [Proposition] = propositionsDict?[surface1], !codePropositions.isEmpty { - /// iterate through items in proposition - ForEach(codePropositions.first?.items as? [PropositionItem] ?? [], id:\.itemId) { propositionItem in - if propositionItem.schema == .htmlContent { - // retrieve the HTML content - let htmlContent = propositionItem.htmlContent - - // use retrieved html content - } +/// get the HTML propositions for surface1 +if let propositionsForSurface1: [Proposition] = propositionsDict?[surface1], !propositionsForSurface1.isEmpty, + let propositionItem1 = propositionsForSurface1.first?.items.first { + if propositionItem1.schema == .htmlContent { + // retrieve the HTML content + let htmlContent = propositionItem1.htmlContent + + // use retrieved html content + + } +} + +/// get the content card propositions for surface2 +if let propositionsForSurface2: [Proposition] = propositionsDict?[surface2], !propositionsForSurface2.isEmpty, + let propositionItem2 = propositionsForSurface2.first?.items.first { + if propositionItem2.schema == .contentCard { + // retrieve the content card + let contentCard = propositionItem2.contentCardSchemaData?.getContentCard() + + // use retrieved content card + } } ``` @@ -190,11 +223,11 @@ if let codePropositions: [Proposition] = propositionsDict?[surface1], !codePropo ```kotlin // Tracking display of PropositionItem // use the same propositionItem object that was used to get the content in the previous section -propositionItem.track(MessagingEdgeEventType.DISPLAY) +propositionItem1.track(MessagingEdgeEventType.DISPLAY) // Tracking interaction with PropositionItem // use the same propositionItem object that was used to get the content in the previous section -propositionItem.track("click", MessagingEdgeEventType.INTERACT, null) +propositionItem1.track("click", MessagingEdgeEventType.INTERACT, null) ``` #### Java @@ -202,11 +235,11 @@ propositionItem.track("click", MessagingEdgeEventType.INTERACT, null) ```java // Tracking display of PropositionItem // use the same propositionItem object that was used to get the content in the previous section -propositionItem.track(MessagingEdgeEventType.DISPLAY); +propositionItem1.track(MessagingEdgeEventType.DISPLAY); // Tracking interaction with PropositionItem // use the same propositionItem object that was used to get the content in the previous section -propositionItem.track("click", MessagingEdgeEventType.INTERACT, null); +propositionItem1.track("click", MessagingEdgeEventType.INTERACT, null); ``` @@ -216,11 +249,11 @@ propositionItem.track("click", MessagingEdgeEventType.INTERACT, null); ```swift /// Tracking display of PropositionItem /// use the same propositionItem object that was used to get the content in the previous section -propositionItem.track(withEdgeEventType: MessagingEdgeEventType.display) +propositionItem1.track(withEdgeEventType: MessagingEdgeEventType.display) /// Tracking interaction with PropositionItem /// use the same propositionItem object that was used to get the content in the previous section -propositionItem.track("click", withEdgeEventType: MessagingEdgeEventType.display) +propositionItem1.track("click", withEdgeEventType: MessagingEdgeEventType.display) ``` @@ -244,7 +277,7 @@ propositionItem.track("click", MessagingEdgeEventType.INTERACT, tokenList) final List tokenList = new ArrayList<>(); tokenList.add(dataItemToken1); tokenList.add(dataItemToken2); -propositionItem.track("click", MessagingEdgeEventType.INTERACT, tokenList); +propositionItem1.track("click", MessagingEdgeEventType.INTERACT, tokenList); ``` @@ -254,5 +287,45 @@ propositionItem.track("click", MessagingEdgeEventType.INTERACT, tokenList); ```swift /// Tracking interaction with PropositionItem with tokens /// Extract the tokens from the PropositionItem item data -propositionItem.track("click", withEdgeEventType: .interact, forTokens: [dataItemToken1, dataItemToken2]) +propositionItem1.track("click", withEdgeEventType: .interact, forTokens: [dataItemToken1, dataItemToken2]) +``` + + + +#### Kotlin + +```kotlin +// Tracking display of ContentCard +// use the same contentCard object from the retrieve propositions section +contentCard.track(null, MessagingEdgeEventType.DISPLAY) + +// Tracking interaction with ContentCard +// use the same contentCard object from the retrieve propositions section +contentCard.track("click", MessagingEdgeEventType.INTERACT) ``` + +#### Java + +```java +// Tracking display of ContentCard +// use the same contentCard from the retrieve propositions section +contentCard.track(null, MessagingEdgeEventType.DISPLAY); + +// Tracking interaction with ContentCard +// use the same contentCard object from the retrieve propositions section +contentCard.track("click", MessagingEdgeEventType.INTERACT); +``` + + + +#### Swift + +```swift +/// Tracking display of ContentCard +/// use the same contentCard object from the retrieve propositions section +contentCard.track(withEdgeEventType: MessagingEdgeEventType.display) + +/// Tracking interaction with ContentCard +/// use the same contentCard object from retrieve propositions section +contentCard.track("click", withEdgeEventType: MessagingEdgeEventType.interact) +``` \ No newline at end of file diff --git a/src/pages/edge/adobe-journey-optimizer/code-based/tutorial.md b/src/pages/edge/adobe-journey-optimizer/code-based/tutorial.md index 9ac99cdcc4..c1a2410859 100644 --- a/src/pages/edge/adobe-journey-optimizer/code-based/tutorial.md +++ b/src/pages/edge/adobe-journey-optimizer/code-based/tutorial.md @@ -1,26 +1,27 @@ --- -title: Code-based experiences implementation tutorial -description: This document describes how to fetch, display and track code-based experiences using the Adobe Journey Optimizer extension. +title: Code-based experiences & Content Cards implementation tutorial +description: This document describes how to fetch, display and track code-based experiences & content cards using the Adobe Journey Optimizer extension. keywords: - Adobe Journey Optimizer - Messaging - Code-based experiences +- Content Cards - Tutorial --- import Tabs from './tabs/tutorial.md' -# Code-based experiences implementation tutorial +# Code-based experiences & Content Cards implementation tutorial -This document describes how to fetch, display and track code-based experiences using the Adobe Journey Optimizer extension. +This document describes how to fetch, display and track code-based experiences and content cards using the Adobe Journey Optimizer extension. ## Pre-requisites [Integrate and register Messaging extension](../../index.md#implement-extension-in-mobile-app) in your app. -## Fetch and cache the code-based content +## Fetch and cache code-based experiences & content cards -To fetch the content for the surfaces configured in Adobe Journey Optimizer campaigns, call the [updatePropositionsForSurfaces](../api-reference.md#updatepropositionsforsurfaces) API . You should batch requesting multiple [Surface](../public-classes/surface.md) URIs in a single API call when possible. The returned code-based experiences are cached in-memory by the Messaging extension and persists through the lifecycle of the app (i.e as long as the app is running). An example of the call is shown below: +To fetch the propositions for the surfaces configured in Adobe Journey Optimizer campaigns, call the [updatePropositionsForSurfaces](../api-reference.md#updatepropositionsforsurfaces) API . You should batch requesting multiple [Surface](../public-classes/surface.md) URIs in a single API call when possible. The returned code-based experiences and content cards are cached in-memory by the Messaging extension and persists through the lifecycle of the app (i.e as long as the app is running). An example of the call is shown below: @@ -34,7 +35,7 @@ iOS ## Retrieve cached propositions -To retrieve the previously fetched content from the in-memory cache, call the [getPropositionsForSurfaces](../api-reference.md#getpropositionsforsurfaces) API with a list of required surface URIs and a completion handler. The completion handler will be invoked with a list of [Proposition](../public-classes/proposition.md) objects corresponding to the requested surfaces, or `AEPError` object if an error occurs. +To retrieve the previously fetched propositions from the in-memory cache, call the [getPropositionsForSurfaces](../api-reference.md#getpropositionsforsurfaces) API with a list of required surface URIs and a completion handler. The completion handler will be invoked with a list of [Proposition](../public-classes/proposition.md) objects corresponding to the requested surfaces, or `AEPError` object if an error occurs. @@ -54,9 +55,9 @@ iOS ## Using the retrieved propositions -The [Proposition](../public-classes/proposition.md) object returned in the completion handler encapsulates the content specified for the corresponding surface, as well as information needed for tracking interactions with the content. Multiple `Proposition` objects can be returned for a single surface based on the number of campaigns configured for it in Adobe Journey Optimizer. Each `Proposition` object in turn can contain multiple items, represented by the [PropositionItem](../public-classes/proposition-item.md) class, based on how the campaign's content is defined. To access the content, iterate through the list of `PropositionItem` present in the returned list of `Proposition`. The `SchemaType` of the `PropositionItem` indicates the type of content it contains and can be used to determine how to render or interpret the returned content. The `PropositionItem` class contains helper functions to access the different types of supported content. +The [Proposition](../public-classes/proposition.md) object returned in the completion handler encapsulates the content specified for the corresponding surface, as well as information needed for tracking interactions with the content. Multiple `Proposition` objects can be returned for a single surface based on the number of campaigns configured for it in Adobe Journey Optimizer. The content can be accessed through the [PropositionItem](../public-classes/proposition-item.md) present inside the returned list of `Proposition`. The `SchemaType` of the `PropositionItem` indicates the type of content it contains and can be used to determine how to render or interpret the returned content. The `PropositionItem` class contains helper functions to access the different types of supported content. -The following example shows how to iterate through the propositions returned earlier and retrieve the HTML content. Please adapt the solution to suit the needs of your application and use the returned proposition content appropriately. +The following example shows how to iterate through the propositions returned earlier and retrieve the HTML content and content cards. Please adapt the solution to suit the needs of your application and use the returned proposition content appropriately. @@ -70,7 +71,7 @@ iOS ## Tracking interactions with code-based experiences -Since the onus of rendering the code-based experience lies with the app developer, you must monitor the desired end user interactions and call the appropriate tracking APIs. To record an interaction with the code-based content, call the [track](../public-classes/proposition-item.md#track) API provided in the `PropositionItem` class. The following code shows two examples of tracking: when the content is displayed to the user and when the user clicks on the content. These examples are for illustrating how to call the track API and not a recommendation on where it should be called. Please examine your app workflow to find the appropriate way to perform tracking. +Since the onus of rendering the code-based experience lies with the app developer, you must monitor the desired end user interactions and call the appropriate tracking APIs. To record an interaction with the code-based experience, call the [track](../public-classes/proposition-item.md#track) API provided in the `PropositionItem` class. The following code shows two examples of tracking: when the content is displayed to the user and when the user clicks on the content. These examples are for illustrating how to call the track API and not a recommendation on where it should be called. Please examine your app workflow to find the appropriate way to perform tracking. @@ -84,7 +85,7 @@ iOS ### Tracking items from embedded decisions -When Adobe Journey Optimizer campaigns are created with embedded decisions, the server can respond with one or more items based on the number of items requested in the decision. To track these embedded items, the Adobe Journey Optimizer campaign UI provides `item._trackingToken` attributes. When authoring the campaign's content, you would need to embed the provided token as an HTML data-attribute in case of HTML content or JSON attribute in case on JSON content. The following example campaign shows content with embedded decision, where multiple paragraph tags containing image URLs can be returned. +When Adobe Journey Optimizer campaigns are created with embedded decisions, the server can respond with one or more items based on the number of items requested in the decision. To track these embedded items, the Adobe Journey Optimizer campaign UI provides `item._trackingToken` attributes. When authoring the campaign's content, you would need to embed the provided token as an HTML data-attribute in case of HTML content or JSON attribute in case on JSON content. The following example campaign shows HTML content with embedded decision, where multiple paragraph tags containing image URLs can be returned. ```html @@ -107,7 +108,7 @@ For the above example, the server can return a response with two decision items ``` -Since the embedded items are located inside a single PropositionItem's data, the app developer will need to extract the `data-item-token` when tracking the interactions with the item. The token, along with the other tracking information, will need to be passed to the [track](../public-classes/proposition-item.md#track) API provided by the Messaging SDK. If no tracking tokens are supplied, normal tracking events will be sent. If tracking tokens were used during authoring, it will be assumed that all the corresponding embedded items were displayed. The following code shows an example of calling the track API with tokens. +Since the embedded items are located inside a single `PropositionItem` data, the app developer will need to extract the `data-item-token` when tracking the interactions with the item. The token, along with the other tracking information, will need to be passed to the [track](../public-classes/proposition-item.md#track) API provided by the Messaging SDK. If no tracking tokens are supplied, normal tracking events will be sent. If tracking tokens were used during authoring, it will be assumed that all the corresponding embedded items were displayed. The following code shows an example of calling the track API with tokens. @@ -118,3 +119,17 @@ Android iOS + +## Tracking interactions with content cards + +Since the onus of rendering the content card lies with the app developer, you must monitor the display and desired end user interactions and call the appropriate tracking APIs. To record a display or interaction with the content card, call the [track](../public-classes/content-card.md#track) API provided in the `ContentCard` class. The following code shows two examples of tracking: when the content card is displayed to the user and when the user clicks on the content card. These examples are for illustrating how to call the track API and not a recommendation on where it should be called. Please examine your app workflow to find the appropriate way to perform tracking. + + + +Android + + + +iOS + + From 4daedeef7a26fb2c47e6dd17e4bb2e17b1f9ea8b Mon Sep 17 00:00:00 2001 From: Spoorthi Pujari <63024083+spoorthipujariadobe@users.noreply.github.com> Date: Mon, 5 Aug 2024 12:02:24 -0700 Subject: [PATCH 2/3] fix lint issues --- .../edge/adobe-journey-optimizer/code-based/tabs/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/edge/adobe-journey-optimizer/code-based/tabs/tutorial.md b/src/pages/edge/adobe-journey-optimizer/code-based/tabs/tutorial.md index 3d1b892075..27c2cb577e 100644 --- a/src/pages/edge/adobe-journey-optimizer/code-based/tabs/tutorial.md +++ b/src/pages/edge/adobe-journey-optimizer/code-based/tabs/tutorial.md @@ -328,4 +328,4 @@ contentCard.track(withEdgeEventType: MessagingEdgeEventType.display) /// Tracking interaction with ContentCard /// use the same contentCard object from retrieve propositions section contentCard.track("click", withEdgeEventType: MessagingEdgeEventType.interact) -``` \ No newline at end of file +``` From e7da8e439345ab6653d4d38049b9fc5ce1681b1e Mon Sep 17 00:00:00 2001 From: Spoorthi Pujari <63024083+spoorthipujariadobe@users.noreply.github.com> Date: Mon, 5 Aug 2024 14:30:30 -0700 Subject: [PATCH 3/3] make content card tracking simpler --- src/pages/edge/adobe-journey-optimizer/code-based/tutorial.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/edge/adobe-journey-optimizer/code-based/tutorial.md b/src/pages/edge/adobe-journey-optimizer/code-based/tutorial.md index c1a2410859..cfebb9963d 100644 --- a/src/pages/edge/adobe-journey-optimizer/code-based/tutorial.md +++ b/src/pages/edge/adobe-journey-optimizer/code-based/tutorial.md @@ -71,7 +71,7 @@ iOS ## Tracking interactions with code-based experiences -Since the onus of rendering the code-based experience lies with the app developer, you must monitor the desired end user interactions and call the appropriate tracking APIs. To record an interaction with the code-based experience, call the [track](../public-classes/proposition-item.md#track) API provided in the `PropositionItem` class. The following code shows two examples of tracking: when the content is displayed to the user and when the user clicks on the content. These examples are for illustrating how to call the track API and not a recommendation on where it should be called. Please examine your app workflow to find the appropriate way to perform tracking. +Since it's up to the app developer to render the content card UI, you must monitor the desired end user interactions and call the appropriate tracking APIs. To record an interaction with the code-based experience, call the [track](../public-classes/proposition-item.md#track) API provided in the `PropositionItem` class. The following code shows two examples of tracking: when the content is displayed to the user and when the user clicks on the content. These examples are for illustrating how to call the track API and not a recommendation on where it should be called. Please examine your app workflow to find the appropriate way to perform tracking. @@ -122,7 +122,7 @@ iOS ## Tracking interactions with content cards -Since the onus of rendering the content card lies with the app developer, you must monitor the display and desired end user interactions and call the appropriate tracking APIs. To record a display or interaction with the content card, call the [track](../public-classes/content-card.md#track) API provided in the `ContentCard` class. The following code shows two examples of tracking: when the content card is displayed to the user and when the user clicks on the content card. These examples are for illustrating how to call the track API and not a recommendation on where it should be called. Please examine your app workflow to find the appropriate way to perform tracking. +Since it's up to the app developer to render the content card UI, you must monitor the display and desired end user interactions and call the appropriate tracking APIs. To record a display or interaction with the content card, call the [track](../public-classes/content-card.md#track) API provided in the `ContentCard` class. The following code shows two examples of tracking: when the content card is displayed to the user and when the user clicks on the content card. These examples are for illustrating how to call the track API and not a recommendation on where it should be called. Please examine your app workflow to find the appropriate way to perform tracking.