Goal
Solution
Setup IMS in AEM for Target Integration
Tools > Security > Adobe IMS Configurations
1. Create a Certificate in AEM...
2. Upload Certificate in https://console.adobe.io
3. Continue the IMS integration in AEM...
4. Provide the necessary permissions for Integration in Admin Console. Without this you might see the following error when exporting XFs to Target...
Caused by: com.day.cq.analytics.testandtarget.impl.service.WebServiceException: Unexpected response status code [403] for request [https://mc.adobe.io/ags959/target/offers/content?includeMarketingCloudMetadata=true].{"httpStatus":403,"requestId":"SKeC0FKYUiWHkDxi2D47KS33xMkRKpdy","requestTime":"2021-06-15T17:12:51.320578Z","errors":[{"errorCode":"Forbidden.Resource","message":"Access denied. To perform this operation, all of the following privileges are required \"[editor]\".","meta":{}}]}at com.day.cq.analytics.testandtarget.impl.service.WebServiceImpl.request(WebServiceImpl.java:610) [com.adobe.cq.cq-target-integration:1.4.30]... 163 common frames omitted
Create Target Integration using IMS
Tools > Cloud Services > Legacy Cloud Services > Adobe Target
Create Geo XF SPA Component in AEM
1) Create the project using following maven command
mvn -B archetype:generate -D archetypeGroupId=com.adobe.aem -D archetypeArtifactId=aem-project-archetype -D archetypeVersion=30 -D aemVersion=cloud -D appTitle="Experience AEM SPA Geo Targeting" -D appId="eaem-spa-geo-target" -D groupId="apps.experienceaem.sites" -D frontendModule=react -D includeExamples=n -D includeDispatcherConfig=y
3) Add the component render script in eaem-spa-geo-target\ui.frontend\src\components\geo-xf\geo-xf.tsx
import {MappedComponentProperties, MapTo} from "@adobe/aem-react-editable-components"; import React, { FC, useState } from "react"; import Helmet from "react-helmet"; import useScript from 'react-script-hook'; import {AuthoringUtils} from "@adobe/aem-spa-page-model-manager"; const GeoXFConfig = { emptyLabel: "Geo XF - Experience AEM", isEmpty: function (props: any) { return !props; } }; type GeoXFProps = MappedComponentProperties & { mboxName ?: string; } const isInProxyOrAuthoring = () => process.env.REACT_APP_PROXY_ENABLED || AuthoringUtils.isInEditor() || (window.location.search.indexOf("wcmmode=disabled") !== -1) const GeoXF: FC<GeoXFProps> = props => { // @ts-ignore window.targetGlobalSettings = { cookieDomain: window.location.hostname }; const [html, setHtml] = useState("<div>Loading...</div>"); const successFn = (offer : any) => { const offerJSON = JSON.parse(offer[0].content); if (!offerJSON.xfHtmlPath) { setHtml("<div>Target Error loading offer : xfHtmlPath not available</div>"); return; } let xfHtmlPath = offerJSON.xfHtmlPath; if(isInProxyOrAuthoring()){ xfHtmlPath = xfHtmlPath.substring(xfHtmlPath.indexOf("/content")); } const respPromise = process.env.REACT_APP_PROXY_ENABLED ? fetch(xfHtmlPath, { credentials: 'same-origin', headers: { 'Authorization': process.env.REACT_APP_AEM_AUTHORIZATION_HEADER } as any }): fetch(xfHtmlPath); respPromise.then( response => response.text()).then( (html) => setHtml(html)) } useScript({ src: '/etc.clientlibs/eaem-spa-geo-target/clientlibs/clientlib-react/resources/at.js', onload: () => { // @ts-ignore window.adobe.target.getOffer({ mbox: props.mboxName || 'eaem-state-flag-box', success: successFn, error: () => setHtml("<div>Target Error loading offer</div>") }) } }); return ( <> <Helmet> <link rel="preconnect" href="//ags959.tt.omtrdc.net?lang=en"/> <link rel="dns-prefetch" href="//ags959.tt.omtrdc.net?lang=en"/> </Helmet> <div dangerouslySetInnerHTML={{ __html: html }} /> </> ); } export default MapTo('eaem-spa-geo-target/components/geo-xf')(GeoXF, GeoXFConfig);
4) In above script the following snippet sets the Target cookieDomain to cloud service instance sub domain eg. publish-p10961-e90064.adobeaemcloud.com
cookieDomain: window.location.hostname
};
VM21:1 AT: [getOffer()] Adobe Target content delivery is disabled. Ensure that you can save cookies to your current domain, there is no "mboxDisable" cookie and there is no "mboxDisable" parameter in query string.
4) Integrating Target with Launch is the right way to load Target in your app (check documentation) however to keep things simple lets download the Target lib file at.js from your Adobe Target account (check documentation) and add it in the app public folder eaem-spa-geo-target\ui.frontend\public\at.js. When the app is built (npm run build) its copied to /apps/eaem-spa-geo-target/clientlibs/clientlib-react/resources/at.js
Create Personalization Blocks - Experience Fragments
1) Personalization blocks shown on page (welcome message and flag image) are created as Experience Fragments (XF). To facilitate this, create a template type /conf/eaem-spa-geo-target/settings/wcm/template-types/geo-xf and template /conf/eaem-spa-geo-target/settings/wcm/templates/geo-targeting-xf with page sling:resourceType set to eaem-spa-geo-target/components/xfpage (this template uses HTL Core Components for generating the XF html server side injected into the Geo React component)
2) Set the Target Integration configuration in XF structure /content/experience-fragments/eaem-spa-geo-target/us/en/site
3) Create a filter apps.experienceaem.assets.core.filters.ExperienceFragmentJSONOfferFilter with the following code to modify the product model.json response, and provide the publish url of XF...
eg. https://publish-p10961-e90064.adobeaemcloud.com/content/experience-fragments/eaem-spa-geo-target/us/en/site/utah.model.json
{
}
package apps.experienceaem.assets.core.filters; import com.day.cq.commons.Externalizer; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.resource.ResourceResolver; import org.apache.sling.commons.json.JSONObject; import org.osgi.framework.Constants; import org.osgi.service.component.annotations.Component; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.*; import java.io.IOException; @Component( service = Filter.class, immediate = true, name = "Experience AEM - Change offer JSON exported to Target", property = { Constants.SERVICE_RANKING + ":Integer=-99", "sling.filter.scope=COMPONENT", "sling.filter.pattern=(/content/experience-fragments/.*.model.json)", } ) public class ExperienceFragmentJSONOfferFilter implements Filter { private static final Logger log = LoggerFactory.getLogger(ExperienceFragmentJSONOfferFilter.class); @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request; try { String uri = slingRequest.getRequestURI(); if(!uri.endsWith(".model.json")){ chain.doFilter(request, response); return; } JSONObject model = new JSONObject(); String masterXFPath = uri.substring(0,uri.lastIndexOf(".model.json")); masterXFPath = masterXFPath + ".html"; ResourceResolver resolver = slingRequest.getResourceResolver(); Externalizer externalizer = resolver.adaptTo(Externalizer.class); model.put("xfHtmlPath", externalizer.publishLink(resolver, masterXFPath)); response.getWriter().print(model); } catch (Exception e) { log.error("Error getting json offer response : " + slingRequest.getRequestURI()); } } @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { } }
4) Create XFs for various states Texas, California, Utah, US etc. and Export to Target (Also, Activate the XF page so its accessible from publish instance eg. https://publish-p10961-e90064.adobeaemcloud.com/content/experience-fragments/eaem-spa-geo-target/us/en/site/utah/master.html)
Create the Target Activity
1) The XF exported from AEM is added in Adobe Target as an Offer.
2) Create the Audiences for your Experience Activity eg. https://experience.adobe.com/#/@ags959/target/audiences
3) Create the necessary experiences in your Target Activity
4) Map the Audiences to Experiences (each one set to the respective XF offer)
5) The individual personalized experiences are available in the Activity QA of the Activity
6) Report of how the Experiences are doing is available in the Reports section of Activity...
No comments:
Post a Comment