CMS 13 and 12 Graph comparison
Understand the Graph query and output differences between Content Management System (CMS 13) and CMS 12, focusing on the following areas:
- Differences in content type structures.
- Differences in GraphQL schema.
- Comparison of property structures, including illustrative examples of queries and responses.
- Querying with Experience-based content.
- Comparison of Content Graph features.
ImportantThe schema changes outlined below are breaking changes upon upgrade from CMS 12 to CMS 13. Review the changes to update your queries accordingly.
Content type comparison
Below is a comparison of content types in CMS 12 and CMS 13.
| Content Type | CMS 12 | CMS 13 |
|---|---|---|
| PageType | Supported | Supported |
| BlockType | Supported | Supported |
| MediaType | Image, Video, GenericMedia | Image, Video, GenericMedia |
| Experience | Not supported | Supported |
| Section | Not supported | Supported |
GraphQL schema comparison
Both CMS 12 and CMS 13 support standard GraphQL features, including queries with cursor, ids, limit, locale, skip, orderBy, pinned, where, facets, _fulltext, _and, _or, _not, _link, _children, _score, _json, _track, __modified, and _deleted.
Key differences:
- CMS 12 exposes each content type as a separate root-level query.
- CMS 13 introduces a unified, inheritance-based schema and adds support for
_metadata, Experiences, external sources, and Variations. - CMS 13 introduces changes to property query structures and output formats.
- CMS 13 no longer supports queries with
SiteIdandSiteDefinition. Use_metadata.url.baseto return only content belonging to a specific site.
CMS 13 defines base schema types (prefixed with _) including:
_Content, _Page, _Component, _Media, _Folder, _Experience, _Image, _Video, _Section, _Item, _AssetItem, _ImageItem.
Custom content types inherit from these base types. For example:
- A page type (
NewsPage) might inherit from_Page. - A block type (
TeaserBlock) might inherit from_Component. - Both
_Pageand_Componentinherit from_Content.
This inheritance model results in a more consistent and extensible schema, enabling uniform queries across different content types.
Property query comparison
Metadata properties
The following table compares equivalent metadata properties between CMS 12 and CMS 13. In CMS 13, metadata is exposed through the unified _metadata object, whereas CMS 12 exposes similar information through dedicated fields.
| CMS 12 | CMS 13 |
|---|---|
ContentLink { GuidValue } | _metadata { key } |
Language { Name } | _metadata { locale } |
ExistingLanguages { Name } | _metadata { locales } |
ContentLink { WorkId } | _metadata { version } |
ContentType | _metadata { types } |
Name | _metadata { displayName } |
StartPublish | _metadata { published } |
StopPublish | _metadata { expired } |
Status | _metadata { status } |
ParentLink { Id } | _metadata { container } |
Url | _metadata { url { base, default, graph, hierarchical, internal, type } } |
RouteSegment | _metadata { routeSegment } |
| Not available | _metadata { path } |
| Not available | _metadata { owner } |
| Not available | _metadata { ... on InstanceMetadata { expired } } |
| Not available | _metadata { ... on InstanceMetadata { lastModifiedBy } } |
| Not available | _metadata { ... on InstanceMetadata { createdBy } } |
Sample query comparison using metadata (IContentMetadata)
CMS 12 query:
query MyQuery {
Content(where: { Name: { eq: "Start2" } }) {
items {
ContentLink {
GuidValue
Id
WorkId
Url
}
Language {
Link
DisplayName
Name
}
Name
StartPublish
Status
Created
Changed
_sortOrder
ContentType
Url
}
}
}CMS 13 query:
query MyQuery {
_Content(where: { _metadata: { displayName: { eq: "Start2" } } }) {
items {
_metadata {
key
locale
version
displayName
published
status
changeset
created
lastModified
sortOrder
variation
types
url {
type
default
hierarchical
internal
graph
base
}
}
}
}
}CMS 12 result:
{
"data": {
"Content": {
"items": [
{
"ContentLink": {
"GuidValue": "337c7c36-1998-4a64-b3e1-ea4e544fdf76",
"Id": 1405,
"WorkId": 1704,
"Url": "https://localhost:8039/en/start2/"
},
"Language": {
"Link": "https://localhost:8039/en/start2/",
"DisplayName": "English",
"Name": "en"
},
"Name": "Start2",
"StartPublish": "2025-11-05T03:33:17Z",
"Status": "Published",
"Created": "2025-11-05T03:33:10Z",
"Changed": "2025-11-05T03:33:17Z",
"_sortOrder": 1700,
"ContentType": ["Page", "StartPage", "Content"],
"Url": "https://localhost:8039/en/start2/"
}
]
}
}
}CMS 13 result:
{
"data": {
"_Content": {
"items": [
{
"_metadata": {
"key": "f565ddf42213425390fdbad7147d2a06",
"locale": "en",
"version": "8",
"displayName": "Start2",
"published": "2025-11-24T04:14:09.698Z",
"status": "Published",
"changeset": "default",
"created": "2025-11-24T04:13:53.504Z",
"lastModified": "2025-11-24T04:14:09.698Z",
"sortOrder": 0,
"variation": null,
"types": ["StartPage", "_Page", "_Content", "_Item"],
"url": {
"type": "HIERARCHICAL",
"default": "/en/start2/",
"hierarchical": "/en/start2/",
"internal": "cms://content/f565ddf42213425390fdbad7147d2a06?loc=en&ver=8",
"graph": "graph://cms/StartPage/f565ddf42213425390fdbad7147d2a06",
"base": "https://localhost:8001"
}
}
}
]
}
}
}Graph on CMS 13 no longer supports queries with SiteId and SiteDefinition, so users can scope queries to a site by _metadata.url. This ensures that only content belonging to the specified site (based on hostname) is returned. Ex:
query {
_Content(
where: {
_metadata: {
url: {
base: { eq: "https://site-a.com" }
}
}
}
) {
items {
_id
_metadata {
url {
base
}
}
}
}
}In CMS 13, metadata is structured into different scopes to clearly separate content lifecycle, content identity, and media-specific information.
InstanceMetadata
Use when querying standalone content instances, such as pages and blocks. To access instance-level details, cast _metadata on those root items to InstanceMetadata, which inherits IContentMetadata but adds additional properties. For example:
container– the key of the content item that contains this item.owner– the key of the owning content item if the content is in an asset to another content item.path– specifies the hierarchy of containers.
InstanceMetadata query example:
query MyQuery {
_Content(where: { _metadata: { displayName: { eq: "Start2" } } }) {
items {
_metadata {
displayName
... on InstanceMetadata {
routeSegment
container
createdBy
expired
lastModifiedBy
locales
owner
path
}
}
}
}
}InstanceMetadata result:
{
"data": {
"_Content": {
"items": [
{
"_metadata": {
"displayName": "Start2",
"routeSegment": "start2",
"container": "dd3adb7ae0884449a1eed6c7f1dffdef",
"createdBy": "[email protected]",
"expired": null,
"lastModifiedBy": "[email protected]",
"locales": ["en"],
"owner": null,
"path": [
"dd3adb7ae0884449a1eed6c7f1dffdef",
"f565ddf42213425390fdbad7147d2a06"
]
}
}
]
}
}
}ItemMetadata
Use for content items that appear inside a container, such as entries in a ContentArea. For content items under ContentArea or ContentAreaItem, cast _metadata to ItemMetadata, which inherits IContentMetadata but adds additional properties like displayOption.
ItemMetadata query example:
query MyQuery {
StandardPage(where: { _metadata: { displayName: { eq: "StandardPage3" } } }) {
items {
_metadata {
displayName
key
}
ContentArea {
_metadata {
... on ItemMetadata {
displayOption
locale
key
}
}
}
}
}
}ItemMetadata result:
{
"data": {
"StandardPage": {
"items": [
{
"_metadata": {
"displayName": "StandardPage3",
"key": "0076eb95f7e0425ea082197d2bb039a8"
},
"ContentArea": [
{
"_metadata": {
"displayOption": null,
"locale": "en",
"key": "f565ddf42213425390fdbad7147d2a06"
}
},
{
"_metadata": {
"displayOption": null,
"locale": "en",
"key": "b8a60749ef584cedbaf111a4f93ae15d"
}
}
]
}
]
}
}
}MediaMetadata
Use for media content such as images, videos, and other media files. Cast _metadata to MediaMetadata, which also inherits IContentMetadata but adds additional properties like container, mimeType, and thumbnail.
MediaMetadata query example:
query MyQuery {
_Content(where: { _metadata: { displayName: { eq: "Image1.png" } } }) {
items {
_metadata {
displayName
... on MediaMetadata {
container
content
createdBy
expired
lastModifiedBy
locales
mimeType
owner
path
routeSegment
thumbnail
}
}
}
}
}MediaMetadata result:
{
"data": {
"_Content": {
"items": [
{
"_metadata": {
"displayName": "Image1.png",
"container": "e56f85d0e8334e02976a2d11fe4d598c",
"content": "A beautiful picture",
"createdBy": "[email protected]",
"expired": null,
"lastModifiedBy": "[email protected]",
"locales": [],
"mimeType": "image/png",
"owner": null,
"path": ["aabdb22fd36c4044af0b14cc31efb292"],
"routeSegment": "Image1",
"thumbnail": "https://app-sactmain242x8byp001.cmstest.optimizely.com/globalassets/Image1//thumbnail"
}
}
]
}
}
}Standard primitive properties
In GraphQL, standard primitive property types such as String, Int, Boolean, DateTime, Float, Guid, and Choice are queried in the same way and return responses in a consistent format.
CMS 12 query:
query MyQuery {
StandardPage(where: { Name: { eq: "StandardPage3" } }) {
items {
p_String
p_Select
p_Int
p_Guid
p_Date
p_Choice
}
}
}CMS 13 query:
query MyQuery {
StandardPage(where: { _metadata: { displayName: { eq: "StandardPage3" } } }) {
items {
p_String
p_Select
p_Int
p_Guid
p_Date
p_Choice
}
}
}Both versions return similar result structures. The primary difference is in how the where filter references content (by Name in CMS 12 versus _metadata.displayName in CMS 13).
Query referenced properties
In CMS 12, referenced content can be expanded through ContentArea, ContentAreaItem, ContentReference, LinkItem, LinkItemCollection, and similar properties. In CMS 13, referenced content can only be queried when added to ContentArea or ContentAreaItem. Other property types like ContentReference, PageReference, and LinkItem only contain information on the link.
ContentArea or ContentAreaItem properties
In CMS 12, ContentArea items can be queried through ContentLink.Expanded, which returns the referenced data. In CMS 13, this expansion model is removed, and referenced content must be queried explicitly using inline fragments or fragments.
CMS 12 query:
query MyQuery {
StandardPage(where: { Name: { eq: "StandardPage1" } }) {
total
items {
MainContentArea {
InlineBlock {
ContentType
}
DisplayOption
ContentLink {
GuidValue
Id
ProviderName
Url
WorkId
Expanded {
... on ButtonBlock {
Name
Created
Url
ButtonText
}
}
}
}
}
}
}CMS 13 query:
query MyQuery {
StandardPage(where: { _metadata: { displayName: { eq: "StandardPage1" } } }) {
total
items {
MainContentArea {
... on ButtonBlock {
_metadata {
key
locale
fallbackForLocale
version
displayName
published
status
changeset
created
lastModified
sortOrder
variation
types
url {
type
default
hierarchical
internal
graph
base
}
}
ButtonText
}
}
}
}
}An example query when a ContentArea contains multiple block types with inline fragments:
query MyQuery {
StandardPage(where: { _metadata: { displayName: { eq: "StandardPage2" } } }) {
total
items {
MainContentArea {
... on ButtonBlock {
_metadata {
version
created
key
}
ButtonText
}
... on EditorialBlock {
_metadata {
displayName
key
}
_id
}
... on TeaserBlock {
_metadata {
displayName
key
}
Text
}
}
}
}
}An example query when a ContentArea contains multiple block types with fragments:
query MyQuery {
StandardPage(where: { _metadata: { displayName: { eq: "StandardPage2" } } }) {
total
items {
MainContentArea {
_metadata {
displayName
key
}
...ButtonBlockFragment
...EditorialBlockFragment
...TeaserBlockFragment
}
}
}
}
fragment ButtonBlockFragment on ButtonBlock {
_metadata {
version
}
ButtonText
}
fragment EditorialBlockFragment on EditorialBlock {
_id
}
fragment TeaserBlockFragment on TeaserBlock {
Text
}Recursive queries on ContentArea
In CMS 12, the @recursive directive applies to ContentArea.ContentLink.Expanded with a maximum depth of three levels by default. CMS 13 removes the Expanded field and applies recursion directly to the ContentArea property using the @recursive directive, typically inside a fragment. This approach provides cleaner queries and more reliable access to deeply nested or cyclic ContentArea structures.
CMS 12 recursive query:
query MyQuery {
StandardPage(where: { Name: { eq: "StandardPage1" } }) {
items {
ContentArea {
ContentLink {
Expanded {
Name
...ContentAreaBlock
}
}
}
}
}
}
fragment ContentAreaBlock on ContentAreaBlock {
Name
ContentType
ContentArea {
ContentLink {
Expanded @recursive(depth: 10) {
Name
ContentType
}
}
}
}CMS 13 recursive query:
query MyQuery {
StandardPage(where: { _metadata: { displayName: { eq: "StandardPage1" } } }) {
items {
MainContentArea {
_metadata {
displayName
}
...ContentAreaBlock
}
}
}
}
fragment ContentAreaBlock on ContentAreaBlock {
_metadata {
displayName
types
}
cultureContentArea @recursive(depth: 10) {
_metadata {
displayName
}
}
}ContentReference and ContentReferenceList properties
In CMS 12, ContentReference and ContentReferenceList properties expand and return the referenced content through the Expanded field. In CMS 13, these properties return only a structured url object and a stable key. Query the referenced content explicitly if needed.
CMS 12 query:
query MyQuery {
StandardPage(where: { Name: { eq: "StandardPage1" } }) {
total
items {
ContentReference {
GuidValue
Id
Url
WorkId
Expanded {
Url
ContentLink {
Id
GuidValue
Url
WorkId
}
}
}
}
}
}CMS 13 query:
query MyQuery {
StandardPage(where: { _metadata: { displayName: { eq: "StandardPage1" } } }) {
total
items {
ContentReference {
url {
type
default
hierarchical
internal
graph
base
}
key
}
}
}
}In CMS 13, ContentReference and ContentReferenceList properties reference content from external sources and CMS-managed content. Retrieve external items through the ContentReference.item field for unified querying of internal and external content through Optimizely Graph.
External content reference query example:
query MyQuery {
StandardPage(where: { _metadata: { displayName: { eq: "StandardPage1" } } }) {
total
items {
ContentReference {
url {
type
default
hierarchical
internal
graph
base
}
key
item {
_id
... on GraphShadowType {
Name
Id
_id
_modified
}
}
}
}
}
}External content reference result:
{
"data": {
"StandardPage": {
"total": 1,
"items": [
{
"ContentReference": {
"url": {
"type": "GRAPH",
"default": null,
"hierarchical": null,
"internal": "cms://content/43fd8aecaad245d3b59b0db48c615cdb",
"graph": "graph://shadow/GraphShadowType/101",
"base": null
},
"key": "43fd8aecaad245d3b59b0db48c615cdb",
"item": {
"_id": "2",
"Name": "Shakespeare",
"Id": 101,
"_modified": "2025-12-12T06:52:21Z"
}
}
}
]
}
}
}LinkItem, LinkItemList, and LinkItemCollection properties
In CMS 12, link data is retrieved through Href and ContentLink with expanded content details. CMS 13 simplifies the model by exposing a unified url object with structured URL types. LinkItem, LinkItemList, and LinkItemCollection properties no longer expand referenced content directly.
CMS 12 query:
query MyQuery {
StandardPage(where: { Name: { eq: "StandardPage1" } }) {
total
items {
LinkItem {
Title
Text
Target
Href
ContentLink {
Id
WorkId
GuidValue
Url
Expanded {
Name
Created
}
}
}
}
}
}CMS 13 query:
query MyQuery {
StandardPage(where: { _metadata: { displayName: { eq: "StandardPage1" } } }) {
total
items {
LinkItem {
title
text
target
url {
type
default
hierarchical
internal
graph
base
}
}
}
}
}Url and UrlList properties
In CMS 12, Url and UrlList properties return plain string values. In CMS 13, these properties return structured objects with multiple representations (default, hierarchical, internal, graph, and base). This approach provides richer and more consistent URL handling. The graph schema for Url includes the following fields:
default– The default URL for the content instance.type– Describes the type for thedefaultvalue. Possible values includeHIERARCHICAL,INTERNAL,EXTERNAL, and others.hierarchical– The path for the content item, based on the hierarchical structure within CMS 13.internal– A permanent URL to the content item. This format is used within the integration API to reference content items.base– The authority for the content item. This depends on the application configuration with CMS 13.
CMS 12 query:
query MyQuery {
StandardPage(where: { Name: { eq: "StandardPage1" } }) {
total
items {
UrlToImage
}
}
}CMS 13 query:
query MyQuery {
StandardPage(where: { _metadata: { displayName: { eq: "StandardPage1" } } }) {
total
items {
UrlToImage {
type
default
hierarchical
internal
graph
base
}
}
}
}XhtmlString and XhtmlStringList properties
In CMS 12, XhtmlString and XhtmlStringList properties return raw HTML as a plain string by default. CMS 13 returns rich text as a structured object that includes rendered HTML and a JSON representation. This structure enables more flexible rendering and content processing on the front end. By default, the XhtmlString property returns the following:
html– The rendered HTML stringjson– A structured representation of the rich text.
The json value follows a tree structure:
- The root node as
type: "richText"and achildrenarray. - Each child node has a
type(for example,paragraph) and may also have its ownchildren.
CMS 12 query:
query MyQuery {
StandardPage(where: { Name: { eq: "StandardPage1" } }) {
items {
XhtmlString
}
}
}CMS 13 query:
query MyQuery {
StandardPage(where: { _metadata: { displayName: { eq: "StandardPage1" } } }) {
items {
XhtmlString {
html
json
}
}
}
}CMS 12 result:
{
"data": {
"StandardPage": {
"items": [
{
"XhtmlString": "<p>Apple is red!</p>"
}
]
}
}
}CMS 13 result:
{
"data": {
"StandardPage": {
"items": [
{
"XhtmlString": {
"html": "<p>Apple is red!</p>",
"json": {
"type": "richText",
"children": [
{
"type": "paragraph",
"children": [
{
"text": "Apple is red!"
}
]
}
]
}
}
}
]
}
}
}Experience query on CMS 13
In CMS 13, Visual Builder introduces a layout-and-composition-based approach to content creation. This approach uses small, reusable content units. An Experience functions like a Page but also supports layouts and unstructured editor-added content. Experiences organize content as an ordered list of Sections. Sections and Elements extend Blocks. Sections act as layout containers, while Elements represent the smallest content units and contain the actual content data. Elements act as leaf nodes in the composition tree with no child elements.
The following example query retrieves data for Experiences, Sections, and Elements through GraphQL. An Experience contains a composition field. The composition is a tree of nodes. CompositionStructureNode represents layout containers (Sections). CompositionComponentNode represents content units (Elements). Structure nodes can contain other nodes; component nodes are leaf nodes.
fragment _IComponent on _IComponent {
__typename
... on BlankSection {
longString
string
xhtmlString {
html
}
Int
contentArea {
_metadata {
key
displayName
}
... on _Content {
_metadata {
created
version
}
}
}
contentReference {
key
url {
default
base
}
}
block {
Description
}
}
... on ContentAreaBlock {
_metadata {
displayName
types
}
Link {
Heading
Text
}
}
}
fragment ElementFields on Element {
Name
Time
Number
}
fragment _IExperience on _IExperience {
composition {
...ICompositionNode
}
}
fragment ICompositionNode on ICompositionNode {
... on CompositionStructureNode {
key
displayName
nodeType
layoutType
component {
..._IComponent
}
nodes @recursive {
type
nodeType
layoutType
displayName
key
displayTemplateKey
}
}
... on CompositionComponentNode {
key
displayName
nodeType
component {
..._IComponent
...ElementFields
}
}
}
fragment BlankExperience on BlankExperience {
..._IExperience
}
query MyQuery {
_Content(where: { _metadata: { displayName: { contains: "BlankExper236" } } }) {
item {
__typename
_metadata {
displayName
version
}
...BlankExperience
}
}
}Variation query on CMS 13
In CMS 13, editors can create one or more variations of a page or an experience. A unique string in the variation field on the content metadata identifies each variation. By default, GraphQL queries return only the original (non-variation) content. Query specific variations or retrieve all variations using the variation filter.
Retrieve all variations of a content item:
query GetAllVariations {
_Content(variation: { include: ALL, includeOriginal: true }) {
items {
_metadata {
key
displayName
}
}
}
}Retrieve specific variations:
query variation {
_Content(
where: { _metadata: { displayName: { eq: "Rainrain" } } }
variation: { includeOriginal: false, include: SOME, value: "Variation_2" }
) {
items {
_metadata {
variation
displayName
}
}
}
}Retrieve only default content (no variations):
query GetOnlyDefaultContent {
_Content(variation: { include: NONE, includeOriginal: true }) {
items {
_metadata {
displayName
variation
}
}
}
}Optimizely Graph features
Core Content Graph features such as _children, _link, full-text search, filtering through search providers, and fuzzy search remain functionally consistent between CMS 12 and CMS 13. CMS 13 retains these capabilities and introduces a more normalized and composable schema, requiring updates to query structure rather than changes to feature behavior.
Conclusion
CMS 13 introduces significant structural improvements through Optimizely Graph and the Experience model. These changes fundamentally alter how content is queried compared to CMS 12.. Key differences include the following:
- URLs are returned as structured objects instead of plain strings.
XhtmlStringexposes both HTML and JSON representations by default.ContentArea,ContentAreaItem,ContentReference, and Link properties no longer supportExpand. Query referenced content explicitly.- All blocks can be queried through the unified
_Componentinterface, simplifying block queries. - Queries use
_Contentand_Mediaas root fields instead ofContentand individual media types. - CMS 13 adds support for
_metadata, Experiences, external sources, and Variations.
Updated 2 days ago
