AEM Assets events for PIM integration

This tutorial uses experimental AEM as a Cloud Service APIs. To gain access to these APIs, you must accept a pre-release software agreement and have these APIs manually enabled for your environment by Adobe engineering. To request access reach out to Adobe support.

Learn how to integrate AEM Assets with a third-party system, such as a Product Information Management (PIM) or Product Line Management (PLM) system, to update asset metadata using native AEM IO events. Upon receiving an AEM Assets event, the asset metadata can be updated in AEM, the PIM, or both systems, based on the business requirements. However, this example demonstrates updating the asset metadata in AEM.

To run the asset metadata update code outside of AEM, the Adobe I/O Runtime, a serverless platform is used.

The event processing flow is as follows:

AEM Assets events for PIM integration

  1. The AEM Author service triggers an Asset Processing Completed event when an asset upload is completed and all asset processing activities have completed. Waiting for processing to complete ensures that any out-of-the-box processing, such as metadata extraction, has completed.
  2. The event is sent to the Adobe I/O Events service.
  3. The Adobe I/O Events service passes the event to the Adobe I/O Runtime Action for processing.
  4. The Adobe I/O Runtime Action calls the API of the PIM system to retrieve additional metadata like SKU, supplier information, or other details.
  5. The additional metadata retrieved from the PIM is then updated in AEM Assets using the Assets Author API.


To complete this tutorial, you need:

Development steps

The high-level development steps are:

  1. Create a project in the Adobe Developer Console (ADC)
  2. Initialize the project for local development
  3. Configure the project in ADC
  4. Configure the AEM Author service to enable ADC project communication
  5. Develop a runtime action that orchestrates metadata retrieval and update
  6. Upload an asset to the AEM Author service and verify that the metadata has been updated

For details on steps 1-2, refer to the Adobe I/O Runtime Action and AEM Events example, and for steps 3-6 refer to the following sections.

Configure the project in Adobe Developer Console (ADC)

To receive AEM Assets Events and execute the Adobe I/O Runtime Action created in the previous step, configure the project in ADC.

  • In ADC, navigate to the project. Select the Stage workspace, this is where runtime action got deployed.

  • Click the Add Service button and select the Event option. In the Add Events dialog, select Experience Cloud > AEM Assets, and click Next. Follow additional configuration steps, select AEMCS instance, Asset Processing Completed event, OAuth Server-to-Server authentication type, and other details.

    AEM Assets Event - add event

  • Finally, in the How to receive events step, expand Runtime action option and select the generic action created in the previous step. Click Save configured events.

    AEM Assets Event - receive event

  • Likewise, click the Add Service button and select the API option. In the Add an API modal, select Experience Cloud > AEM as a Cloud Service API and click Next.

    Add AEM as a Cloud Service API - Configure project

  • Then select OAuth Server-to-Server for authentication type and click Next.

  • Then select the AEM Administrators-XXX product profile and click Save configured API. To update the asset in question, the selected product profile must be associated with the AEM Assets environment from which the event is being produced and have sufficient access to update assets there.

    Add AEM as a Cloud Service API - Configure project

Configure AEM Author service to enable ADC project communication

To update the asset metadata in AEM from the above ADC project, configure AEM Author service with ADC project’s client id. The client id is added as environment variable using the Adobe Cloud Manager UI.

  • Login to Adobe Cloud Manager, select Program > Environment > Ellipsis > View Details > Configuration tab.

    Adobe Cloud Manager - Environment Configuration

  • Then Add Configuration button and enter the variable details as

    table 0-row-4 1-row-4
    Name Value AEM service Type

    Adobe Cloud Manager - Environment Configuration

  • Click Add and Save the configuration.

Develop runtime action

To perform the metadata retrieval and update, start by updating the auto created generic action code in src/dx-excshell-1/actions/generic folder.

Refer to the attached file for the complete code, and below section highlights the key files.

  • The src/dx-excshell-1/actions/generic/mockPIMCommunicator.js file mocks the PIM API call to retrieve additional metadata like SKU and supplier name. This file is used for demo purposes. Once you have the end-to-end flow working, replace this function with a call to your real PIM system to retrieve metadata for the asset.

    code language-javascript
     * Mock PIM API to get the product data such as SKU, Supplier, etc.
     * In a real-world scenario, this function would call the PIM API to get the product data.
     * For this example, we are returning mock data.
     * @param {string} assetId - The assetId to get the product data.
    module.exports = {
        async getPIMData(assetId) {
            if (!assetId) {
            throw new Error('Invalid assetId');
            // Mock response data for demo purposes
            const data = {
            SKUID: 'MockSKU 123',
            SupplierName: 'mock-supplier',
            // ... other product data
            return data;
  • The src/dx-excshell-1/actions/generic/aemCommunicator.js file updates the asset metadata in AEM using the Assets Author API.

    code language-javascript
    const fetch = require('node-fetch');
    *  Get IMS Access Token using Client Credentials Flow
    * @param {*} clientId - IMS Client ID from ADC project's OAuth Server-to-Server Integration
    * @param {*} clientSecret - IMS Client Secret from ADC project's OAuth Server-to-Server Integration
    * @param {*} scopes - IMS Meta Scopes from ADC project's OAuth Server-to-Server Integration as comma separated strings
    * @returns {string} - Returns the IMS Access Token
    async function getIMSAccessToken(clientId, clientSecret, scopes) {
      const adobeIMSV3TokenEndpointURL = '';
      const options = {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
        body: `grant_type=client_credentials&client_id=${clientId}&client_secret=${clientSecret}&scope=${scopes}`,
      const response = await fetch(adobeIMSV3TokenEndpointURL, options);
      const responseJSON = await response.json();
      return responseJSON.access_token;
    async function updateAEMAssetMetadata(metadataDetails, aemAssetEvent, params) {
      // Transform the metadata details to JSON Patch format,
      // see
      const transformedMetadata = Object.keys(metadataDetails).map((key) => ({
        op: 'add',
        path: `wknd-${key.toLowerCase()}`,
        value: metadataDetails[key],
      // Get ADC project's OAuth Server-to-Server Integration credentials
      const clientId = params.ADC_CECREDENTIALS_CLIENTID;
      const clientSecret = params.ADC_CECREDENTIALS_CLIENTSECRET;
      const scopes = params.ADC_CECREDENTIALS_METASCOPES;
      // Get IMS Access Token using Client Credentials Flow
      const access_token = await getIMSAccessToken(clientId, clientSecret, scopes);
      // Call AEM Author service to update the metadata using Assets Author API
      // See
      const res = await fetch(`${aemAuthorHost}/adobe/assets/${assetId}/metadata`, {
        method: 'PATCH',
        headers: {
          'Content-Type': 'application/json-patch+json',
          'If-Match': '*',
          'X-Adobe-Accept-Experimental': '1',
          'X-Api-Key': 'aem-assets-management-api', // temporary value
          Authorization: `Bearer ${access_token}`,
        body: JSON.stringify(transformedMetadata),
    module.exports = { updateAEMAssetMetadata };

    The .env file stores the ADC project’s OAuth Server-to-Server credentials details, and they are passed as parameters to the action using ext.config.yaml file. Refer to the App Builder Configuration Files for managing secrets and action parameters.

  • The src/dx-excshell-1/actions/model folder contains aemAssetEvent.js and errors.js files, which are used by the action to parse the received event and handle errors respectively.

  • The src/dx-excshell-1/actions/generic/index.js file uses the previously mentioned modules to orchestrate the metadata retrieval and update.

    code language-javascript
    let responseMsg;
    // handle the challenge probe request, they are sent by I/O to verify the action is valid
    if (params.challenge) {'Challenge probe request detected');
      responseMsg = JSON.stringify({ challenge: params.challenge });
    } else {'AEM Asset Event request received');
      // create AEM Asset Event object from request parameters
      const aemAssetEvent = new AEMAssetEvent(params);
      // Call mock PIM API to get the product data such as SKU, Supplier, etc.
      const mockPIMData = await mockPIMAPI.getPIMData(
      );'Mock PIM API response', mockPIMData);
      // Update PIM received data in AEM as Asset metadata
      const aemUpdateStatus = await updateAEMAssetMetadata(
      );'AEM Asset metadata update status', aemUpdateStatus);
      if (aemUpdateStatus) {
        // create response message
        responseMsg = JSON.stringify({
            'AEM Asset Event processed successfully, updated the asset metadata with PIM data.',
          assetdata: {
            assetName: aemAssetEvent.getAssetName(),
            assetPath: aemAssetEvent.getAssetPath(),
            assetId: aemAssetEvent.getAssetId(),
            aemHost: aemAssetEvent.getAEMHost(),
            pimdata: mockPIMData,
      // response object
      const response = {
        statusCode: 200,
        body: responseMsg,
      // Return the response to the caller
      return response;

Deploy the updated action to Adobe I/O Runtime using the following command:

$ aio app deploy

Asset upload and metadata verification

To verify the AEM Assets and PIM integration, follow these steps:

  • To view the mock PIM provided metadata like SKU, and Supplier Name, create metadata schema in AEM Assets see Metadata schema that displays the SKU and supplier name metadata properties.

  • Upload an asset in AEM Author service and verify the metadata update.

    AEM Assets metadata update

Concept and key takeaways

The asset metadata synchronization between AEM and other systems like PIM are often required in the enterprise. Using AEM Eventing such requirements can be achieved.

  • The asset metadata retrieval code is executed outside of AEM, avoiding the load on AEM Author service thus event-driven architecture that scales independently.
  • The newly introduced Assets Author API is used to update the asset metadata in AEM.
  • The API authentication uses OAuth server-to-server (aka client credentials flow), see OAuth Server-to-Server credential implementation guide.
  • Instead of Adobe I/O Runtime Actions, other webhooks or Amazon EventBridge can be used to receive the AEM Assets event and process the metadata update.
  • Asset Events via AEM Eventing empower businesses to automate and streamline critical processes, fostering efficiency and coherence across content ecosystem.