---
title: Configure CMS 12 to send content
slug: graph/docs/configure-cms-12-to-send-content
docTags: 
createdAt: 2026-07-30T20:30:18.526Z
---

Optimizely Optimizely Graph integrates with Content Management System 12 (CMS 12) to automatically sync content changes. This guide covers set up, configuration, and best practices for CMS integration.

## Architecture Overview

The data flow between Optimizely CMS and Optimizely Graph works as follows:

1. **Authoring** – A content editor creates, updates, moves, or deletes content in Optimizely CMS.
2. **Event capture** – CMS integration package listens for content lifecycle events, such as SavedContent, PublishedContent, MovedContent, DeletedContent, or ExpiredContent.
3. **Serialization** – The integration serializes the changed content into JSON that matches Optimizely Graph schema.
4. **Transfer** – The serialized content is securely sent to Optimizely Graph Gateway over HTTPS.
5. **Processing** – The gateway validates, enriches, and indexes the content into Optimizely Graph.
6. **Availability** – The content is queryable through Optimizely Graph GraphQL API by websites, applications, or other services.

## Installation

1. Install NuGet Package
   - Package Manager Console: `Install-Package Optimizely.ContentGraph.Cms`
   - .NET CLI: `dotnet add package Optimizely.ContentGraph.Cms`
   - PackageReference in .csproj: `<PackageReference Inclide ="Optimizely.ContentGraph.Cms"Version="version_number" />`
2. Verify Package Installation
   Ensure your project file (.csproj) contains the package reference stated previously

## Configuration

`appsettings.json` example:

```json
{
  "Optimizely": {
    "ContentGraph": {
      "GatewayAddress": "https://cg.optimizely.com",
      "AppKey": "your-hmac-app-key",
      "Secret": "your-hmac-secret-key",
      "SingleKey": "your-single-key-for-public-access",
      "BufferedIndexingGracePeriod": 10000,
      "PreventFieldCollision": true
    }
  }
}
```

### Configuration Properties

- `GatewayAddress` – Optimizely Graph Gateway endpoint URL
- `AppKey` – HMAC authentication public key
- `Secret` – HMAC authentication secret key
- `SingleKey` – Simple authentication key for read-only access
- `AllowSendingLog` – Enable detailed logging
- `MaxBatchSize` - Maximum items per batch (default 300)
- `BufferedIndexingGracePeriod` – Grace period in ms for batching (default 0)
- `ExtractMedia` – Enable text extraction from media files (default true)
- `PreventFieldCollision` – Prevent GraphQL field collisions (default false)
- `MarkRequiredPropertiesToGraph` – Mark required fields in Graph schema (default false)

## CMS Setup

### Basic Configuration in Startup.cs

```csharp
public void ConfigureServices(IServiceCollection services)
{
    services.AddContentDeliveryApi();
    services.AddContentGraph();
    services.AddMvc();
    services.AddCms();
}
```

:::hint{type="info"}
**Note**
Always call `AddContentDeliveryApi()` before `AddContentGraph()`.
:::

### Advanced Configuration

```csharp
public void ConfigureServices(IServiceCollection services)
{
    services.AddContentDeliveryApi();
    
    services.AddContentGraph(options =>
    {
        // Schema Configuration
        options.PreventFieldCollision = true;
        options.IncludeInheritanceInContentType = true;
        options.MarkRequiredPropertiesToGraph = true;
        
        // Content Expansion Settings
        options.ExpandLevel.ContentArea = 2;      // Expand ContentAreas 2 levels deep
        options.ExpandLevel.Default = 0;          // Don't expand other references
        options.ExpandLevel.ContentReference = 1; // Expand ContentReference 1 level
        
        // Batching Configuration
        options.BufferedIndexingGracePeriod = 10000; // 10 seconds in milliseconds
        options.MaxBatchSize = 50;
        
        // Media extraction
        options.ExtractMedia = true;
        
        // Preview Configuration
        options.Events.OnGeneratingPreviewUrl = context =>
        {
            // Custom preview URL generation
            var previewUrl = $"/preview?id={context.ContentReference}&token={GeneratePreviewToken(context)}";
            context.UpdateUrl(new Uri(previewUrl, UriKind.RelativeOrAbsolute));
            return Task.CompletedTask;
        };
    });
    
    // Configure event indexing behavior
    services.Configure<EventIndexingOptions>(options =>
    {
        options.IndexReferencingContent = ReferencingPropertyTypes.Inlined;
        options.SyncContentsInParallelTaskAndForget = false; // Set to false for synchronous processing
    });
}
```

## Content Type Mapping

### Automatic Mapping

Content types are automatically mapped based on your CMS content type definitions:

```csharp
[ContentType(DisplayName = "Article Page", GUID = "...")]
public class ArticlePage : PageData
{
    [Required]
    public virtual string Heading { get; set; }
    [UIHint(UIHint.Textarea)]
    public virtual XhtmlString ArticleBody { get; set; }
    public virtual DateTime? Published { get; set; }
    public virtual ContentReference Author { get; set; }
    public virtual IList<string> Categories { get; set; }
    public virtual ContentReference FeaturedImage { get; set; }
    public virtual ContentArea RelatedArticles { get; set; }
}
```

Generated Graph Schema Example:

```javascript
{
  "ArticlePage": {
    "properties": {
      "Heading": { "type": "String!" },
      "ArticleBody": { "type": "LongString" },
      "Published": { "type": "Date" },
      "Author": { "type": "ContentReference" },
      "Categories": { "type": "StringArray" },
      "FeaturedImage": { "type": "ContentReference" },
      "RelatedArticles": { "type": "[ContentAreaItemModelSearch]" }
    }
  }
}
```

### Custom Field Mapping

Content field mapping is handled through CMS integration package's internal mechanisms. Field exclusion and type mapping are controlled through the configuration options in the `AddContentGraph()` method using the events system:

```csharp
[ContentType(DisplayName = "Product Page")]
public class ProductPage : PageData
{
    // Fields are automatically mapped based on their .NET types
    // Use configuration events to exclude fields if needed
    public virtual string InternalNotes { get; set; }
    
    public virtual string ProductCode { get; set; }
    
    public virtual decimal Price { get; set; }
    
    public virtual ContentArea ProductImages { get; set; }
}
```
