Why Optimizely’s XHTML Properties Can Be a Trap in Headless Solutions Leveraging Optimizely CMS

Optimizely (formerly Episerver) developers are very familiar with the XhtmlString property. It’s the standard for rich text, and it’s a great tool in a traditional CMS setup where HTML goes directly into a Razor view.

But when you move to a headless architecture or need to ingest content from external systems, XhtmlString can quickly become a source of complexity, performance issues, and integration headaches.

Why? Because what seems like a simple field is actually doing a lot behind the scenes.

The Hidden Work of XhtmlString

Let’s look at a simple example.

How it’s stored internally:

<p>Welcome to <strong>our site</strong>! <a href="~/link/12345.aspx">Read more</a></p>

How a headless API delivers it:

{
"body": "<p>Welcome to <strong>our site</strong>! <a href=\"/about-us\">Read more</a></p>"
}

Notice how the internal, permanent link token ~/link/12345.aspx is automatically converted into a user-friendly, site-relative URL /about-us? That’s the magic of XhtmlString, but it comes with a cost.

The Headless Challenges of XhtmlString

This automatic link resolution, along with other behaviors, causes problems in a headless environment:

  • Performance Overhead: Every time a request is made to the API, the CMS has to perform runtime lookups to resolve these internal links. On large HTML blobs with many links or embedded content, this can significantly slow down your API responses.
  • HTML Ingestion Quirks: When you import HTML from another system, Optimizely might try to “fix” the links by rewriting them into its own internal tokens. This can lead to unpredictable and inconsistent data formats.
  • Context Sensitivity: The resolved URLs can change based on the site, language, or environment (staging vs. production), making it hard to ensure consistency and predictability in a multi-site setup.

The Pain Points in a Nutshell

DrawbackImpact in Headless
HTML is a “black box”APIs return a single HTML blob, forcing your consumer applications (like a React or Vue app) to parse HTML instead of working withclean, structured JSON.
Embedded content referencesInline blocks and images aren’t just there—they’re references. Resolving themrequires extra API calls, adding latency.
Link mapping overheadThat automatic link resolution adds latency toevery single delivery request.
Hardcoded domain URLsIf external content comes in with hardcoded URLs, it can break multi-site, staging, andlocalization efforts.
Rendering inflexibilityNeed to deliver your content as plain text, Markdown, or clean JSON? That’s much harderwhen it’s all locked up in a single HTML string.

The Best Practice for Headless Projects

For headless projects, you should always favor structured fields over a single, monolithic XhtmlString.

Instead of a single XhtmlString property, create separate fields for your content, like:

  • Heading (PropertyString)
  • BodyText (PropertyLongString)
  • Image (ContentReference)
  • CTAButton (Custom Block Type)

This approach gives you clean, semantic JSON, and your front-end applications can render it however they need to, from simple web pages to mobile app components.

A Simple Decision Guide

ScenarioUse XhtmlStringUse PropertyLongString
Content is authored by editors in OptimizelyYes. Editors get a greatWYSIWYG experience withautomatic link management.No. You lose rich-textediting and link resolution.
Importing raw HTML that must be preserved exactlyAvoid. Optimizely mayrewrite or tokenize your links,changing the original content.✅ Yes. It stores the raw HTMLwithout any parsing orprocessing.
Links need to automatically update if content movesYes. The permanent linkmapping keeps your links validand functional.No. The links are notprocessed or updated.
Performance is critical for headless delivery❌ Slower. The runtime linkresolution adds overhead,especially with a lot of links.Faster. There’s noprocessing or link resolution atruntime.

By making this choice early in a headless project, you can save yourself from years of complex workarounds and performance bottlenecks down the road.