HomeDev GuideRecipesAPI Reference
Dev GuideAPI ReferenceUser GuideGitHubNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev Guide

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.
🚧

Important

The 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 TypeCMS 12CMS 13
PageTypeSupportedSupported
BlockTypeSupportedSupported
MediaTypeImage, Video, GenericMediaImage, Video, GenericMedia
ExperienceNot supportedSupported
SectionNot supportedSupported

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 SiteId and SiteDefinition. Use _metadata.url.base to 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 _Page and _Component inherit 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 12CMS 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 the default value. Possible values include HIERARCHICAL, 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 string
  • json – A structured representation of the rich text.

The json value follows a tree structure:

  • The root node as type: "richText" and a children array.
  • Each child node has a type (for example, paragraph) and may also have its own children.

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.
  • XhtmlString exposes both HTML and JSON representations by default.
  • ContentArea, ContentAreaItem, ContentReference, and Link properties no longer support Expand. Query referenced content explicitly.
  • All blocks can be queried through the unified _Component interface, simplifying block queries.
  • Queries use _Content and _Media as root fields instead of Content and individual media types.
  • CMS 13 adds support for _metadata, Experiences, external sources, and Variations.