What content Optimizely Graph indexes
Understand which content items Optimizely Graph discovers during a sync, and how to index content that lives outside the default content tree
Optimizely Graph does not scan your database for content to index. It starts from a set of registered indexing roots, which are content items that mark where indexing begins. Graph then walks down the content tree from each root. Content outside every registered root is never discovered, so it never reaches your Graph schema or query results.
Prerequisite
To follow the steps in this article, confirm you have the following:
- A CMS 12, CMS 13, or CMS (SaaS) installation with the Optimizely Graph integration configured.
- Access to deploy code, for the indexing root registration steps.
- CMS administrator access, to run the synchronization job.
How Graph discovers content
Graph indexes IContent instances, which covers pages, blocks, and media. During a full sync, the job loops through every registered indexing root and enumerates the descendants of each. It then sends the resulting content items to Graph.
Graph registers one indexing root by default: the CMS content tree root. This is the Root node at the top of the content tree, not the start page of a site. Every site's start page sits below it, so the default root covers all site content in a standard CMS installation.
One root exists per installation, not per site. A multi-site installation gives each site a start page below the single Root, so Graph indexes every site from that one root.
CMS 12, CMS 13, and CMS (SaaS) all use this model. CMS (SaaS) differs only in configuration, such as the gateway address. No SaaS code path changes how Graph discovers content.
NoteBecause the default root is the top of the content tree, Graph discovers most content in a standard installation without configuration.
Content that Graph does not discover
Content is missing from Graph when it is not reachable by walking down from a registered root. In practice this means content served by a custom content provider whose entry point sits outside the content tree root.
A provider that mounts within the Root subtree is discovered automatically. The tree walk resolves providers as it descends, so it follows the mount point into the provider's own content. Only a provider mounted outside the Root hierarchy is missed.
Commerce Connect is the clearest example. Catalog content lives in its own provider, outside the CMS content tree. Commerce Connect therefore registers its own indexing root, and Graph indexes the catalog. Custom providers you write need the same treatment.
What Graph excludes within a root
Being a descendant of an indexing root is necessary but not sufficient. Graph enumerates everything below each root and then filters the results. Graph excludes content when any of the following applies:
- System root nodes – Graph never indexes five nodes: Root, the Recycle Bin, the Global Assets root, the Content Assets root, and the Blueprints root. This applies to those nodes themselves, not to everything beneath them. Graph indexes media stored under Global Assets normally.
- Deleted content – Graph skips content marked as deleted, which also covers items in the Recycle Bin.
- Content types excluded by convention – Graph skips content types excluded through the conventions API, and every type derived from them.
- Abandoned media assets – Graph skips media in a content assets folder when the owning content no longer exists. Graph logs each one as
Skipped index content '{name}' with key '{key}' since it is in abandoned asset folder. - Unpublished content, when drafts are excluded – This exclusion depends on configuration.
ContentVersionSynchronizationModedefaults toAll, which syncs published, draft, and previously published versions. Graph therefore indexes unpublished content by default.
Note
ContentVersionSynchronizationModeacceptsPublishedOnly,DraftAndPublishedOnly, orAll. If you expected drafts to stay out of Graph, set the mode toPublishedOnlyexplicitly rather than relying on the default.
Register an additional indexing root
Register an indexing root for each content tree you want Graph to index in addition to the default.
CMS 13
Implement IContentIndexingRoot from the Optimizely.Graph.Cms.Content namespace. The interface has two members: a Name used in indexing logs, and the ContentRoot to start from. Graph indexes every descendant of ContentRoot.
using EPiServer.Core;
using Optimizely.Graph.Cms.Content;
public class CatalogIndexingRoot : IContentIndexingRoot
{
private readonly ICatalogSystem _catalogSystem;
public CatalogIndexingRoot(ICatalogSystem catalogSystem)
{
_catalogSystem = catalogSystem;
}
public string Name => "catalog";
public ContentReference ContentRoot => _catalogSystem.GetCatalogRoot();
}Register the implementation during startup:
services.TryAddEnumerable(
ServiceDescriptor.Singleton<IContentIndexingRoot, CatalogIndexingRoot>());Use TryAddEnumerable rather than AddSingleton. Graph then registers your root alongside the default CMS root instead of replacing it.
CMS 12
CMS 12 uses the same pattern with a different interface. Implement IIndexTarget and expose the ContentRoot to start from:
using EPiServer.Core;
using Optimizely.ContentGraph.Cms.Services.Internal;
public class CatalogIndexTarget : IIndexTarget
{
private readonly ICatalogSystem _catalogSystem;
public CatalogIndexTarget(ICatalogSystem catalogSystem)
{
_catalogSystem = catalogSystem;
}
public ContentReference ContentRoot => _catalogSystem.GetCatalogRoot();
}Register it during startup:
services.AddSingleton<IIndexTarget, CatalogIndexTarget>();The synchronization job collects every registered IIndexTarget, takes the distinct set of roots, and walks the descendants of each.
Run a full sync after you add a root
Registering an indexing root changes only what future sync runs discover. It does not backfill content that earlier runs skipped.
After you deploy an indexing root, run the full synchronization job so Graph receives the newly reachable content:
- Go to Admin > Scheduled Jobs.
- Select the full synchronization job.
- Click Start Manually.
Content indexed outside a registered root
Full sync is not the only path into the index. Delta sync reads the activity log, and event-driven indexing subscribes to CMS events. Neither one checks where the content sits in the tree, so both can index content that no registered root reaches.
A regular full sync does not undo this. Full sync only adds and updates the content it discovers. It does not delete content that it failed to reach, so content indexed from outside a registered root stays in the index.
A smooth rebuild does undo it. A smooth rebuild provisions a new slot, runs a full sync into that slot, and then swaps it live. The new slot holds only the content the tree walk discovered, plus the delta changes caught during the sync. Content outside every registered root is absent from the new slot and disappears when the rebuild commits.
WarningContent that reaches Graph only through delta or event-driven indexing disappears at the next smooth rebuild commit. If you rely on content that no registered root reaches, register a root for it before you run a smooth rebuild.
Troubleshoot missing content
If a content item does not appear in Graph, work through the following:
- Check the content's position in the tree. Confirm the item is a descendant of a registered indexing root. If a custom content provider serves it, confirm that provider's entry point is covered by a root.
- Confirm a full sync has run. Event-driven indexing covers changes as editors publish them. Only a full sync picks up content that predates your Graph setup.
- Check the exclusion rules. Work through What Graph excludes within a root. Deleted content, excluded content types, and abandoned media assets are the common causes.
- Check the synchronization job logs. Graph logs some skip reasons and not others, so a silent skip does not mean the content was indexed. See the following table.
- Check property-level indexing. If the item appears but a field is missing, the cause is the property's indexing type, not content discovery. See Control field indexing.
Skip reasons Graph logs
The job summary lists items with an explicit skip reason as {contentReference}: Skipped due to {message}. Only some reasons produce a message:
| Skip reason | Logged | Message |
|---|---|---|
| Abandoned media asset | Yes | Skipped index content '{name}' with key '{key}' since it is in abandoned asset folder |
| Unsupported content type | Yes | The content type '{contentType}' is currently not supported. Content '{contentName}' ({contentGuid:N}) will not be indexed. |
| Document over the size limit | Yes | Skipped indexing document {id} due to being larger than {size} MB. |
| Reserved property name | Yes | Reserved name |
| System content node | No | Silent |
| Content type excluded by convention | No | Silent |
| Deleted content | No | Silent |
| Unpublished content, when drafts are excluded | No | Silent |
| Not a descendant of a registered root | No | Silent |
Content that no registered root reaches produces no message at all, because the full sync never encounters it. Rule that cause out by checking the content's position in the tree rather than by searching the logs.
Related documentation
This page covers which content items Graph indexes. For how the properties of those items are indexed, and how to stay within the 100,000-field limit, see Control field indexing.
Updated about 11 hours ago
