Introducing Optimizely Content Seeder
Realistic content for local setup, tests and demos
I've just released TechnicalDogsbody.Optimizely.ContentSeeder, a fluent C# API for seeding pages, shared blocks and media into Optimizely CMS 12 and 13. You can get it on NuGet or explore the source on GitHub.
The Problem
Every Optimizely build needs content before it's any use. A new developer clones the repo and gets an empty site. Integration tests need a known content tree. Demo sites need something that looks real. Usually that means restoring a database backup that drifts out of date, or someone clicking through the editor for an afternoon.
What It Does
You describe the content tree in code: which pages, how many of each, which blocks go in which content areas, and which properties get images. The seeder builds it, filling text with realistic fake data from Bogus and images from Picsum Photos.
It's idempotent. Each seed definition has a stable ID and the seeder records what it created, so re-running the app fills gaps rather than duplicating content. An admin gadget lets you dry run, seed, reseed or delete each definition on demand.
Getting Started
Install the connector for your CMS version. It brings in the core package:
dotnet add package TechnicalDogsbody.Optimizely.ContentSeeder.Connector.Optimizely13
Use Connector.Optimizely12 for CMS 12. Then register the seeder and your definition:
services.AddContentSeeder()
.AddDefinition<MySeedDefinition>();
services.Configure<ContentSeederOptions>(
configuration.GetSection("ContentSeeder"));
{
"ContentSeeder": {
"SeedOnStartup": true,
"MasterLanguage": "en",
"Languages": ["sv"]
}
}
Then write the definition itself:
public sealed class MySeedDefinition : ISeedDefinition
{
public string Id => "my-site-seed-v1";
public SeedTree Build()
{
var promoBlock = new BlockDefinition(id: "promo", type: typeof(PromoBlock));
var homePage = SeedFactory.Page(
type: typeof(StartPage),
count: 1,
contentAreaAssignments:
[
new ContentAreaAssignment(nameof(StartPage.PromoArea), ["promo"])
],
children:
[
SeedFactory.Page(typeof(ArticlePage), count: 5)
]);
return SeedFactory.Tree(blocks: [promoBlock], nodes: [homePage]);
}
}
That gives you a home page with a promo block in its content area and five article pages underneath, plus a Swedish version of each.
AI-Written Content
Lorem ipsum is fine for checking layouts, but it doesn't help when you're demoing to a client. The optional ContentSeeder.AI package writes text properties through any Microsoft.Extensions.AI IChatClient, so you can use Claude, OpenAI, Azure OpenAI, Gemini, or Ollama running locally for free.
You give it a writing brief in the seed definition (prompt, tone of voice, audience and phrases to avoid) plus per-property guidance with hard word or character limits. Each item is written in one request, so a heading, summary and body read as one piece. Other languages are translated from the master, so every language version says the same thing.
Visual Builder on CMS 13
On CMS 13 it also seeds Visual Builder sections and Experience pages, with rows, columns and elements. Repeating rows put the same element in one to six columns, which is handy for checking a front end's grid.
Other Bits
- Videos from YouTube or Vimeo feeds, with no API keys.
- Language branches, with placeholder text in the right script.
- Typed generator rules, generated rich text and a "kitchen sink" field that uses every editor tag.
- A completion email, and a CMS notification on CMS 13.
- A ready-made skill that teaches Claude Code, Copilot, Cursor and others to write seed definitions for your content model.
It's built on MicroMediator too, so you can start a seed run from your own code through the mediator.
Supported Versions
CMS 13 on .NET 10, and CMS 12 on .NET 8, 9 or 10. It's MIT licensed, and issues and pull requests are welcome on GitHub.
Andy Blyth
Andy Blyth, an Optimizely MVP (OMVP) and Technical Architect at MSQ DX with a keen interest in martial arts, occasionally ventures into blogging when memory serves.



