Editing architecture
The framework-agnostic documentation is under development. If you have suggestions for improving the content, let us know by sharing your Feedback at the bottom of this page.
The SitecoreAI Page builder provides content authors with a WYSIWYG canvas for editing pages, but it doesn't render your site pages. Instead, it delegates rendering to your app by loading the app inside an iframe. When you enable visual editing, your app renders the page HTML, embeds structural metadata into the HTML, and returns the result to the Page builder.
Handshake endpoints
For your app and the Page builder to securely communicate, your app must expose two editing API endpoints that the Page builder will call:
/api/editing/config- the Page builder makesGETandOPTIONSrequests first to confirm your app supports metadata editing mode and to get the list of registered components./api/editing/render- for every page view inside the editor, the Page builder loads the editing canvas by setting the iframe src to this endpoint with the relevant parameters in the URL. The browser makes theGETrequest, and your app uses those parameters to fetch the editing layout data from Sitecore, renders the full page HTML with metadata code blocks embedded, and returns the complete HTML document to the browser.
Note that the /api/editing/config and /api/editing/render paths shown in this documentation are conventional defaults, not fixed values:
- The URL the Page builder calls for the
configendpoint is what is stored in the Server side rendering engine application URL field on the corresponding item under/sitecore/system/Settings/Services/Rendering Hosts/*. Most implementations don't need to change this. - Unlike the
configendpoint, therenderendpoint's path is not configurable on the Rendering Host item.
Both endpoints are protected by a shared secret, typically named SITECORE_EDITING_SECRET.
In addition to validating the shared secret, check the request's Origin header and restrict CORS responses to Sitecore's Page builder domains (for example, https://pages.sitecorecloud.io and https://app.sitecorecloud.io). Configure your Content-Security-Policy frame-ancestors directive the same way so that only the Page builder can load your app in an iframe. For an example implementation, see the CORS handling shown in the Enable visual editing walkthrough.
How editing works
When a content author opens a page in the Page builder, the following happens:
- The Page builder calls your app's
/api/editing/configendpoint the first time it connects to an editing host. For example, when the Page builder first loads, or when you switch editing hosts. Your app validates the secret and returns a JSON document declaringÂ"editMode": "metadata"Â and the component names your app can render. This documentation only coversmetadatamode, the modern editing mode that replaces the legacychromesmode. - The Page builder opens the canvas by loading an iframe. The iframe's
srcpoints to your app's/api/editing/renderendpoint, with query parameters that identify the page, site, language, and version being edited. Note that the render endpoint always returns a complete HTML document, not a fragment. - Using the parameters, your app retrieves the editing layout data from the Preview GraphQL API. The response includes field values, the component tree, and editing-specific metadata for each field.
- Your app renders a complete HTML document, embeddingÂ
<code>Â metadata blocks around every placeholder, component, and field value, along with the Sitecore-provided canvas scripts inÂ<head>. The<head>must also include your app's own CSS and JavaScript assets to ensure the page renders with the correct styles and scripts in the editing canvas, just as it does on the published site. After the browser loads this HTML in the iframe, the Sitecore-provided canvas scripts activate editing overlays and scan the<code>markers to map on-screen elements to their Sitecore items.
The config response
Your /api/editing/config endpoint must return a JSON document with the following shape:
| Property | Description |
|---|---|
editMode | Must be "metadata" to use metadata editing mode. |
components | The list of Sitecore component (rendering) names your app can render. Each name must match the name of the corresponding rendering item in Sitecore. |
packages | An optional map of package versions. Leave this an empty object for custom apps. |
The Page builder uses components to determine which renderings it can add to a page from your app. A rendering that isn't in this list can still exist in Sitecore, but content authors won't be able to add it to a page through the Page builder while editing with your app.
The editing GraphQL query
When rendering content in your app, you retrieve layout data by route path using the layout query. The editing query differs in two ways:
- It looks up the page by item ID, not by route path.
- It sends two additional HTTP headers.
Item ID
The Page builder identifies pages by their Sitecore item ID (GUID), not by route path. The editing query uses item(path: $itemId) and passes the GUID directly. It also retrieves the site dictionary alongside the layout data, so that any translation keys your components use are available when rendering the editing HTML:
The rendered field returns layout data in the same JSON shape as the layout query used for content rendering. The $pageSize and $after variables support cursor-based pagination for sites with large dictionaries.
The site dictionary is a flat key-value store of translation strings managed in Sitecore. For example, button labels, form placeholders, and other UI text that content authors translate independently of component field content. The dictionary is returned with the layout data and is available for apps where component renderers need to resolve translation keys at render time. The sample apps in the Enable visual editing walkthrough retrieve the dictionary but don't consume it because their components don't contain translatable UI strings.
HTTP headers
The editing query sends two HTTP headers in addition to the standard x-sitecore-contextid header:
| Header | Description |
|---|---|
sc_editMode | When "true", the Preview GraphQL API returns draft (unpublished) content and adds a metadata property to every field object in the layout data.Set this value to "true" when the Page builder opens a page in edit mode, and "false" for preview mode. |
sc_layoutKind | The layout type to return, which can be shared or final.The default is final. |
The metadata property that sc_editMode: "true" adds to each field object makes inline editing possible. The Page builder uses it to identify which field a content author is interacting with. Without this header, metadata is absent and field chromes cannot be activated.
For the complete query implementation in your framework, see Enable visual editing.
Metadata editing mode
Metadata editing mode is Sitecore's modern editor integration strategy. It uses metadata provided by the layout service for placeholders, renderings, and fields. The Page builder uses this metadata to identify editable layout elements and enable component selection and reordering.
In metadata editing mode, your app wraps every placeholder, component, and field in a pair of <code> elements. The Page builder's JavaScript reads these to identify which parts of the rendered HTML correspond to which Sitecore items and fields. This lets the Page builder build a map of editable regions. That map is what lets content authors click a component, see its selection handles, drag it to a new position, and open the component's fields panel.
Here's an example of what the rendered HTML looks like inside the editor:
Note the following about the id attributes:
- The placeholder
idattribute is<placeholderKey>_<parentUID>, whereparentUIDis theuidof the parent rendering or route item that owns the placeholder. - The component
idattribute is the component's ownuidfrom the layout data.
The Page builder uses these IDs to connect each on-screen element to a specific Sitecore item so it knows what to update when a content author makes a change.
Field chromes
Component-level <code> blocks let the Page builder select and reorder components. To let content authors also edit field values inline, for example, clicking directly on a headline or paragraph and typing, you must also wrap each individual field value in its own pair of <code> blocks. This additional layer activates the content-editable surface so a content author can click on text and type.
When sc_editMode: "true" is set in the GraphQL request, the layout data includes a metadata object on each field. The opening code block serializes that metadata as its text content. When the Page builder loads the page, it reads these blocks to activate a content-editable surface over each field value:
Without field chromes, components are selectable in the canvas, but content authors cannot edit any fields inline. In other words, they can highlight text, but typing has no effect.
Editing scripts
Component and field chromes tell the Page builder what is on the page. The editing scripts tell it how to interact with the page.
When sc_editMode is "true", the sitecore.context object in the editing layout data response includes fields that the Page builder uses to enable editing interactions in the canvas. Your /api/editing/render endpoint must embed these fields in the HTML that it returns to the Page builder, in addition to your app's own CSS and JavaScript assets:
clientScripts- an array of JavaScript URLs. The Page builder loads these scripts into the canvas iframe to attach editing overlays and interaction handlers. Without them, the canvas loads your page but has no way to receive or send editing events.clientData- a map of two values your app must write intoÂ<script> tags with specific IDs:hrz-canvas-state- a JSON object that tells the editing scripts which item, site, language, and layout mode the canvas is displaying.hrz-canvas-verification-token- a token that authenticatesÂpostMessage messages between the iframe and the Page builder. Without it, the Page builder ignores signals from the iframe.
The HTML your app renders must embed these in the <head> and <script> tags:
The HTML your app renders must also include a <script> element with id="jss-hrz-editing" in the <body>. The Page builder checks for this element to confirm the app is responding in metadata editing mode:
Query parameters for the render endpoint
When the Page builder loads the editing canvas, it sets the iframe src to your app's /api/editing/render URL. The browser then makes a GET request with the following query parameters:
| Query parameter | Description |
|---|---|
secret | Required. Must match SITECORE_EDITING_SECRET. |
sc_site | Required. The site name. Example: my-site |
sc_itemid | Required. The Sitecore item ID (GUID) of the page being edited. |
sc_lang | Required. The page's language code. Example: en |
route | Required. The route path to the page. Example: / and /products |
mode | Required.edit for the editing canvas, or preview for preview mode. |
sc_version | Optional. Item version. Use a numeric version number, or latest to explicitly request the most recent version. If unset, the latest version of the item is retrieved. |
sc_variant | Optional. Personalization variant ID. |
sc_layoutKind | Optional. The layout type, which can be shared or final.The default is final. |
Example request
Here's an example GET request that the Page builder makes to the render endpoint:
The sc_version, sc_variant, and sc_layoutKind parameters are all optional and may be omitted.