On a recent project, I had the chance to integrate Adobe Experience Manager (AEM) with Adobe Target. More specifically, the goal was to do Experience Targeting (XT) from within AEM’s interface. That means authors in AEM can use the UI they’re accustomed to in order to create offers/experiences for their various user segments/audiences. The end-user then sees the experience that Target deems is most relevant based on what it knows about the user and AEM serves the experience.
While this integration has been around since AEM 6.2, there are several gotchas that I discovered during this project. The following article documents the pitfalls and best practices that enrich existing Adobe documentation and hopefully, help you get the most out of your Adobe investment.
The articles covers:
- Prerequisites
- Enable Targeting in AEM
- Integrating AEM and Adobe Target APIs with Cloud Service Config
- Deploying at.js Using Launch
- Configuring Target Replication Agent
- AEM Author Permission Requirements
- Dispatcher Considerations
- Other Issues That We Have Run Into
- Understanding AEM Integration with Launch By Adobe, Analytics, and Target (videos)
- Integrate Launch by Adobe with AEM Sites (videos)
- Manually Configuring the Integration with Adobe Target
- Managing Audiences and Managing Activities
(Source: https://helpx.adobe.com/marketing-cloud/how-to/aem-target.html)
Prerequisites
- Before even attempting to integrate the two systems, make sure you have access to the following:
- Adobe Target account with sufficient (at least approver-level) access. Make note of the “client code” and keep your username and password handy.
- AEM admin account. In some scenarios, you may not have full admin access because you’re in a locked-down environment or using Adobe Managed Services. In that case, test-run the setup on a lower/local environment and make sure you’re documenting all the changes you’re making so they can be applied by the appropriate system admin later on.
- Access to both the AEM code base as well as the Apache/Dispatcher configs.
Enable Targeting in AEM
Your page component needs to have all the necessary includes supporting cloud services. If you’re using the Page component that ships with the Core components you’re good to go (take a look at headlibs.html and footer.html), just add the include for ContextHub to enable “Targeting” mode in the editor.
===========
<!--/* Include Context Hub */-->
<sly data-sly-resource="${'contexthub' @ resourceType='granite/contexthub/components/contexthub'}"/>
===========
Note, however, the problem that we ran into with enabling this on Publish.
Integrating AEM and Adobe Target APIs with Cloud Service Config
The first step in setting up the AEM Target integration is configuring the Adobe Target cloud service. This is where you establish the actual API connection between the two systems. You will need your client code as well as a username and password.
With 6.4 you can find the config in the Tools menu under Cloud Services > Legacy Cloud Services. It has not been migrated to the new interface yet.
When you set up the config, check the box for “Use DTM to deliver client library” even if you’re using Launch and not DTM. The idea here is that AEM doesn’t have to worry about loading the Target library.
Also, make sure to check “Synchronize segments from Adobe Target.” As the name implies it will sync the segments which allow your authors to use them when building out the experiences.
Deploying at.js Using Launch
There are different ways of deploying the Target library on an AEM website and Adobe Experience Platform Launch (previously just “Adobe Launch,” or “Launch by Adobe”) is the new recommended way of doing this. Adobe has some videos and documentation about this set up so I won’t get into the details here.
One thing worth noting here is that the asynchronous approach didn’t work for us so we chose to use the less ideal synchronous approach with the library loaded at the top and satellite script at the bottom.
Configuring Target Replication Agent
Another important part of the puzzle is configuring the Target Replication Agent. This step is documented here. Note that at least in AEM 6.4 you will still see it being referred to under its previous name “Test and Target.”
Most of the default settings of the replication agent are fine as is, just make sure it’s enabled (with the “nosamplecontent” runmode it’s disabled by default). Also, confirm that the “Agent User Id” is left blank so that the out-of-the-box (OOTB) system user is used. If you see “your_replication_user” as the user ID, remove it.
The replication agent is used to publish activities to Target. Without this, you won’t be able to test the personalization on Publish or with “?wcmmode=disabled." This was a big gotcha for me at the beginning because on AEM Author I always test in “wcm disabled” mode and nothing was working there until things get published to Target.
On the Target side of things, there should be two line items for each activity that you’ve created in AEM, one appended with “_author” and one without:
If you’re seeing only the “_author” one, check and make sure that the replication agent is set up properly. View the logs and confirm that you’re not seeing any errors. There should be “info” statements like this “Creating content for path /content/path/to/page.”
Your page component needs to have all the necessary includes supporting cloud services. If you’re using the Page component that ships with the Core components you’re good to go (take a look at headlibs.html and footer.html), just add the include for ContextHub to enable “Targeting” mode in the editor.
===========
<!--/* Include Context Hub */-->
<sly data-sly-resource="${'contexthub' @ resourceType='granite/contexthub/components/contexthub'}"/>
===========
Note, however, the problem that we ran into with enabling this on Publish.
Integrating AEM and Adobe Target APIs with Cloud Service Config
The first step in setting up the AEM Target integration is configuring the Adobe Target cloud service. This is where you establish the actual API connection between the two systems. You will need your client code as well as a username and password.
With 6.4 you can find the config in the Tools menu under Cloud Services > Legacy Cloud Services. It has not been migrated to the new interface yet.
When you set up the config, check the box for “Use DTM to deliver client library” even if you’re using Launch and not DTM. The idea here is that AEM doesn’t have to worry about loading the Target library.
Also, make sure to check “Synchronize segments from Adobe Target.” As the name implies it will sync the segments which allow your authors to use them when building out the experiences.
Deploying at.js Using Launch
There are different ways of deploying the Target library on an AEM website and Adobe Experience Platform Launch (previously just “Adobe Launch,” or “Launch by Adobe”) is the new recommended way of doing this. Adobe has some videos and documentation about this set up so I won’t get into the details here.
One thing worth noting here is that the asynchronous approach didn’t work for us so we chose to use the less ideal synchronous approach with the library loaded at the top and satellite script at the bottom.
Configuring Target Replication Agent
Another important part of the puzzle is configuring the Target Replication Agent. This step is documented here. Note that at least in AEM 6.4 you will still see it being referred to under its previous name “Test and Target.”
Most of the default settings of the replication agent are fine as is, just make sure it’s enabled (with the “nosamplecontent” runmode it’s disabled by default). Also, confirm that the “Agent User Id” is left blank so that the out-of-the-box (OOTB) system user is used. If you see “your_replication_user” as the user ID, remove it.
The replication agent is used to publish activities to Target. Without this, you won’t be able to test the personalization on Publish or with “?wcmmode=disabled." This was a big gotcha for me at the beginning because on AEM Author I always test in “wcm disabled” mode and nothing was working there until things get published to Target.
On the Target side of things, there should be two line items for each activity that you’ve created in AEM, one appended with “_author” and one without:
If you’re seeing only the “_author” one, check and make sure that the replication agent is set up properly. View the logs and confirm that you’re not seeing any errors. There should be “info” statements like this “Creating content for path /content/path/to/page.”
AEM Author Permission Requirements
In order to create brands, campaigns, activities, and offers you will need a user group with the following permissions configured.
Read/modify/create/delete/replicate on these paths:
Dispatcher Considerations
Most AEM sites use the Apache HTTP server to rewrite incoming requests so that users don’t need to type in the AEM internal paths (e.g. “/content/path/to/website”) into their address bar. It’s also very common to remove the trailing “.html” from the URL.
Both of these have to be considered to ensure that requests to the default as well as personalized offers are routed properly. Also, check your filter rules to confirm that they are not blocked.
Example rewrite condition to exclude the offer URLs from your rewrites:
===========
RewriteCond %{REQUEST_URI} (default|tandt)\.html$
===========
Also, make sure that the ContextHub and any other JS you may have associated with it, is allowed by your rewrites and filters.
In order to create brands, campaigns, activities, and offers you will need a user group with the following permissions configured.
Read/modify/create/delete/replicate on these paths:
- /content/campaigns/
- /etc/cloudservices/testandtarget/
- /etc/segmentation/adobe-target/
Dispatcher Considerations
Most AEM sites use the Apache HTTP server to rewrite incoming requests so that users don’t need to type in the AEM internal paths (e.g. “/content/path/to/website”) into their address bar. It’s also very common to remove the trailing “.html” from the URL.
Both of these have to be considered to ensure that requests to the default as well as personalized offers are routed properly. Also, check your filter rules to confirm that they are not blocked.
Example rewrite condition to exclude the offer URLs from your rewrites:
===========
RewriteCond %{REQUEST_URI} (default|tandt)\.html$
===========
Also, make sure that the ContextHub and any other JS you may have associated with it, is allowed by your rewrites and filters.
Other Issues That We Have Run Into
Activity Creation Modal
The dialog box to create a new activity acted a little strange for us in AEM 6.4.2. When first opened, the dropdown for “Select a Target Configuration” and “Activity type” is grayed out but when closed and opened again, they show up fine and are selectable.
We have not found the solution for this yet but with the “workaround” we’re at least able to create activities as necessary.
Activity Creation Modal
The dialog box to create a new activity acted a little strange for us in AEM 6.4.2. When first opened, the dropdown for “Select a Target Configuration” and “Activity type” is grayed out but when closed and opened again, they show up fine and are selectable.
We have not found the solution for this yet but with the “workaround” we’re at least able to create activities as necessary.
Synchronization With Target Fails
This is an error we got when trying to save everything in the editor:
The solution here was a permission fix Adobe had to make for us on their end. If you run into this, file a ticket and they can get it taken care of.
Another issue that I've seen is this: "The values for 'email' and 'password' parameters cannot be blank unless there is an IMS token in the Authorization header or Basic Authentication is used or userId+orgId IMS headers are present."
This showed up even though the IMS configuration was set and the Launch cloud-config was configured properly to use the IMS token. The solution here was to re-enter the password in the Target cloud-config because somehow the field had got wiped out. This error message threw me off because the IMS config isn’t even used for this part of the integration as far as I can see.
This is an error we got when trying to save everything in the editor:
The solution here was a permission fix Adobe had to make for us on their end. If you run into this, file a ticket and they can get it taken care of.
Another issue that I've seen is this: "The values for 'email' and 'password' parameters cannot be blank unless there is an IMS token in the Authorization header or Basic Authentication is used or userId+orgId IMS headers are present."
This showed up even though the IMS configuration was set and the Launch cloud-config was configured properly to use the IMS token. The solution here was to re-enter the password in the Target cloud-config because somehow the field had got wiped out. This error message threw me off because the IMS config isn’t even used for this part of the integration as far as I can see.
Uncaught ReferenceError: CQ_Analytics is not defined
Make sure there’s a snippet in the <head> defining “CQ_Analytics” and “CQ_Analytics.TestTarget”. If it’s not there, it could be that the Target cloud service config is not assigned to the page you’re on. It’s also common to have the config assigned to the root page. In that case, make sure the root page got published so that all the descendant pages can inherit their config from it.
Make sure there’s a snippet in the <head> defining “CQ_Analytics” and “CQ_Analytics.TestTarget”. If it’s not there, it could be that the Target cloud service config is not assigned to the page you’re on. It’s also common to have the config assigned to the root page. In that case, make sure the root page got published so that all the descendant pages can inherit their config from it.
“Uncaught TypeError: Cannot read property 'externalize' of undefined” / “TypeError: Granite.HTTP is undefined”
Check that you’re including the “granite.utils” clientlib. You can either do that with a separate clientlib include or just make it a dependency for your main site client lib that’s already being included everywhere.
Check that you’re including the “granite.utils” clientlib. You can either do that with a separate clientlib include or just make it a dependency for your main site client lib that’s already being included everywhere.
Browser Testing
Be aware that you may see different behavior depending on which browser and browser mode you’re testing with. For example, private windows in Firefox block DTM and Launch. It’s fine in Chrome’s incognito windows, though.
Be aware that you may see different behavior depending on which browser and browser mode you’re testing with. For example, private windows in Firefox block DTM and Launch. It’s fine in Chrome’s incognito windows, though.
Backend Integration Logs
If part of the integration isn’t quite doing what it’s supposed to, it can help to review the messages that the Target implementation logs. To do that, create a Logger for the package: “com.day.cq.analytics.testandtarget.impl”.
For Example:
If part of the integration isn’t quite doing what it’s supposed to, it can help to review the messages that the Target implementation logs. To do that, create a Logger for the package: “com.day.cq.analytics.testandtarget.impl”.
For Example:
Components Need to Support Targeting
Some specific things to look out for:
Don’t rely on a specific <div> structure outside of what’s in your component’s HTL file. That’s all fair game for AEM and the Target component to modify. For example, we had relied on the standard component <div> with the CSS class with the component name which when targeted is not there anymore.
If your component has some JS that runs on page load, like setting up a slider/carousel/etc., it may have to get re-initialized since AEM will load in your offer HTML but if the JS already ran on page load, it by default wouldn’t run again when all the Ajax requests for offers are done. Here’s an example for the “adobe.target.event.REQUEST_SUCCEEDED” event that you can listen to and here’s a list of all the available events that you can act on.
When using VueJS in your components, be aware that it creates a virtual DOM that it interacts with. AEM targeting just appends/deletes HTML snippets it gets from the offers and that conflicts with Vue. To get around this, delay initializing Vue until the offer is completely loaded. [Thanks to Ryan Keenan for this tip!]
Some specific things to look out for:
Don’t rely on a specific <div> structure outside of what’s in your component’s HTL file. That’s all fair game for AEM and the Target component to modify. For example, we had relied on the standard component <div> with the CSS class with the component name which when targeted is not there anymore.
If your component has some JS that runs on page load, like setting up a slider/carousel/etc., it may have to get re-initialized since AEM will load in your offer HTML but if the JS already ran on page load, it by default wouldn’t run again when all the Ajax requests for offers are done. Here’s an example for the “adobe.target.event.REQUEST_SUCCEEDED” event that you can listen to and here’s a list of all the available events that you can act on.
When using VueJS in your components, be aware that it creates a virtual DOM that it interacts with. AEM targeting just appends/deletes HTML snippets it gets from the offers and that conflicts with Vue. To get around this, delay initializing Vue until the offer is completely loaded. [Thanks to Ryan Keenan for this tip!]
ContextHub Slows Down the Site
According to the Adobe documentation, ContextHub needs to be included in order to enable the “Targeting” mode in the AEM authoring interface. However, on AEM Publish we saw some issues with ContextHub slowing down our page requests and even bringing the server to a crawl.
For our use case, since we’re not actually leveraging ContextHub for personalization, we disabled it in Publish and don’t even load all the associated JavaScript files that slow things down.
According to the Adobe documentation, ContextHub needs to be included in order to enable the “Targeting” mode in the AEM authoring interface. However, on AEM Publish we saw some issues with ContextHub slowing down our page requests and even bringing the server to a crawl.
For our use case, since we’re not actually leveraging ContextHub for personalization, we disabled it in Publish and don’t even load all the associated JavaScript files that slow things down.
Custom Link Rewriters/Transformers
If you have a custom link rewriter, make sure to add your respective “/content/campaigns/*” path to the list of allowed paths that it acts on. I noticed that the rewriter wasn’t acting on our offers so links would still include “/content/path/to/site” as well as have the “HTML” file extension.
If you have a custom link rewriter, make sure to add your respective “/content/campaigns/*” path to the list of allowed paths that it acts on. I noticed that the rewriter wasn’t acting on our offers so links would still include “/content/path/to/site” as well as have the “HTML” file extension.
Targeting Mode Doesn't Show Up
If you don’t see “Targeting” as an option in the editor dropdown, make sure you have the ContextHub snippet from above included. Also, check and make sure the "ContextHub Configurations" in the page properties of your page (or further up in the hierarchy) are set correctly (mine had a wrong path at some point which caused issues.).
If you don’t see “Targeting” as an option in the editor dropdown, make sure you have the ContextHub snippet from above included. Also, check and make sure the "ContextHub Configurations" in the page properties of your page (or further up in the hierarchy) are set correctly (mine had a wrong path at some point which caused issues.).
"Choose Audience" Dialog is Empty
Check under "Personalization > Audiences" and the appropriate folder that audiences/segments were properly synced from Target. In my case that was into the "/etc/segmentation/adobe-target" folder. You can see where this is stored in the "segmentsPollConfig" under your Target cloud-config node. Also, make sure you use "Adobe Target" as the Targeting engine instead of "ContextHub," otherwise it will try to pull the audience from the wrong folder.
Check under "Personalization > Audiences" and the appropriate folder that audiences/segments were properly synced from Target. In my case that was into the "/etc/segmentation/adobe-target" folder. You can see where this is stored in the "segmentsPollConfig" under your Target cloud-config node. Also, make sure you use "Adobe Target" as the Targeting engine instead of "ContextHub," otherwise it will try to pull the audience from the wrong folder.
A Note About Using at.js 2.x
Adobe Launch now has the option to select the new version of the Target library and I've had a chance to try this out. The first thing that got me was the lack of "mbox" requests in the network panel so I thought it wasn't working properly. However, this is on purpose because the at.js 2.x uses a new Delivery API, and also the global mbox isn’t used anymore. Instead, you can now filter by "delivery" or "tt.omtrdc.net" to see Target requests. If you're considering using the new version, definitely check out the migration guide here.
Adobe Launch now has the option to select the new version of the Target library and I've had a chance to try this out. The first thing that got me was the lack of "mbox" requests in the network panel so I thought it wasn't working properly. However, this is on purpose because the at.js 2.x uses a new Delivery API, and also the global mbox isn’t used anymore. Instead, you can now filter by "delivery" or "tt.omtrdc.net" to see Target requests. If you're considering using the new version, definitely check out the migration guide here.
Summary
The integration between AEM and Target seems fairly straight forward but there are a few things to be aware of. As with any integration, it becomes tricky when something doesn’t quite work as it’s documented (or it’s not documented at all).
Happy integration!
The integration between AEM and Target seems fairly straight forward but there are a few things to be aware of. As with any integration, it becomes tricky when something doesn’t quite work as it’s documented (or it’s not documented at all).
Happy integration!
No comments:
Post a Comment
If you have any doubts or questions, please let us know.