A note from 2026: This article was published in 2019. SAP Commerce Cloud, SmartEdit, and the CMS APIs have evolved significantly since then; Spartacus is now SAP Composable Storefront, AngularJS has reached end of life, and extension/build tooling has changed across later SAP Commerce Cloud releases.

Rauf Aliev

Non-product content management has for many years been the weakest link of the SAP Commerce platform. Formally, the suite had a WCMS module from the very first version, but it was obvious to everybody that the solution was terribly old-fashioned and outdated.

Back in 2016, SAP Hybris Commerce was extended with a new solution: SmartEdit. On the one hand, SAP released it too early. Many commented that the product was underbaked to replace WCMS Cockpit. Even two years later, SmartEdit had drawn much criticism from users and developers. On the other hand, it was long overdue. We had been waiting for a replacement for years.

In search of the truth, in 2018, I examined SmartEdit in detail and shared the findings here on Hybrismart. There hasn’t been a lot of water under the bridge since 2018, but the situation with SmartEdit has taken a definite turn for the better. However, being a “non-mandatory” component for two years, it was generally ignored by the community. After all, why should we use SmartEdit if there is a good old WCMS Cockpit, time-tested and proven, albeit with known issues and poor customizability? This is why only a small percentage of developers are aware of SmartEdit from a technical perspective. I hope this article will help them move forward.

It should be noted that starting from version 1811, we’re currently out of options. The cockpit framework, and with it WCMS Cockpit and BTG personalization, were completely removed from the platform. So, SmartEdit is the only option for content management and personalization.

Content Management Systems

To better understand the concepts of SmartEdit and its place in the market, let’s look back at how content management systems have evolved over time.

The first CMSs were developed to support only websites. Mobile, desktop, and kiosk versions were considered separate channels. As a result, many of the solutions were designed as monolithic applications in which the user interface and data access code are combined into a single program to form a single platform. When it comes to innovation, most CMS solutions are constrained by their legacy architecture. This was one of the reasons why CMS Cockpit had not been evolved for years by SAP. With every single year of dealing with deprecated software, the developer experience has been a key pain point, which boils down to lack of vendor support, poor documentation, and problematic troubleshooting and debugging.

Traditional monolithic CMSs provide both content management and content rendering. More specifically, they have been developed with the frontend and backend designed into a single platform. In SAP Commerce, we had Accelerator templates built in JSP, page controllers built in Java, and all this stuff had to be aligned with the data model and architecture of the CMS system. WCMS was designed mainly for developers, thereby reducing the leverage of these systems by non-technical users. Many concepts require an understanding of the underlying data model.

A headless CMS has no default frontend system to determine how the content is presented to the end user. It provides all the capabilities of the backend of a traditional CMS (i.e., the “body”) while giving the responsibility for content presentation to the delivery channels (i.e., the head). It acts as a content repository. The data can be requested or pulled from the CMS by any channel, such as a mobile or kiosk app, by way of a RESTful API. Each individual channel takes advantage of its own unique presentation capabilities. Some would also call these content management systems “API-driven CMSs.”

The problem with most headless CMSs is that you need one more layer to be managed somehow: the presentation layer. The possibility of having a page-oriented approach with layouts or grids is important, but it is generally not provided by headless CMS solutions.

SmartEdit

SmartEdit was designed to bring the best of both worlds. Its architecture combines the flexibility and adaptability of an API-first approach with the user-friendliness of a traditional CMS. For the stable set of API interfaces, you can create more than one storefront and even more than one content management client. For example, on top of the CMS API, you can develop a module that regularly checks content and performs corrective actions if it doesn’t meet requirements.

SmartEdit is built as a single-page app interacting with the CMS API. Like a storefront, this makes SmartEdit headless too, so theoretically you can have an alternative client app for CMS operations. Such architecture makes SmartEdit clear and understandable in terms of architecture, customizability, and data flows.

SmartEdit architecture overview

However, SmartEdit introduces a bunch of new technologies and tools. It imposes stricter requirements on the project team. It is very unlikely you will use the old and obsolete AngularJS 1.6 for the storefront too.

SmartEdit technologies and tools overview

The reason for that is clear. Being a single-page app, the essential part of SmartEdit belongs to frontend development. The frontend world is crazy: it has changed fundamentally in the last four to five years. Multiple tools and libraries rose to meet the challenge, and the best ones have slowly floated to the top. Years ago, AngularJS was a promising toolset.

As we can see from the code, roadmap, and SmartEdit releases and updates, the product has been making great headway in refactoring and redesign. The extendable components are now in TypeScript, and the interfaces have been evolving to meet market standards.

Key Concepts of SmartEdit

SmartEdit maintains content in a “page-oriented” manner. Content is generally tied to the components it is used in. You can’t browse a list of all banners in the system to manage their parameters in isolation from the presentation configuration. Instead, you need to open a page, select a banner on the page, and change the configuration for that particular banner instance. All alternative approaches require deep customization of the system.

The page editor is integrated into the website UI. It makes SmartEdit look like a transparent layer on top of the storefront.

SmartEdit transparent editor layer

Without SmartEdit With SmartEdit
Storefront without SmartEdit
Storefront with SmartEdit editor overlay

SmartEdit modes selector

This layer can be presented in different functional modes, from basic to advanced. Each mode provides a set of available content operations and can be restricted to a content management role. There are five modes out of the box: Preview, Basic Edit, Advanced Edit, Versioning, and Personalization.

The content delivery layer is completely decoupled from content management. SmartEdit is responsible for the content management part only. Content delivery and rendering are based on the good old Spring MVC.

For pages, components, and templates, the data model is generally the same as we had with WCMS.

SmartEdit is designed to work with any storefront supporting the well-documented SmartEdit storefront integration contract. Currently, only two storefronts support the contract: the built-in JSP-based SAP Commerce Accelerator and a brand-new JavaScript storefront, Spartacus.

The modular structure helps to extend almost everything. The extensibility capabilities are demonstrated with the personalization module, which can also be used as a reference implementation for your own custom modules.

Key Components

There are three functional components: Navigation Management, Page Management, and Personalization. In terms of navigation, there is a fourth component, Versioning, but functionally it is part of page management.

SmartEdit key components

As the name of a CMS feature, “Versioning” was really confusing to me. It is not Undo/Redo functionality as I would have thought. Functionally, SmartEdit’s versioning is closer to Backup/Restore: you can save a current version before making changes and revert to the saved version to discard changes and restore the saved state.

Currently, versioning in SmartEdit is only by page. Content slot and component versioning are not available yet, but they are promised to be added in the future.

Navigation management is based on similar concepts to those found in good old CMS Cockpit. You can add, move, edit, and delete navigation nodes, and change the order of navigation nodes using drag and drop.

SmartEdit’s UI is faster, sleeker, and generally more convenient than what we had in WCMS Cockpit. However, a few hiccups are still a struggle for newbies. For example, you can’t publish changes in navigation directly from the page where those changes were made. You need to synchronize a navigation component, which is in a completely different corner. The navigation data model makes it difficult for many people who are not familiar with complex data structure handling and are not experts in this matter at all. How do you explain the different types of navigation entries to a non-specialist? However, these cases are few.

SmartEdit navigation management screen

SmartEdit’s personalization module replaced the old similar-purpose component, Behaviour Target Groups, or Advanced Personalization. The legacy solution triggers actions or shows CMS content to different groups of customers based on their behavior, interests, and historical data. You could use customer-specific promotions, suggest products, or adapt the website’s content and products to their interests. It looks great in demonstrations, but due to its significant impact on performance, this module was generally avoided. The new personalization module is promising.

Architecture of SmartEdit Personalization

SmartEdit personalization concept

The personalization module is based on two pillars:

It is important to say that SAP Commerce can’t assign customers to segments automatically based on their behavior or attributes. This is because of the separation of responsibilities: this is not part of the e-commerce platform’s purpose and tasks. You need to integrate SAP Commerce with the segment data provider, such as SAP Marketing or Context-Driven Services. There is an out-of-the-box integration package from SAP to make the process smooth and fast.

Also, you can’t edit or remove segments and user-to-segment assignments in SmartEdit. These data are considered external to the e-commerce platform.

SmartEdit allows you to create variations and connect them to variation triggers. A variation is a set of changes. This change, an action, can be applied to CMS, promo, or search configurations. For example, you can replace a CMS component with another version of it and name it as a variation. The trigger is used for enabling variations for specific conditions. For example, a segment trigger is used when the customer belongs to a particular segment.

SmartEdit personalization variations and triggers

The legacy BTG personalization engine was not popular mainly because of the performance impact it created. That module was capable of assigning users to segments dynamically and activating changes based on a combination of rules in a near real-time manner. These two operations are expensive in terms of resources. In the new implementation, user segmentation is no longer the e-commerce platform’s responsibility, and the rules are checked only when particular events, such as User Login, occur. After a variation is calculated for the customer session, the system caches the findings in the session and uses them for further requests.

Such actions are used for SmartEdit configuration (DefaultCxRecalculationService):

These actions can be specified for a fixed (OOTB) number of events, such as user login or user consent:

Personalization recalculation events

The key difference between SmartEdit personalization and legacy BTG personalization is the way the calculation is implemented. For BTG, it was a real-time calculation, while in SmartEdit the calculation is asynchronous. The results can come seconds after the customer is logged in. Using asynchronous calculation makes this approach fast and manageable in terms of performance. There are tiny delays, but they don’t affect the customer experience because they occur in the background.

When the events are expected to be too frequent, there is a way to perform recalculation on a schedule. There is CxDefaultPersonalizationCalculationJob, which executes CxService().calculateAndStoreDefaultPersonalization.

Customizing SmartEdit

There are two main techniques, used together, for customizing business logic and interfaces:

The following APIs are considered SmartEdit-related. Some of them are purely frontend mechanisms, such as Angular services; some of them are RESTful webservices; and some are a combination of webservices and Angular services.

Permission Service and Permission API. It is used to determine what functional elements are available for a user and what a user can access, or access and edit. Permissionwebservices exposes the RESTful API for global, type, attribute, and catalog permission checks. The typical requests for global and catalog permissions are:

Example code:

/* Copyright (c) 2017 SAP SE or an SAP affiliate company. All rights reserved. */
angular.module('personalizationsmarteditRulesAndPermissionsRegistrationModule', [
    'permissionServiceModule',
    'personalizationsmarteditServicesModule'
]).run(function($q, permissionService, personalizationsmarteditRestService, personalizationsmarteditContextService) {

    var getCustomizationFilter = function() {
        return {
            currentPage: 0,
            currentSize: 1
        };
    };

    // Rules
    permissionService.registerRule({
        names: ['se.access.personalization'],
        verify: function() {
            return personalizationsmarteditContextService.refreshExperienceData().then(function() {
                return personalizationsmarteditRestService.getCustomizations(getCustomizationFilter()).then(function() {
                    return $q.when(true);
                }, function(errorResp) {
                    if (errorResp.status === 403) {
                        // Forbidden status on GET /customizations - user doesn't have permission to personalization perspective
                        return $q.when(false);
                    } else {
                        // Other errors will be handled with personalization perspective turned on
                        return $q.when(true);
                    }
                });
            });
        }
    });

    // Permissions
    permissionService.registerPermission({
        aliases: ['se.personalization.open'],
        rules: ['se.read.page', 'se.access.personalization']
    });
});

Spring Security OAuth scope configuration

Catalog API. Returns catalog + catalog versions you have access to, namely: catalog name, catalog version name, thumbnail of the homepage, and page display condition details.

CMS SmartEdit Structure API. Returns metadata about the specific CMS component type to determine which of the component’s attributes are editable, and to handle editable and non-editable attributes properly. The response contains the field types as well. They are used for rendering the UI controls.

It provides information about:

Configuration API. CRUD operations with the configuration attributes.

Drag-and-drop service. Angular API for implementing drag-and-drop services.

Translation API. Provides the functionality to retrieve an SAP Commerce resource bundle for specific locales.

Gateway Factory. A gateway system between the iframe, where the storefront is injected, and a SmartEdit container, which contains the iframe. It establishes communication between the frames (outer/inner) using a pub/sub pattern.

HTTP Interceptor Service. This service is used in the preprocessing and postprocessing of $http requests and responses in AngularJS. There are four predefined interceptors:

Toolbar Service. Adding actions to the SmartEdit header, experience, and perspective toolbar. This service will be explained in detail later.

SmartEdit Contract for the Storefront

The SmartEdit framework is capable of working on any storefront that implements the SmartEdit Contract. The SmartEdit Contract consists of the following:

<script src="some/location/webApplicationInjector.js"
data-smartedit-allow-origin="domain1, domain2"></script>
<div
class="smartEditComponent"
data-smartedit-component-
type="SimpleResponsiveBannerComponent"
data-smartedit-component-id=
"SAPCommerceComponentName"
data-smartedit-component-uuid="somecompositekeyserialization"
data-smartedit-catalog-version-uuid="apparel-deContentCatalog/Staged">

<your-original-component/>

</div>

Body:

<body
class="smartedit-page-uid-mypageuid
smartedit-page-uuid-mypageuuid
smartedit-catalog-version-uuid-mycatalogversionuuid">

Modules

The following diagram shows how SmartEdit modules interact with the platform:

SmartEdit modules diagram

CMS Components

SmartEdit is compatible with SAP Commerce CMS Components. As usual, for a new component, you need to register a component type extending AbstractCMSComponent or its children and create a JSP view (<yourcomponentname.jsp>). Additionally, you need to associate a component type group with the component type:

INSERT_UPDATE ComponentTypeGroups2ComponentType; source(code)[unique=true]; target(code)[unique=true]
; wide ; YourCustomComponent

The attributes and type details are exposed to SmartEdit via the Structure API. By default, it provides converters for Collections, Maps, Primitive Wrapper classes, Dates, Products, Categories, User Groups, Media Containers, CMS Items, and all localized variations of these types. For blacklisting specific attributes, list them in defaultCmsStructureTypeBlacklistAttributeMap.

If all slots have ValidComponents configured with a specific set of allowed components, and if your new component type is outside this list (merged across the slots), it won’t be displayed in SmartEdit.

SmartEdit UI Customization

You can extend the services and features by adding or replacing the OOTB code with your own. As a starting point, create your extension using the ysmarteditmodule template. It is very likely that your code will leverage the services listed above and AngularJS built-in capabilities. So, understanding the details of both is crucial to success.

The deprecated ycmssmartedit extension is no longer used.

There are three things you can customize easily:

Custom Toolbar Actions

In order to extend the toolbars, you need to use featureService.addToolbarItem and register it in the perspectiveService (sorry for no indents):

import { IFeatureService, IPerspectiveService, SeModule } from 'smarteditcommons';
import { doImport } from './forcedImports';

doImport();

@SeModule({
    imports: [
        'smarteditServicesModule',
        'trainingsmarteditPerspectiveToolbarItemModule',
        'MyServiceModule'
    ],
    initialize: (perspectiveService: IPerspectiveService, featureService: IFeatureService, myService: any) => {
        'ngInject';

        featureService.addToolbarItem({
            toolbarId: 'smartEditPerspectiveToolbar',
            key: 'trainingsmarteditPerspectiveToolbarItem',
            type: 'HYBRID_ACTION',
            nameI18nKey: 'A New Button',
            priority: 2,
            section: 'left',
            iconClassName: 'hyicon hyicon-info se-toolbar-menu-ddlb--button__icon',
            include: 'trainingsmarteditPerspectiveToolbarItemWrapperTemplate.html',
            callback: () => {
                myService.openAWizard();
            },
        });

        perspectiveService.register({
            key: 'se.cms.perspective.advanced',
            nameI18nKey: 'se.cms.perspective.advanced',
            descriptionI18nKey: 'se.hotkey.tooltip',
            features: ['trainingsmarteditPerspectiveToolbarItem'],
            perspectives: []
        });
    }
})

export class TrainingsmarteditContainer {}

This code creates “A NEW BUTTON” in the Perspective Toolbar:

A NEW BUTTON in the SmartEdit perspective toolbar

With this service, you can customize all three toolbars:

SmartEdit toolbar customization options

The name of the toolbar — Header, Experience, or Perspective — is specified in addToolbarItem.toolbarId.

If you decide to add a custom Wizard, add a callback function implementation into a toolbar definition (see above):

//...
callback: () => {
    myService.openAWizard();
},

and your custom service (myService.ts):

(function() {
    angular.module('MyServiceModule', [
        …
    ])
    .service('myService', function(modalWizard, catalogService, pageFacade) {
        this.openAWizard = function openAWizard(pageData) {
            var promise = pageData ? catalogService.retrieveUriContext() :
                pageFacade.retrievePageUriContext();

            return promise.then(function(uriContext) {
                return modalWizard.open({
                    controller: 'myWizardController',
                    controllerAs: 'myWizardCtrl',
                    properties: {
                        uriContext: uriContext,
                        basePageUUID: pageData ? pageData.uuid : undefined
                    }
                });
            });
        };
    })
    .controller('myWizardController', function() {
        this.getWizardConfig = function() {
            var wizardConfig = {
                steps: [{
                    id: "step1",
                    name: 'Step1',
                    title: 'Step',
                    templateUrl: 'step1.html'
                }]
            };
            return wizardConfig;
        }.bind(this);
    });
})();

Contextual Menu Items

A contextual menu is a decorator that wraps around a component. It can contain a set of icons, each of which performs a different action. You can add your own controls to the menu.

featureService.addContextualMenuButton({
    key: "my.menu.item.key",
    i18nKey: 'My Menu Item',
    nameI18nKey: 'my.menu.item',
    regexpKeys: ['MyTestComponent3'], // Regexp, here is a
    condition: (config: any) => { // component uid
        return true;
    },
    action: {
        template: 'test – will be displayed below the icon'
    },
    displayClass: "movebutton",
    iconIdle: '/trainingsmartedit/icons/icon_off.png',
    iconNonIdle: '/trainingsmartedit/icons/icon_on.png',
    smallicon: '/trainingsmartedit/icons/info.png',
    // permissions: ['se.read.page'], // for permissions
} as IContextualMenuButton);

featureService.enable(' my.menu.item.key ');

Custom contextual menu icon in SmartEdit

Homepage Links

After analyzing the customization approach and available toolset, I decided to experiment with making changes in the UI outside the documented scope, such as adding a link to a SmartEdit homepage.

For such operations, you need to clone the simple module from cmssmartedit and extend it:

this.addItems([{
include: 'myCustomCVDTemplate.html'
}], CATALOG_DETAILS_COLUMNS.LEFT);

Custom SmartEdit homepage link

In my PoC, this link opens a custom page:

Custom SmartEdit page opened from homepage link

SmartEdit Builder

SmartEdit uses Grunt Task Runner and its plugins to provide a single, unified set of commands for easier and faster development. Using the Grunt scripts as a black box works well if you don’t make mistakes. Without understanding what is behind the scripts, troubleshooting will be rather difficult. For example, all your template filenames must end with “Template”. You can read that in the documentation, but… if you forget about that, your template file won’t be converted into JavaScript code during the build process, and Angular components will throw an exception. Almost all error messages are not informative in AngularJS/SmartEdit, and even in such a simple case, you can waste a day trying to find the root cause. The builder scans for the templates, and the folder and filename patterns are listed in the Grunt scripts. It is very useful to read them over and understand the builder logic in detail. It will save you a lot of time later.

Conclusion

Summary

Things I Liked in SmartEdit

In the last release, SmartEdit seems to be a mature tool for content management. Despite some drawbacks, such as poor media management and no workflows, the product is good enough for the majority of e-commerce content management needs.

It is great that all forms are built automatically based on the platform model definitions. Unlike the Cockpit framework, SmartEdit’s code is extendable.

The architecture is clear, the source code is available, and the system components are decoupled. All this makes troubleshooting much easier in comparison with what we had in the legacy WCMS Cockpit.

What Pains Me the Most

The architecture of SmartEdit is not settled yet. Despite the fact that the product is relatively new, many components are marked as deprecated. Even the official SmartEdit Trail is not 100% relevant to what we have in the latest release (1801).

A deprecated tech stack. SmartEdit is built on top of AngularJS 1.6. AngularJS has been announced as deprecated and has three years of security support. Better alternatives than AngularJS or even Angular 2 may become available as SAP goes.

Poor error handling. The error messages are not informative or are absent. For example, if you don’t install a SmartEdit addon or the preview URL is not correct, the system simply won’t start. Of course, after gaining weeks of experience, you will learn how to see the signs of typical root causes. However, in the beginning, that is tough.

SmartEdit introduces a bunch of new technologies and tools. It imposes stricter requirements on the project team. Some tools are too young. This creates risks of functional and performance issues and frequent changes in the core architecture.