---
title: Integrate profile orchestration with V8 to deliver cart abandonment emails
slug: docs/integrate-profile-orchestration-with-v8-to-deliver-cart-abandonment-emails
docTags: 
createdAt: 2025-06-27T08:26:34.141Z
---

# Integrate profile orchestration with V8 to deliver cart abandonment emails

As soon as someone triggers a checkout event which is not followed by a purchase event within a specified timeout, you want to send an email that displays the content of the shopping cart at checkout time. To make this possible, you use Adobe Real-time CDP, AJO (Profile orchestration), and Campaign V8.

There are quite a few examples for simple and flat payloads on how to set this up on both AJO side (Campaign Classic action) and Campaign V8 (transactional message). But as soon as the payload becomes complex (arrays of nested objects), there is no documentation available on how the payload is transformed from XDM (JSON) to XML in V8. There are no code examples available on how to iterate over the shopping cart items in a transactional email in Campaign.

This document describes a working end-to-end approach.

## Data collection

The checkout process on our website will be collected via Adobe Edge and will look like this, most important are the eventType (trigger journey) and the productListItems (that is what our email is all about)

:::BlockQuote
\{
&#x20;   "events": \[
&#x20;       \{
&#x20;           "xdm": \{
&#x20;               "eventType": "commerce.checkouts",
&#x20;               "productListItems": \[
&#x20;                   \{
&#x20;                       "SKU": "Meindle Mens Response GTW Shoes",
&#x20;                       "\_demoemea": \{
&#x20;                           "core": \{
&#x20;                               "imageURL": "https\://publish913.adobedemo.com/content/dam/cotsworld-assets/cw-meindle-mens-respond-gtx-shoes.jpg",
&#x20;                               "description": "Meindle Mens Response GTW Shoes"
&#x20;                           }
&#x20;                       },
&#x20;                       "name": "Meindle Mens Response GTW Shoes",
&#x20;                       "priceTotal": 160,
&#x20;                       "productAddMethod": "web",
&#x20;                       "quantity": 1,
&#x20;                       "category": "Hiking Shoes"
&#x20;                   },
&#x20;                   \{
&#x20;                       "SKU": "Meindl Mens Respond Mid II",
&#x20;                       "\_demoemea": \{
&#x20;                           "core": \{
&#x20;                               "imageURL": "https\://publish913.adobedemo.com/content/dam/cotsworld-assets/cw-meindle-men-respond-mid-II.jpg",
&#x20;                               "description": "Meindl Mens Respond Mid II"
&#x20;                           }
&#x20;                       },
&#x20;                       "name": "Meindl Mens Respond Mid II",
&#x20;                       "priceTotal": 185,
&#x20;                       "productAddMethod": "web",
&#x20;                       "quantity": 1,
&#x20;                       "category": "Hiking Shoes"
&#x20;                   }
&#x20;               ]
&#x20;           }
&#x20;       }
&#x20;   ]
}
:::

## V8: define transactional email

- Create a transactional email in Adobe Campaign V8
- Specify and eventType "**mmeewis YDL Abandon Cart**"
- Add sample context data

:::BlockQuote
\<ctx>
&#x20; \<firstname>Marc\</firstname>
\</ctx>
:::

- Edit the email's content and display just the firstname

:::BlockQuote
Hello \<%= rtEvent.ctx.firstname %>
:::

- Publish the transactional email

## AJO: Define Campaign Classic Action

That action will trigger a transactional email in V8; the JSON format of the payload that the campaign expects is as follows. Note that we include productListItems without providing further details. It is modelled as an array with two empty elements. The eventType refers to the transactional mail's eventType:

:::BlockQuote
\{
&#x20;   "channel": "email",
&#x20;   "eventType": "mmeewis YDL Abandon Cart",
&#x20;   "email": "mmeewis\@adobe.com",
&#x20;   "ctx": \{
&#x20;       "firstname": "Marc",
&#x20;       "productListItems": \[
&#x20;           \{
&#x20;           },
&#x20;           \{
&#x20;           }
&#x20;       ]
&#x20;   }
}
:::

Define a custom action "**mmeewis\_YDL\_AbandonCart\_Email**" of type "**Campaign Classic**" in AJO Configurations -> Actions, and paste the above as the sample payload. Change the variable input type from constant to variable. "productListItems" should be of type listObject, variable with name **productListItems**, and optional:

![](https://api.archbee.com/api/optimize/bAgVaanSi1tFmfc8PghaH/W7pD6E2z73XY4KZ_YvTyJ_cleanshot-2025-06-27-at-102958.png)

## AJO: Define checkout journey

This journey starts whenever a checkout event is collected. Next, it waits for 20 seconds for a purchase event, and if that does not happen, our campaign classic custom action "mmeewis\_YDL\_AbandonCart\_Email" will be executed.

Check out the event definition:

- EventId condition: **In(the eventType, \['commerce.checkouts'])**
- Fields selected: **select productListItems**

![](https://api.archbee.com/api/optimize/bAgVaanSi1tFmfc8PghaH/2u5DMofR45UEZWySzSlfM_cleanshot-2025-06-27-at-103036.png)



**mmeewis\_YDL\_AbandonCart\_Email** request parameter mapping

- eventType (labeled *mmeewis YDL Abondon Cart*) : mmeewis YDL Abondon Cart
- email (labeled <u>*mmeewis\@adobe.com*</u>) : The Address of personalEmail (person.personalEmail.address)
- firstname (labeled *Marc*) : The firstName of name (person.name.firstname)
- productListItems : Context > Checkout > Product list items

Public the journey

## Trigger checkout event

Trigger the checkout event (DSN website)

![](https://api.archbee.com/api/optimize/bAgVaanSi1tFmfc8PghaH/AMZjGBnVPLYm-To_vUHLc_cleanshot-2025-06-27-at-103113.png)

and the email:



![](https://api.archbee.com/api/optimize/bAgVaanSi1tFmfc8PghaH/kYqQ97KfMIi8oSckk-j3C_cleanshot-2025-06-27-at-103144.png)

## V8: What payload is AJO sending to V8

In the Campaign web UI, navigate to "Event history" and open your most recent event. Note: It can take a few minutes before the event history is updated.

Check the payload via \</> View data:

:::BlockQuote
\<firstname>Marc\</firstname>
\<productListItems-collection>
&#x20;   \<productListItems>
&#x20;       \<quantity>1\</quantity>
&#x20;       \<productAddMethod>web\</productAddMethod>
&#x20;       \<priceTotal>160\</priceTotal>
&#x20;       \<name>Meindle Mens Response GTW Shoes\</name>
&#x20;       \<\_demoemea>
&#x20;           \<core>
&#x20;               \<imageURL>https\://publish913.adobedemo.com/content/dam/cotsworld-assets/cw-meindle-mens-respond-gtx-shoes.jpg\</imageURL>
&#x20;               \<description>Meindle Mens Response GTW Shoes\</description>
&#x20;           \</core>
&#x20;       \</\_demoemea>
&#x20;       \<SKU>Meindle Mens Response GTW Shoes\</SKU>
&#x20;   \</productListItems>
&#x20;   \<productListItems>
&#x20;       \<quantity>1\</quantity>
&#x20;       \<productAddMethod>web\</productAddMethod>
&#x20;       \<priceTotal>185\</priceTotal>
&#x20;       \<name>Meindl Mens Respond Mid II\</name>
&#x20;       \<\_demoemea>
&#x20;           \<core>
&#x20;               \<imageURL>https\://publish913.adobedemo.com/content/dam/cotsworld-assets/cw-meindle-men-respond-mid-II.jpg\</imageURL>
&#x20;               \<description>Meindl Mens Respond Mid II\</description>
&#x20;           \</core>
&#x20;       \</\_demoemea>
&#x20;       \<SKU>Meindl Mens Respond Mid II\</SKU>
&#x20;   \</productListItems>
\</productListItems-collection>
:::

Our XDM productListItems array is wrapped in an element.

## V8: Update transactional email context sample

Open the transaction email's sample content and paste your event's payload, do not forget to add the open and close element:

:::BlockQuote
\<ctx>
&#x9;\<firstname>Marc\</firstname>
&#x9;\<productListItems-collection>
&#x9;	\<productListItems>
&#x9;		\<quantity>1\</quantity>
&#x9;		\<productAddMethod>web\</productAddMethod>
&#x9;		\<priceTotal>160\</priceTotal>
&#x9;		\<name>Meindle Mens Response GTW Shoes\</name>
&#x9;		\<\_demoemea>
&#x9;			\<core>
&#x9;				\<imageURL>https\://publish913.adobedemo.com/content/dam/cotsworld-assets/cw-meindle-mens-respond-gtx-shoes.jpg\</imageURL>
&#x9;				\<description>Meindle Mens Response GTW Shoes\</description>
&#x9;			\</core>
&#x9;		\</\_demoemea>
&#x9;		\<SKU>Meindle Mens Response GTW Shoes\</SKU>
&#x9;	\</productListItems>
&#x9;	\<productListItems>
&#x9;		\<quantity>1\</quantity>
&#x9;		\<productAddMethod>web\</productAddMethod>
&#x9;		\<priceTotal>185\</priceTotal>
&#x9;		\<name>Meindl Mens Respond Mid II\</name>
&#x9;		\<\_demoemea>
&#x9;			\<core>
&#x9;				\<imageURL>https\://publish913.adobedemo.com/content/dam/cotsworld-assets/cw-meindle-men-respond-mid-II.jpg\</imageURL>
&#x9;				\<description>Meindl Mens Respond Mid II\</description>
&#x9;			\</core>
&#x9;		\</\_demoemea>
&#x9;		\<SKU>Meindl Mens Respond Mid II\</SKU>
&#x9;	\</productListItems>
&#x9;\</productListItems-collection>
\</ctx>
:::

## V8: Add an HTML component to render the cart

Know we know the correct payload, we can start writing the code to render our shopping cart. Edit the email's content and add an HTML component to your email and paste the code below:

:::BlockQuote
\<p>Dear \<%

&#x20;   try \{
&#x20;       rootXML = new XML(rtEvent.ctx);
&#x20;       firstName = String(rootXML.firstname);
&#x20;   } catch (e) \{
&#x20;       logInfo("Error parsing XML for firstname: " + e.message + " XML: " + xmlString);
&#x20;   }
&#x20;   %>\<%= firstName %>,\</p>

\<p>Here are the items currently in your shopping basket:\</p>

\<table width="100%" border="0" cellpadding="0" cellspacing="0" style="border-collapse\:collapse;">
&#x20;   \<thead>
&#x20;       \<tr style="background-color:#f2f2f2;">
&#x20;           \<th style="padding:8px;text-align\:left;">Product\</th>
&#x20;           \<th style="padding:8px;text-align\:left;">Quantity\</th>
&#x20;           \<th style="padding:8px;text-align\:right;">Total Price\</th>
&#x20;           \<th style="padding:8px;text-align\:left;">SKU\</th>
&#x20;       \</tr>
&#x20;   \</thead>
&#x20;   \<tbody>
&#x20;       \<%
&#x20;       var grandTotal = 0;
&#x20;       try \{
&#x20;           // Re-use rootXML from above, or parse again if you prefer to keep scope tight
&#x20;           if (typeof rootXML === 'undefined' || !rootXML) \{
&#x20;                rootXML = new XML(xmlString); // Parse again if not already
&#x20;           }
&#x20;           // Access the collection using array notation due to the hyphen in the tag name
&#x20;           var productListItemsCollection = rootXML\['productListItems-collection'];
&#x20;          &#x20;
&#x20;           // Now, iterate directly over 'productListItems' children
&#x20;           // E4X handles this beautifully when the element names are consistent
&#x20;           if (productListItemsCollection.productListItems.length() > 0) \{
&#x20;               for each (var item in productListItemsCollection.productListItems) \{
&#x20;                   var quantity = Number(item.quantity);
&#x20;                   var productAddMethod = String(item.productAddMethod); // If you need this
&#x20;                   var priceTotal = Number(item.priceTotal);
&#x20;                   var name = String(item.name);
&#x20;                  &#x20;
&#x20;                   // Access nested elements: item.\_demoemea.core.imageURL
&#x20;                   var imageURL = String(item.\_demoemea.core.imageURL);
&#x20;                   var description = String(item.\_demoemea.core.description); // For alt text
&#x20;                   var sku = String(item.SKU);
&#x20;                   grandTotal += priceTotal; // Summing the pre-calculated priceTotal
&#x20;       %>
&#x20;       \<tr>
&#x20;           \<td style="padding:8px;border-bottom:1px solid #ddd;">
&#x20;               \<% if (imageURL && imageURL !== "undefined") \{ %>
&#x20;                   \<img src="\<%= imageURL %>" alt="\<%= description %>" width="50" height="50" style="vertical-align\:middle;margin-right:10px;">
&#x20;               \<% } %>
&#x20;               \<%= name %>
&#x20;           \</td>
&#x20;           \<td style="padding:8px;border-bottom:1px solid #ddd;">\<%= quantity %>\</td>
&#x20;           \<td style="padding:8px;border-bottom:1px solid #ddd;text-align\:right;">\<%= priceTotal.toFixed(2) %>\</td>
&#x20;           \<td style="padding:8px;border-bottom:1px solid #ddd;">\<%= sku %>\</td>
&#x20;       \</tr>
&#x20;       \<%
&#x20;               }
&#x20;           } else \{
&#x20;       %>
&#x20;       \<tr>
&#x20;           \<td colspan="4" style="padding:8px;text-align\:center;color:#888;">Your basket is empty.\</td>
&#x20;       \</tr>
&#x20;       \<%
&#x20;           }
&#x20;       } catch (e) \{
&#x20;       %>
&#x20;       \<tr>
&#x20;           \<td colspan="4" style="padding:8px;text-align\:center;color\:red;">Error processing basket data: \<%= e.message %>\</td>
&#x20;       \</tr>
&#x20;       \<%
&#x20;           // Log the error in Adobe Campaign's logs for debugging
&#x20;           logInfo("Error processing XML basket data (main loop): " + e.message + " XML: " + xmlString);
&#x20;       }
&#x20;       %>
&#x20;   \</tbody>
&#x20;   \<tfoot>
&#x20;       \<tr>
&#x20;           \<td colspan="3" style="padding:8px;text-align\:right;font-weight\:bold;">Grand Total:\</td>
&#x20;           \<td style="padding:8px;text-align\:right;font-weight\:bold;">\<%= grandTotal.toFixed(2) %>\</td>
&#x20;       \</tr>
&#x20;   \</tfoot>
\</table>

\<p>Thank you for shopping with us!\</p>
:::



![](https://api.archbee.com/api/optimize/bAgVaanSi1tFmfc8PghaH/hPYhGyOHQcfICRjjq1q5Z_cleanshot-2025-06-27-at-103213.png)

## V8: Simulate content

![](https://api.archbee.com/api/optimize/bAgVaanSi1tFmfc8PghaH/j3lny616MIpht-7OnjdqF_cleanshot-2025-06-27-at-103228.png)

Publish the transactional email

## Trigger checkout event

![](https://api.archbee.com/api/optimize/bAgVaanSi1tFmfc8PghaH/iv9CFIx2MqKm6aJzPgXkg_cleanshot-2025-06-27-at-103254.png)

***

**Author**: Marc Meewis, Principal Solutions Consultant

**Source**: [https://git.corp.adobe.com/mmeewis/aep-ajo-camaignv8-integration](https://git.corp.adobe.com/mmeewis/aep-ajo-camaignv8-integration)
