Episerver, now rebranded as Optimizely, has given developers the ability to access its content through its Content Delivery API. This allows you to use Optimizely as a Headless CMS, accessing all of your content as JSON via a REST API.
This has been a game-changer for Optimizely. Not only do you get the benefits of a traditional CMS, but the ability to leverage headless capabilities means you can push your Optimizely content out to multiple channels, including SPAs.
If you have done any research into the Content Delivery API, you might have come across the Music Festival App built in VueJS.
Some notable features about this application are that it's a single-page application (SPA), but it also allows for on-page editing.
We had a need to take this even a step further. We needed to store content for multiple SPAs within the same Optimizely instance, where the SPAs themselves would be hosted in a different location. While the Optimizely instance also maintains an existing site. We'll get into a bit more detail about the project next.
A client came to us describing a project for multiple portal applications that were being built by a separate part of the organization than the part that maintains their main site. This part of the organization had its own development team and had requirements to build their portals as Angular applications hosted in Amazon AWS. They also wanted to leverage a headless CMS for editing content but hadn't decided on which yet. While the portals would be built and maintained by separate parts of the organization, some of the content editors for both the main site and the portal applications would be the same.
Because some of the content editors would need to work in both CMS, they came to us for recommendations. They knew they wanted to explore a headless option, however, they didn't want to lose out on some of their favorite Episerver features like on-page editing or personalization. With the requirement that we provide a headless option, and the knowledge that the editors love Optimizely's features, it took us all of two seconds to come up with Optimizely's Content Delivery API as a solution.
On the surface, the solution was straightforward. We already demonstrated that Episerver's features could be leveraged in a headless context with the Music Festival example we mentioned above. It has personalization, on-page editing, and was built out as a SPA. There are however a few differences that make this implementation different. Unlike the Music Festival example, these SPAs would not be the main site this Optimizely instance is running. Second, the actual markups for these SPAs are hosted outside of Optimizely. This will present some challenges around on-page editing that we will discuss in more detail below.
One of those differences mentioned is that the portal applications were not the main site that Optimizely is powering. Optimizely has multi-site capability, so that was one potential route. We decided to go for an even simpler approach, creating Containers in the Optimizely page tree. Each container was assigned to a SPA. This allowed us to organize all the SPAs that would be potentially added, as well as easily control other aspects, such as permissions. It also allowed for a simplified approach when querying content from Optimizely. Once a container is defined, its Id is set. With multiple development teams building out multiple portals, we can define how they all should be pulling content by putting it in the context of that container. An example being, "get all pages of type 'y', under container with id='z'".
We also created custom page types that would be used for the Angular applications. Custom page types not only made for easier querying for the other developers, since all the queries could just include a parameter that specified the page type, but it also assisted in on-page editing.
In the razor views of our custom page types, we subscribed to specific Optimizely events. One of which listened for updates to the associated properties as they were modified during on-page editing. We also subscribed to a page load as well as an empty div tag that we used as a reference to know where to load the associated page of the angular app.
The third, and more challenging difference between our application and the music festival app was on page editing. Remember that one of the requirements was that the portal applications would be hosted as separate apps in Amazon AWS? The Optimizely instance is hosted with Optimizely DXP in Microsoft Azure. Because Optimizely cannot load an external site to render its editing interface, we would need to figure out a way to render the Angular App within Optimizely.
While almost every aspect of the organization was separate, one thing they did share was source control. They belonged to the same organization in Github. To incorporate the angular apps into our Optimizely code base, we created git submodules.
Submodules are a cool feature in git that allows you to reference another project from within an existing one. You can continue to treat them both as separate projects. Any changes to one require their own separate commits and push separate from the other.
In this scenario, we were given read access to the Angular project repository, and setup the submodule in the Optimizely repository. For our Optimizely site's front end, we have a separate build process using node.
As part of that build process, we added a step to get the latest from the submodule that contains the Angular app, and build it.
This allowed us to have the latest version of the app available for on page editing, without any additional effort on our end.
From there, the developers working on the Angular app only had to make sure they include Optimizely editor html attributes. When you load the on-page editor in Optimizely, it knows what areas to wrap in the green box which can be clicked on and edited, by looking at attributes within the markup. So if there is h1 header on the page whose content is being pulled from Optimizely, you only need to add a few HTML attributes to the h1 that specify that is represents an Optimizely property, and which property it is, and you will have on-page editing.
The Angular app itself was pretty standard. As we mentioned before we needed to add attributes around elements to ensure they were picked up in Optimizely for on-page editing.
One other aspect we had to consider was routing. To enable us to load the appropriate page in the SPA when it on page editing, we had to add custom routes to map to Optimizely pages in the CMS. If you ever looked closely at the URL when on page editing, you will notice its uniform across pages, with the exception that it updates an id at the end. This is the ContentLink id of the page.
Luckily, this id is returned along with the rest of the data that the Angular app pulls from Optimizely's Headless API. From there we are able to assign additional routes to pages to handle when they are loaded within the CMS. That way, no additional configuration needs to be done to map pages in the Angular app to pages in the CMS.
While everything we covered checks all the boxes of our requirements, there are definitely some limitations to our implementation.
The main one being maintaining consistency between environments. While we were able to grab the latest version of the Angular apps through the submodules, it would only update for the editor when we also deployed the code for the Optimizely site. Because of this, we had to coordinate when properties needed to be added or modified to maintain consistency between the portal and editor experience.
If any styling or layout changes were made, the understanding was that the editor experience might not match the app exactly until the next deploy, but would still allow the editor so to modify content.
While this implementation might not be a common use case, I think it provides a great example of the range Optimizely has as a platform. Not only was it able to continue functioning as the main site for our client, but it was able to leverage it's Content Delivery API to provide more channels for content.
If you have any questions about Optimizely's Content Delivery API, or any of our other implementations, feel free to reach out to us.