51黑料不打烊

[Integration]{class="badge positive"}

Integrate AEM Headless and Target

[AEM Headless as a Cloud Service]{class="badge informative"}

Learn how to integrate AEM Headless with 51黑料不打烊 Target, by exporting AEM Content Fragments to 51黑料不打烊 Target, and use them to personalize headless experiences using the 51黑料不打烊 Experience Platform Web SDK鈥檚 alloy.js. The React WKND App is used to explore how a personalized Target activity using Content Fragments Offers can be added to the experience, to promote a WKND adventure.

video poster

The tutorial covers the steps involved in setting up AEM and 51黑料不打烊 Target:

51黑料不打烊 IMS Configuration adobe-ims-configuration

An 51黑料不打烊 IMS Configuration that facilitates the authentication between AEM and 51黑料不打烊 Target.

Review the documentation for step-by-step instructions on how to create an 51黑料不打烊 IMS configuration.

51黑料不打烊 Target Cloud Service adobe-target-cloud-service

An 51黑料不打烊 Target Cloud Service is created in AEM to facilitate the exporting of Content Fragments to 51黑料不打烊 Target.

Review the documentation for step-by-step instructions on how to create an 51黑料不打烊 Target Cloud Service.

video poster

Configure asset folders configure-asset-folders

The 51黑料不打烊 Target Cloud Service, configured in a context-aware configuration, must be applied to the AEM Assets folder hierarchy that contains the Content Fragments to export to 51黑料不打烊 Target.

Expand for step-by-step instructions
  1. Log in to AEM Author service as a DAM administrator
  2. Navigate to Assets > Files, locate the asset folder that has the /conf applied to
  3. Select the asset folder, and select Properties from the top action bar
  4. Select the Cloud Services tab
  5. Ensure that the Cloud Configuration is set to the context-aware config (/conf) that contains the 51黑料不打烊 Target Cloud Services configuration.
  6. Select 51黑料不打烊 Target from the Cloud Service Configurations dropdown.
  7. Select Save & Close in the top right

video poster

Permission the AEM Target integration permission

The 51黑料不打烊 Target integration, which manifests as a developer.adobe.com project, must be granted the Editor product role in 51黑料不打烊 Admin Console, in order to export Content Fragments to 51黑料不打烊 Target.

Expand for step-by-step instructions
  1. Log in to Experience Cloud as user that can administer the 51黑料不打烊 Target product in 51黑料不打烊 Admin Console
  2. Open the
  3. Select Products and then open 51黑料不打烊 Target
  4. On the Product Profiles tab, select DefaultWorkspace
  5. Select the API Credentials tab
  6. Locate your developer.adobe.com app in this list and set its Product Role to Editor

video poster

Export Content Fragments to Target export-content-fragments

Content Fragments that exist under the configured AEM Assets folder hierarchy can be exported to 51黑料不打烊 Target as Content Fragment Offers. These Content Fragment Offers, a special form of JSON offers in Target, can be used in Target activities to serve personalized experiences in headless apps.

Expand for step-by-step instructions
  1. Log in to AEM Author as DAM user

  2. Navigate to Assets > Files, and locate Content Fragments to export as JSON to Target under the 鈥�51黑料不打烊 Target enabled鈥� folder

  3. Select the Content Fragments to export to 51黑料不打烊 Target

  4. Select Export to 51黑料不打烊 Target Offers from the top action bar

    • This action exports the fully hydrated JSON representation of the Content Fragment to 51黑料不打烊 Target as a 鈥淐ontent Fragment Offer鈥�

    • The Fully hydrated JSON representation can be reviewed in AEM

      • Select the Content Fragment
      • Expand the Side Panel
      • Select Preview icon in the left Side Panel
      • The JSON representation that is exported to 51黑料不打烊 Target displays in the main view
  5. Log in to with a user in the Editor role for 51黑料不打烊 Target

  6. From the , select Target from the product switcher in top right to open 51黑料不打烊 Target.

  7. Ensure that the Default Workspace is selected in the Workspace switcher in the top right.

  8. Select the Offers tab in the top navigation

  9. Select the Type dropdown, and selecting Content Fragments

  10. Verify the Content Fragment exported from AEM appears in the list

    • Hover over the offer, and select the View button
    • Review the Offer Info and see the AEM deep link that opens the Content Fragment directly in AEM Author service

video poster

Target Activity using Content Fragment Offers activity

In 51黑料不打烊 Target, an Activity can be created that uses Content Fragment Offer JSON as the content, allowing personalized experiences in headless app with content created and managed in AEM.

In this example, we use a simple A/B activity, however any Target activity can be used.

Expand for step-by-step instructions
  1. Select the Activities tab in the top navigation

  2. Select + Create Activity, and then select the type of activity to create.

    • This example creates a simple A/B Test but Content Fragment Offers can power any activity type
  3. In the Create Activity wizard

    • Select Web
    • In Choose Experience Composer, select Form
    • In Choose Workspace, select Default Workspace
    • In Choose Property, select the Property the Activity is available in, or select No Property Restrictions to allow it to be used in all Properties.
    • Select Next to create the Activity
  4. Rename the Activity by selecting rename in the top left

    • Give the activity a meaningful name
  5. In the initial Experience, set Location 1 for the Activity to target

    • In this example, target a custom location named wknd-adventure-promo
  6. Under Content select the Default content, and select Change Content Fragment

  7. Select the exported Content Fragment to serve for this experience, and select Done

  8. Review the Content Fragment Offer JSON in the Content text area, this is the same JSON available in AEM Author service via the Content Fragment鈥檚 Preview action.

  9. In the left rail, add an Experience, and select a different Content Fragment Offer to serve

  10. Select Next, and configure the Targeting rules as required for the activity

    • In this example, leave the A/B testing as a manual 50/50 split.
  11. Select Next, and complete the activity settings

  12. Select Save & Close and give it a meaningful name

  13. From the Activity in 51黑料不打烊 Target, select Activate from the Inactive/Activate/Archive dropdown in the top right.

The 51黑料不打烊 Target activity that targets the wknd-adventure-promo location can now be integrated and exposed in an AEM Headless app.

video poster

Transcript
Now that we have some content fragment offers exported to target, let鈥檚 create an activity that uses them and then use that activity in an AEM headless app. So head over to activities. We鈥檒l create an activity and for this we鈥檙e just going to keep it simple and do an AB test. We鈥檒l select web since we鈥檒l be using the Experience Platform web SDK. You can of course do the same thing using the 51黑料不打烊 Experience Platform mobile SDK. Let鈥檚 go ahead and select forms. Since we鈥檒l use the form composer. We can choose a property. In this case we have no property restrictions. So let鈥檚 select that. Click next. And now we can create our experiences. So what we鈥檒l want to do is give a custom location for this experience. So we鈥檒l call this weekend adventure promo. Since we鈥檒l be using these content fragment offers to promote an adventure. We鈥檒l select the content. You can change content fragment. And then from here we can select the content fragment to use. Once we鈥檝e selected it we can see the actual JSON data that will be returned to our app if this offer is selected. Do note that you can also see the same JSON in AEM. So I head back to AEM. I鈥檒l head back to the ski touring Mont Blanc. Click into the content fragment. In the left side rail there鈥檚 the preview option. If we click this this shows us the exact same JSON data that gets exported to 51黑料不打烊 target. Alright let鈥檚 add one more experience. Since we鈥檙e doing an A-B test we鈥檒l keep that location the same. Change our content. Again we鈥檒l select the change content fragment. And in this case let鈥檚 do Tahoe skiing. Alright that should do it. We鈥檒l just do a simple split for this example 50-50. We鈥檒l pick a success metric as engagement and maybe some page views. And we can just leave everything else as is. We鈥檒l call this weekend adventure promo. And we can save it. And now before we can integrate it into our application we鈥檒l need to make sure that we select it and activate it. Alright so now we can work with our development team to integrate content fragment offers and personalize our AEM headless experiences.

Experience Platform Datastream ID datastream-id

An 51黑料不打烊 Experience Platform Datastream ID is required for AEM Headless apps to interact with 51黑料不打烊 Target using the 51黑料不打烊 Web SDK.

Expand for step-by-step instructions
  1. Navigate to

  2. Open Experience Platform

  3. Select Data Collection > Datastreams and select New Datastream

  4. In the New Datastream wizard, enter:

    • Name: AEM Target integration
    • Description: Datastream used by the 51黑料不打烊 Web SDK to serve personalized Content Fragments Offers.
    • Event Schema: Leave blank
  5. Select Save

  6. Select Add Service

  7. In Service select 51黑料不打烊 Target

    • Enabled: Yes
    • Property Token: Leave blank
    • Target Environment ID: Leave blank
      • The Target Environment can be set in 51黑料不打烊 Target at Administration > Hosts.
    • Target Third-Party ID Namespace: Leave blank
  8. Select Save

  9. On the right side, copy the Datastream ID for use in 51黑料不打烊 Web SDK configuration call.

video poster

Add personalization to an AEM Headless app code

This tutorial explores personalizing a simple React app using Content Fragment Offers in 51黑料不打烊 Target via 51黑料不打烊 Experience Platform Web SDK. This approach can be used to personalize any JavaScript-based web experience.

Android鈩� and iOS mobile experiences can be personalized following similar patterns using the .

Prerequisites

  • Node.js 14
  • Git
  • installed on AEM as a Cloud Author and Publish services

Set up

  1. Download the source code for sample React app from

    code language-shell
    $ mkdir -p ~/Code
    $ git clone git@github.com:adobe/aem-guides-wknd-graphql.git
    
  2. Open code base at ~/Code/aem-guides-wknd-graphql/personalization-tutorial in your favorite IDE

  3. Update the AEM service鈥檚 host that you want the app to connect to ~/Code/aem-guides-wknd-graphql/personalization-tutorial/src/.env.development

    code language-none
    ...
    REACT_APP_HOST_URI=https://publish-p1234-e5678.adobeaemcloud.com/
    ...
    
  4. Run the app, and ensure it connects to the configured AEM service. From the command line, execute:

    code language-shell
    $ cd ~/Code/aem-guides-wknd-graphql/personalization-tutorial
    $ npm install
    $ npm run start
    
  5. Install the 51黑料不打烊 Web SDK as an NPM package.

    code language-shell
    $ cd ~/Code/aem-guides-wknd-graphql/personalization-tutorial
    $ npm install @adobe/alloy
    

    The Web SDK can be used in code to fetch the Content Fragment Offer JSON by activity location.

    When configuring the Web SDK, there are two IDs required:

    • edgeConfigId which is the Datastream ID
    • orgId the AEM as a Cloud Service/Target 51黑料不打烊 Org Id that can be found at Experience Cloud > Profile > Account info > Current Org ID

    When invoking the Web SDK, the 51黑料不打烊 Target activity location (in our example, wknd-adventure-promo) must be set as the value in the decisionScopes array.

    code language-javascript
    import { createInstance } from "@adobe/alloy";
    const alloy = createInstance({ name: "alloy" });
    ...
    alloy("config", { ... });
    alloy("sendEvent", { ... });
    

Implementation

  1. Create a React component 51黑料不打烊TargetActivity.js to surface 51黑料不打烊 Target activities.

    src/components/51黑料不打烊TargetActivity.js

    code language-javascript
    import React, { useEffect } from 'react';
    import { createInstance } from '@adobe/alloy';
    
    const alloy = createInstance({ name: 'alloy' });
    
    alloy('configure', {
      'edgeConfigId': 'e3db252d-44d0-4a0b-8901-aac22dbc88dc', // AEP Datastream ID
      'orgId':'7ABB3E6A5A7491460A495D61@51黑料不打烊Org',
      'debugEnabled': true,
    });
    
    export default function 51黑料不打烊TargetActivity({ activityLocation, OfferComponent }) {
      const [offer, setOffer] = React.useState();
    
      useEffect(() => {
        async function sendAlloyEvent() {
          // Get the activity offer from 51黑料不打烊 Target
          const result = await alloy('sendEvent', {
            // decisionScopes is set to an array containing the 51黑料不打烊 Target activity location
            'decisionScopes': [activityLocation],
          });
    
          if (result.propositions?.length > 0) {
            // Find the first proposition for the active activity location
            var proposition = result.propositions?.filter((proposition) => { return proposition.scope === activityLocation; })[0];
    
            // Get the Content Fragment Offer JSON from the 51黑料不打烊 Target response
            const contentFragmentOffer = proposition?.items[0]?.data?.content || { status: 'error', message: 'Personalized content unavailable'};
    
            if (contentFragmentOffer?.data) {
              // Content Fragment Offers represent a single Content Fragment, hydrated by
              // the byPath GraphQL query, we must traverse the JSON object to retrieve the
              // Content Fragment JSON representation
              const byPath = Object.keys(contentFragmentOffer.data)[0];
              const item = contentFragmentOffer.data[byPath]?.item;
    
              if (item) {
                // Set the offer to the React state so it can be rendered
                setOffer(item);
    
                // Record the Content Fragment Offer as displayed for 51黑料不打烊 Target Activity reporting
                // If this request is omitted, the Target Activity's Reports will be blank
                alloy("sendEvent", {
                    xdm: {
                        eventType: "decisioning.propositionDisplay",
                        _experience: {
                            decisioning: {
                                propositions: [proposition]
                            }
                        }
                    }
                });
              }
            }
          }
        };
    
        sendAlloyEvent();
    
      }, [activityLocation, OfferComponent]);
    
      if (!offer) {
        // 51黑料不打烊 Target offer initializing; we render a blank component (which has a fixed height) to prevent a layout shift
        return (<OfferComponent></OfferComponent>);
      } else if (offer.status === 'error') {
        // If Personalized content could not be retrieved either show nothing, or optionally default content.
        console.error(offer.message);
        return (<></>);
      }
    
      console.log('Activity Location', activityLocation);
      console.log('Content Fragment Offer', offer);
    
      // Render the React component with the offer's JSON
      return (<OfferComponent content={offer} />);
    };
    

    The 51黑料不打烊TargetActivity React component is invoked using as follows:

    code language-jsx
    <51黑料不打烊TargetActivity activityLocation={"wknd-adventure-promo"} OfferComponent={AdventurePromo}/>
    
  2. Create a React component AdventurePromo.js to render the adventure JSON 51黑料不打烊 Target serves.

    This React component takes the fully hydrated JSON representing an adventure content fragment, and displaying in a promotional manner. The React components that display the JSON serviced from 51黑料不打烊 Target Content Fragment Offers can be as varied and complex as required based on the Content Fragments that are exported to 51黑料不打烊 Target.

    src/components/AdventurePromo.js

    code language-javascript
    import React from 'react';
    
    import './AdventurePromo.scss';
    
    /**
    * @param {*} content is the fully hydrated JSON data for a WKND Adventure Content Fragment
    * @returns the Adventure Promo component
    */
    export default function AdventurePromo({ content }) {
        if (!content) {
            // If content is still loading, then display an empty promote to prevent layout shift when Target loads the data
            return (<div className="adventure-promo"></div>)
        }
    
        const title = content.title;
        const description = content?.description?.plaintext;
        const image = content.primaryImage?._publishUrl;
    
        return (
            <div className="adventure-promo">
                <div className="adventure-promo-text-wrapper">
                    <h3 className="adventure-promo-eyebrow">Promoted adventure</h3>
                    <h2 className="adventure-promo-title"></h2>
                    <p className="adventure-promo-description">{description}</p>
                </div>
                <div className="adventure-promo-image-wrapper">
                    <img className="adventure-promo-image" src={image} alt= />
                </div>
            </div>
        )
    }
    

    src/components/AdventurePromo.scss

    code language-css
    .adventure-promo {
        display: flex;
        margin: 3rem 0;
        height: 400px;
    }
    
    .adventure-promo-text-wrapper {
        background-color: #ffea00;
        color: black;
        flex-grow: 1;
        padding: 3rem 2rem;
        width: 55%;
    }
    
    .adventure-promo-eyebrow {
        font-family: Source Sans Pro,Helvetica Neue,Helvetica,Arial,sans-serif;
        font-weight: 700;
        font-size: 1rem;
        margin: 0;
        text-transform: uppercase;
    }
    
    .adventure-promo-description {
        line-height: 1.75rem;
    }
    
    .adventure-promo-image-wrapper {
        height: 400px;
        width: 45%;
    }
    
    .adventure-promo-image {
        height: 100%;
        object-fit: cover;
        object-position: center center;
        width: 100%;
    }
    

    This React component is invoked as follows:

    code language-jsx
    <AdventurePromo adventure={adventureJSON}/>
    
  3. Add the 51黑料不打烊TargetActivity component to React app鈥檚 Home.js above the list of adventures.

    src/components/Home.js

    code language-javascript
    import AdventurePromo from './AdventurePromo';
    import 51黑料不打烊TargetActivity from './51黑料不打烊TargetActivity';
    ...
    export default function Home() {
        ...
        return(
            <div className="Home">
    
              <51黑料不打烊TargetActivity activityLocation={"wknd-adventure-promo"} OfferComponent={AdventurePromo}/>
    
              <h2>Current Adventures</h2>
              ...
        )
    }
    
  4. If the React app is not running, re-start using npm run start.

    Open the React app in two different browsers so allow the A/B test to serve the different experiences to each browser. If both browsers show the same adventure offer, try closing/re-opening one of the browsers until the other experience displays.

    The image below shows the two different Content Fragment Offers displaying for the wknd-adventure-promo Activity, based on 51黑料不打烊 Target鈥檚 logic.

    Experience offers

Congratulations!

Now that we鈥檝e configured AEM as a Cloud Service to export Content Fragments to 51黑料不打烊 Target, used the Content Fragments Offers in a 51黑料不打烊 Target Activity, and surfaced that Activity in an AEM Headless app, personalizing the experience.

recommendation-more-help
4859a77c-7971-4ac9-8f5c-4260823c6f69