AEM 6 - Search and Download DAM Assets in Adobe CC Products


This post is on developing a Adobe CC HTML Extension to login to AEM 6, search and download Adobe CC assets (eg. Adobe Illustrator 18.1 files) uploaded to AEM DAM from CC products like Illustrator, InDesign, Photoshop...

CC HTML Extensions ( short guide and samples ) run on Common Extensibility Platform (CEP) of Adobe Illustrator 18.1, Adobe InDesign 10.1 etc. (the best part is, if you are not/little interacting with the host in extensions, without any changes they can run on various Adobe CC products). For example (though i've not tried) there are very good changes the sample extension developed in this post will run with minor changes (like adding an entry in CSXS/manifest.xml) in PhotoShop...

For downloading AEM assets (images, content fragments) and place them on InDesign pages check this post

Demo | AI 18.1 IDSN 10.1 CC HTML Extension | Extension Source  |  AEM 6 Package Install

I just put together the pieces, thanks to my fantastic adobe colleagues and internet for quick code snippets

Login panel in Illustrator ( click Window -> Extensions -> Search AEM )

AEM Asset Search in Illustrator

Login Panel in InDesign

Asset Search in InDesign


AEM CRX Updates

1) Login to CRXDE Lite (http://localhost:4502/crx/de), create folder and node of type sling:OsgiConfig and set the allow.empty property to true (Package Install). This setting allows the CEP panel (explained in next steps) to post credentials successfully to AEM. It's an observation that Chromium Embedded of CEP doesn't send referer header with requests (a bug in CEP?). To circumvent the problem we set allow.empty to true (it may be a security issue in publish environments; this CEP extension connects to and downloads assets from author instance, so set the configuration in folder)

CC HTML Extension

1) Create the following folder structure (Download source). This folder structure is installed as extension. The lib folder (containing helper files for creating the extension) is excluded from final executable created


2)  Use ant for assembling the extension for dev and distribution purposes. Ant targets to copy files to extensions folder and create installer.

Develop & Test
              a. Create CEP/extensions folder in user's home if it doesn't exist. On my windows it's C:\Users\nalabotu\AppData\Roaming\Adobe\CEP\extensions and MAC /Library/Application Support/Adobe/CEP/extensions

              b. Set PlayerDebugMode to  ( for debugging extensions the flag PlayerDebugMode needs to be set to 1)

                    On Windows, Open registry (Run -> regedit), HKEY_CURRENT_USER\Software\Adobe\CSXS.5

                    On local MAC (/Users/nalabotu/Library/Preferences/com.adobe.CSXS.5.plist)

              c. Create a .debug file in extension root. Add following xml; extension debugger will be available on http://localhost:8098/ when the extension panel is open in Illustrator 18.1. Extension id should be the same id added in CSXS/manifest.xml (next steps)

<?xml version="1.0" encoding="UTF-8"?>
    <Extension Id="">
           <Host Name="ILST" Port="8098"/>
              d. For development purposes we can use the following ant target (in build.xml) to copy files over to user's extensions folder eg. C:\Users\nalabotu\AppData\Roaming\Adobe\CEP\extensions

    <target name="copy">
        <delete dir="${live.extensions.dir}" />

        <mkdir dir="${live.extensions.dir}"/>

        <copy todir="${live.extensions.dir}" failonerror="false">
            <fileset dir="${basedir}">
                <exclude name="*.xml"/>
                <exclude name="*.iml"/>
                <exclude name="lib/**"/>
                <exclude name="temp/**"/>
                <exclude name="docs/**"/>

               e. Executing ant target copy, copies the extension files to extensions folder (eg. C:\Users\nalabotu\AppData\Roaming\Adobe\CEP\extensions)

               f. To debug the extension, open CC product (here Adobe Illustrator 18.1), make sure extension panel (Search AEM is open), open chrome browser and access http://localhost:8098/. Check log files, for example on my local C:\Users\nalabotu\AppData\Local\Temp\csxs5-IDSN.log, C:\Users\nalabotu\AppData\Local\Temp\csxs5-ILST.log, C:\Users\nalabotu\AppData\Local\Temp\cef_debug.log; For MAC the log files are in /Users/<user>/Library/Logs/CSXS

Distribute & Install

                a. To distribute the extension for installation on user's CC products, create a ZXP.

                b. ZXP should be CA (Certificate authority ) signed or self signed.

                c. To create a self signed key and certificate in pkcs12 format, use the following openssl commands (A sample certificate experience-aem-cep.p12 is available in
                    extension source, lib folder, password is experience-aem)

                    openssl req -x509 -days 365 -newkey rsa:2048 -keyout experience-aem-cep-key.pem -out experience-aem-cep-cert.pem

                    openssl pkcs12 -export -in  experience-aem-cep-cert.pem -inkey experience-aem-cep-key.pem -out experience-aem-cep.p12

                d. A signing toolkit ZXPSignCmd (available in extension source or can be downloaded at adobe labs ). It's different on MAC (the one available in source is Windows executable)

                e. Use following ant target zxp (in build.xml) to create the extension installer search-aem.zxp in extension source/temp folder

    Use this target for creating zxp, installed using Adobe Extension Manager
    The ZXPSignCmd library is different for MAC, the following targets use windows library
    <target name="zxp" if="isWindows">
        <delete dir="${basedir}/temp" />

        <mkdir dir="${basedir}/temp" />

        <copy todir="${basedir}/temp" failonerror="false">
            <fileset dir="${basedir}">
                <exclude name="*.xml"/>
                <exclude name="*.iml"/>
                <exclude name="lib/**"/>
                <exclude name="temp/**"/>
                <exclude name="docs/**"/>
                <exclude name=".debug"/>

        <exec executable="${basedir}/lib/ZXPSignCmd">
            <arg line="-sign ${basedir}/temp" />
            <arg value="${basedir}/temp/search-aem.zxp" />
            <arg value="${basedir}/lib/experience-aem-cep.p12" />
            <arg value="experience-aem" />  <!-- cert password -->

                   f.  To install the extension, use Adobe Extension Manager CC. Click Install on top right, browse to zxp folder and select search-aem.zxp. If the certificate used is not
                       CA signed (ie. a self signed) Extension Manager alerts with warning...

                       g. The installed extension. Open Adobe Illustrator 18.1 (Window -> Extensions) or InDesign 10.1 (Window -> Extensions) and you should see the Search AEM menu item

3) The most important part of the extension is CSXS/manifest.xml. The following xml fragment of manifest says this extension runs on Illustrator 18.1 and InDesign 10.1

            <Host Name="ILST" Version="18.1"/>
            <Host Name="IDSN" Version="10.1"/>
            <!-- Add other CC products here -->

4) The extension declaration with id (provided in .debug file for debugging in browser) <MainPath>./html/search-aem.html</MainPath> instructs Illustrator to load the html file html/search-aem.html when extension is opened by clicking Window -> Extensions -> Search AEM

        <Extension Id="">
                    <Menu>Search AEM</Menu>

4) For AEM developers, developing the actual extension should be pretty easy, its standard html, css, javascript

5) The following code in search-aem.html provides extension view. It loads angular, underscore from cdns. CSInterface-5.2.js is a helper CEP file to interact with host (Illustrator or InDesign) to run native code, for example in later steps we code a simple script to open downloaded file )

<!DOCTYPE html>
<html lang="en" ng-app="SearchAEM">

    <meta charset="utf-8">

    <title>Login Search AEM</title>

    <link rel="stylesheet" href="../css/style.css">

<div ng-controller="pc">
    <div class="sign-in" ng-show="showLogin">
            <h3>DIGITAL ASSET MANAGEMENT</h3>
            <label>User Name</label>
            <input type="text" ng-model="j_username" ng-enter="login()"/>
            <input type="password" ng-model="j_password" ng-enter="login()"/>
            <label>DAM Host</label>
            <input type="text" value="{{damHost}}" ng-model="damHost" ng-enter="login()"/>

        <button type="button" ng-click="login()">Sign In</button>

    <div ng-show="!showLogin">
        <div class="top-left">
            <input type="text" placeholder="Enter search text" ng-model="term" ng-enter="search()"/>
        <div class="top-right">
            <button type="button" ng-click="search()">Search</button>
        <div class="results">
            <div class="result-block" ng-repeat="result in results" ng-click="download(result)">
                    <img ng-src="{{result.imgPath}}"/>

<script src=""></script>
<script src=""></script>
<script src="../js/CSInterface-5.2.js"></script>
<script src="../js/login-search.js"></script>

6) The js/login-search.js provides necessary login/search/download from AEM functionality. Discussing Angular or Underscore logic is beyond the scope of this post; JS frameworks are not mandatory for developing CC HTML extensions, if you know HTML, CSS, Javascript that's good enough

'use strict';

(function () {
    var underscore = angular.module('underscore', []);

    underscore.factory('_', function () {
        return window._;

    var cep = angular.module('cep', []);

    cep.factory('cep', ['$window', function ($window) {
        return $window.cep;

    cep.service('csi', CSInterface);

    var aem = angular.module('aem', ['underscore', 'cep']);

    aem.service('login', [ '$http' , '_', function ($http, _) {
        return {
            login: function (username, password, damHost) {
                var jSecurityCheck = damHost + "/libs/granite/core/content/login.html/j_security_check";

                var data = {
                    j_username: username,
                    j_password: password,
                    j_validate: true

                return $, data, {
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
                    transformRequest: function(obj) {
                        var params = [];

                        angular.forEach(obj, function(value, key){
                            params.push(encodeURIComponent(key) + "=" + encodeURIComponent(value));

                        return params.join("&");

    aem.factory('search', [ '_', '$http', function (_, $http) {
        return function (defaults) {
            this.aem = "http://localhost:4502";
            this.params = _.extend({}, defaults);
            this.numPredicates = 0;

   = function(aem){
                this.aem = aem;
                return this;

            this.fullText = function (value) {
                if (!value) {
                    return this;

                this.params[this.numPredicates + '_fulltext'] = value;

                return this;

            this.http = function(){
                var builder = this;

                return $http({
                    method: 'GET',
                    url: builder.aem + "/bin/querybuilder.json",
                    params: builder.params

    var app = angular.module('SearchAEM', ['aem']);

    app.directive('ngEnter', function () {
        return function(scope, element, attrs) {
            element.bind("keydown keypress", function(event) {
                if (event.which === 13) {
                    scope.$apply(function() {


    app.controller('pc', [ '$scope', 'login', 'search', '$http', 'csi', 'cep',
        function ($scope, login, search, $http, csi, cep) {
            $scope.damHost = "localhost:4502";
            $scope.showLogin = true;

            $scope.login = function () {
                if (!$scope.j_username || !$scope.j_password || !$scope.damHost) {
                    alert("Enter credentials");

                $scope.damHost = $scope.damHost.trim();

                if ($scope.damHost.indexOf("http://") == -1) {
                    $scope.damHost = "http://" + $scope.damHost;

                login.login($scope.j_username, $scope.j_password, $scope.damHost)
                    .success(function (data) {
                        $scope.showLogin = false;
                    .error(function () {
                        alert("Trouble logging-in, Invalid Credentials?")

            var searchDefaults = {
                'path': "/content/dam",
                'type': 'dam:Asset',
                'orderby': '@jcr:content/jcr:lastModified',
                'orderby.sort': 'desc',
                'p.hits': 'full',
                'p.nodedepth': 2,
                'p.limit': 25,
                'p.offset': 0

            $ = function () {
                if (!$scope.term) {
                    alert("Enter search term");

                $scope.results = [];

                var mapHit = function(hit) {
                    var result;

                    result = {};

           = hit["jcr:path"].substring(hit["jcr:path"].lastIndexOf("/") + 1);
                    result.url = $scope.damHost + hit["jcr:path"];
                    result.imgPath = $scope.damHost + hit["jcr:path"] + "/jcr:content/renditions/cq5dam.thumbnail.140.100.png";

                    return result;

                new search(searchDefaults).host($scope.damHost)
                        .then(function(resp) {
                    $scope.results = _.compact(, mapHit));

            $ = function(result){
                $http.get(result.url, {
                    responseType: "blob"
                }).success(function(data) {
                    var reader = new FileReader();

                    reader.onload = function() {
                        var filePath = csi.getSystemPath(SystemPath.MY_DOCUMENTS)
                                            + "/" +;
                        cep.fs.writeFile(filePath, reader.result.split(',')[1], cep.encoding.Base64);

                        csi.evalScript("(function(){ File('" + filePath + "'));})();", function(){
                            alert("File " + + " downloaded as " + filePath)

                }).error(function() {
                    alert("Error downloading file");

7) The following script at #183, executes call to open the downloaded file in Illustrator or InDesign. It's a simple script, provided inline to the evalScript() function; for developing sleek panels with complex extend script logic (Extendscript is similar to javascript, used to code CC extensions) you can use <ScriptPath></ScriptPath> in CSXS/manifest.xml (not explained in this post). app is a global variable available in host (Illustrator or InDesign)

                        csi.evalScript("(function(){ File('" + filePath + "'));})();", function(){
                            alert("File " + + " downloaded as " + filePath)

8) A note on using JQuery in CC HTML Extensions. If you get error $ is undefined when executing jquery selectors, add window.module=undefined in html. I am not aware of the details behind NodeJS and JQuery ($) not able to co-exist, but having window.module=undefined makes NodeJS unavailable in extension panel and a developer can code using JQuery

    <script type="text/javascript">
        window.module = undefined;


  1. This comment has been removed by a blog administrator.

    1. This comment has been removed by a blog administrator.

    2. The development of artificial intelligence (AI) has propelled more programming architects, information scientists, and different experts to investigate the plausibility of a vocation in machine learning. Notwithstanding, a few newcomers will in general spotlight a lot on hypothesis and insufficient on commonsense application. machine learning projects for final year In case you will succeed, you have to begin building machine learning projects in the near future.

      Projects assist you with improving your applied ML skills rapidly while allowing you to investigate an intriguing point. Furthermore, you can include projects into your portfolio, making it simpler to get a vocation, discover cool profession openings, and Final Year Project Centers in Chennai even arrange a more significant compensation.

      Data analytics is the study of dissecting crude data so as to make decisions about that data. Data analytics advances and procedures are generally utilized in business ventures to empower associations to settle on progressively Python Training in Chennai educated business choices. In the present worldwide commercial center, it isn't sufficient to assemble data and do the math; you should realize how to apply that data to genuine situations such that will affect conduct. In the program you will initially gain proficiency with the specialized skills, including R and Python dialects most usually utilized in data analytics programming and usage; Python Training in Chennai at that point center around the commonsense application, in view of genuine business issues in a scope of industry segments, for example, wellbeing, promoting and account.

      The Nodejs Projects Angular Training covers a wide range of topics including Components, Angular Directives, Angular Services, Pipes, security fundamentals, Routing, and Angular programmability. The new Angular TRaining will lay the foundation you need to specialise in Single Page Application developer. Angular Training

  2. This comment has been removed by a blog administrator.

  3. This comment has been removed by a blog administrator.

  4. This comment has been removed by a blog administrator.

  5. This comment has been removed by a blog administrator.

  6. This comment has been removed by a blog administrator.

  7. If you want to learn about Graphics Design, is the best platform for you. It provides online graphic design, Adobe Photoshop and Illustrator Tutorials for beat career building. also offer latest update of Jobs Circular in Bangladesh. Visit for more details and updates.

  8. This comment has been removed by a blog administrator.

  9. Excellent ! I am truly impressed that there is so much about this subject that has been revealed and you did it so nicely.
    Angularjs developer

  10. Awesome! good info on this post.

  11. Hiii...Thanks for sharing great info...Nice post...Keep move on....
    Angular JS Training in Hyderabad

  12. Thanks for Sharing This Article.It is very so much valuable content. I hope these Commenting lists will help to my website
    top angularjs online training
    best angularjs online training
    angularjs online training

  13. Thanks for sharing this content. Technology has changed drastically over the past few decades. Even though services are available to more people than ever, unfortunately, not everyone has access to the same level of services. Read more