Thoughts

Building a Dynamic Content Rendering System with Optimizely Opal

Author

Bob Davison

Categories:

Bob Davidson sitting at a table in his office.

Spinning up templates for new content types takes time. Here's a proof-of-concept that uses Optimizely Opal to make it faster and safer.

I recently finished the Opal Tools course and certification. But true to form, I decided halfway through the course to do the fun thing and build a tool before doing the less fun thing of taking a test. I challenged myself to build something a bit more complex than returning the current weather or doing basic validation.

So I built a dynamic content rendering system.

The big idea.

The idea is simple. Opal has tools to dynamically create content types, but a developer still needs to get involved to build the templates to properly render that content on the site. Could I remove that barrier? Spoiler alert: yes I can, with some caveats.

What I did not want is directly deployed AI-generated vibe-code. I’m not necessarily opposed to vibe-coding itself, but I do expect all AI-generated code to be reviewed and vetted before being put into production. I couldn’t have Opal generate raw code.

Instead, I built a system of components within a design system which Opal could then utilize to build web designs that are guaranteed to at least match the look and feel of the existing site, and be safe from broken HTML and many other potential pitfalls. To that end, I built a series of tools Opal can take advantage of to build dynamic but safe templates.

Opal Demo Example

Showing off a demo dynamic template system built around Optimizely SaaS and Opal. Though it's not exactly production ready, this demo allows an editor to go from content type idea to live content on the site without a developer or a deployment.

How it works.

I've created a collection of tools that Opal can use to list, read, and update templates.

When Opal needs to create or update a template, it first calls a "list components" tool, which returns all of the components available for use, including detailed instructions on how and when to use them. Next, it queries the SaaS content type tools to discover the content type and all of its available properties. Opal can then call "get template" to retrieve any existing templates for further guidance. From there, Opal combines its knowledge of the components, the content type, existing templates, and the user's description of their desired layout to generate a new tree of components. It calls a "save template" tool, and the process — from Opal's perspective — is done.

On the site, when a request for a page comes in, the site queries Optimizely's GraphQL endpoint to discover information about the page being requested, including its ID and content type. It then combines knowledge of the content types and existing templates to generate a GraphQL query that requests only the information necessary to display the content, and renders the final result to the browser.

In theory, an editor could go from an idea for a content type to live content on the site in a matter of minutes. In reality, what I've written here isn't quite production-ready, and I'm papering over some of the thornier issues in pursuit of an interesting demo. There's much to resolve: governance, caching, performance, and more. Components don't have any logic or the ability to fetch dynamic content yet — you couldn't build a carousel, for example. But as a proof-of-concept, it works.

Lessons learned.

Being a glutton for punishment, I made the brave but questionable decision to forgo Optimizely's SDKs and build my own discovery and tools endpoints instead. That meant getting down into the details of how Opal tool calling works, and I learned a few things along the way.

Opal doesn't use GET verbs, URL parameters, or query string parameters. Near as I can tell, all Opal tool calls are POSTs with JSON bodies. The documentation I read implied that tool calls are POSTs, but it wasn't clear they would only ever be POSTs — even though the discovery endpoint has an "http_method" parameter, which in my mind implied that more verbs than POST would be supported.

There's some kind of MCP proxy that sits between the LLM that Opal uses and your tools API endpoint. This proxy has some limitations — I discovered it was mangling my complicated parameter structure. It seems it was trying to validate the request but couldn't handle the recursive structure my component tree required. The solution was to plug my nose and instruct the LLM to send the component tree as a JSON-encoded string. Not ideal, but as far as I can tell, that's how some of the more complicated calls in Optimizely's own tools are made.

Tool call API bodies don't necessarily fit the model you might expect. For example, if you're expecting "name" and "body" keys on a root object, you won't get that. Instead, you'll get an object with "parameters," "environment," and "chat_meta" keys, and your values are nested inside that "parameters" sub-object.

The bottom line.

Opal is a powerful tool backed by a number of capable AI models. This demo is just one use case — a look at what Opal can do when it's combined with smart, custom tooling to remove bottlenecks for editors and developers. If you're building with Optimizely Opal, or just starting to explore what it can do, we'd love to hear about it — or help you figure it out. Get in touch with the team at Blend.

Related articles.

We’ve been writing and creating things for — and about! — the web for over 20 years, including our thoughts about Optimizely. Check out more articles similar to this one.

More from Blend.

Coaching Icon - Football Play

Coaching and Co-Development

Build your .NET development team's CMS capabilities alongside experienced Optimizely and Umbraco practitioners.

Development Icon - Web Wireframe and Code

.NET Development

Custom .NET development on Optimizely, Umbraco, and Contentstack — built for complex content and the editorial teams who manage it.

AI Icon - Lightbulb with Gear

AI Strategy

Practical AI guidance for content teams — from editorial workflows to search optimization — without chasing hype.