Umbraco.Community.SchemeWeaver.uSync
1.4.3
dotnet add package Umbraco.Community.SchemeWeaver.uSync --version 1.4.3
NuGet\Install-Package Umbraco.Community.SchemeWeaver.uSync -Version 1.4.3
<PackageReference Include="Umbraco.Community.SchemeWeaver.uSync" Version="1.4.3" />
<PackageVersion Include="Umbraco.Community.SchemeWeaver.uSync" Version="1.4.3" />
<PackageReference Include="Umbraco.Community.SchemeWeaver.uSync" />
paket add Umbraco.Community.SchemeWeaver.uSync --version 1.4.3
#r "nuget: Umbraco.Community.SchemeWeaver.uSync, 1.4.3"
#:package Umbraco.Community.SchemeWeaver.uSync@1.4.3
#addin nuget:?package=Umbraco.Community.SchemeWeaver.uSync&version=1.4.3
#tool nuget:?package=Umbraco.Community.SchemeWeaver.uSync&version=1.4.3
![]()
Umbraco.Community.SchemeWeaver
Map Umbraco Content Types to Schema.org types and automatically generate JSON-LD structured data for your pages.
👋 Heads-up — I'm building this one in public. SchemeWeaver is usable today, but I'm still dialling in the editor UX and a few of the sharper edges. Expect small behavioural and UI changes between releases while that settles down. Every change (breaking or otherwise) gets called out in the release notes so you can see what's coming before you upgrade.
If something bites you, confuses you, or you just have a suggestion — please open an issue. I genuinely want the feedback, especially the "this UX is weird" kind. The package is better for every issue that gets logged.
SchemeWeaver provides a document type editor UI for configuring mappings, an auto-mapper that suggests property assignments, and runtime JSON-LD generation that works with both server-rendered templates and the headless Delivery API.
Why structured data?
Search engines use JSON-LD to understand page content. A blog post tagged as BlogPosting with a headline, author, and datePublished can appear as a rich result in Google, Bing, and other search engines. Manually maintaining JSON-LD scripts is tedious and error-prone -- SchemeWeaver automates it from your existing content.
Features
- 780 Schema.org types -- discovers every type in the Schema.NET.Pending library at startup, including pending types like
RealEstateListing - Auto-mapping with confidence scores -- suggests property mappings using exact matching, synonym dictionaries, and substring matching
- Smart property UI -- shows mapped properties first, with an "Add property" combobox to add more schema properties
- Seven source types -- pull values from the current node, a static value, the parent, an ancestor, a sibling, block content, or nested complex types
- Transforms -- strip HTML, convert to absolute URL, or format dates before output
- Content Type generation -- scaffold a new Umbraco document type from any Schema.org type
- Language variants -- culture-aware JSON-LD generation for multi-language sites. When content varies by culture, SchemeWeaver pulls the correct localised values and auto-populates
inLanguagewith the BCP 47 culture code. Works across server-rendered templates, the Delivery API, and the backoffice preview - Delivery API integration -- dedicated
/umbraco/delivery/api/v2/schemeweaver/json-ldendpoint returns the per-page JSON-LD blocks, culture-aware, cached in-process with event-driven invalidation on publish/unpublish/move/delete - Tag helper -- drop
<scheme-weaver content="@Model" />into any Razor template; the tag helper reads the current culture from Umbraco'sIVariationContextAccessorautomatically - Inherited schemas -- mark a mapping as inherited and it outputs on all descendant pages
- BreadcrumbList -- automatically generated from the content's ancestor hierarchy
Requirements
- Umbraco 17+
- .NET 10
Installation
dotnet add package Umbraco.Community.SchemeWeaver
No additional configuration needed. The package registers all services, creates its database tables on first run, and adds the backoffice UI automatically.
Optional: uSync Integration
To sync schema mappings between environments via uSync:
dotnet add package Umbraco.Community.SchemeWeaver.uSync --prerelease
See uSync Integration for details.
Quick Start
1. Add the tag helper
In your master layout (e.g. _Layout.cshtml):
@addTagHelper *, Umbraco.Community.SchemeWeaver
<head>
...
<scheme-weaver content="@Model" />
</head>
2. Map your content types
- Open any document type in Settings > Document Types
- Click the Schema.org tab
- Click Map to Schema.org and select a type (e.g. Product, Article, Event)
- Review the auto-suggested property mappings in the modal and click Save
- Publish content -- JSON-LD appears in the page source
3. Headless / Delivery API
JSON-LD is served from a dedicated endpoint — fetch it in parallel with your content request and inject the strings as <script type="application/ld+json"> tags:
const response = await fetch(
'/umbraco/delivery/api/v2/schemeweaver/json-ld/by-route?route=/my-blog-post',
{ headers: { 'Api-Key': process.env.UMBRACO_DELIVERY_API_KEY! } },
);
const { schemaOrg }: { schemaOrg: string[] } = await response.json();
Responses are cached in-process and invalidated automatically by publish/unpublish/move/delete notifications, so the cache stays fresh without manual busting. The array is ordered: inherited ancestor schemas → BreadcrumbList → main page schema → block-element schemas. See Delivery API docs for the full endpoint surface, Next.js example, and the opt-out for BreadcrumbList when your front-end builds its own.
Pre-1.3 consumers who read
schemaOrgfromproperties.schemaOrgon the content response: that was never actually wired up (index handlers feed Examine, not the response body). Use the dedicated endpoint above.
4. Language variants
No extra configuration needed. If your content type varies by culture, SchemeWeaver automatically:
- Pulls property values in the requested culture (tag helper reads the current
VariationContext; the Delivery API handler is called once per culture) - Populates
inLanguagewith the BCP 47 culture code (e.g."de-DE") unless you've explicitly mappedinLanguageyourself - Generates culture-correct URLs for
@idand breadcrumb links
Mappings stay invariant -- the same mapping applies to all cultures. You don't need per-language mappings; SchemeWeaver resolves the right value at generation time.
The backoffice JSON-LD preview tab automatically follows the workspace variant selector, so switching to German in the editor shows the German JSON-LD output.
Documentation
- Getting Started -- installation, tag helper, first mapping
- Mapping Content Types -- full mapping workflow
- Property Mappings -- source types, transforms, confidence tiers
- Block Content -- BlockList/BlockGrid mapping, nested types, wrapInType
- Content Type Generation -- scaffold document types from Schema.org
- Delivery API -- headless integration
- Extending -- custom property resolvers, replacing core services
- uSync Integration -- sync schema mappings between environments
- Advanced -- inherited schemas, BreadcrumbList, troubleshooting
- API Reference -- REST API endpoints
How it works
Each mapping connects one Umbraco Content Type to one Schema.org type. Within that mapping, individual property mappings define where each schema property gets its value:
| Schema Property | Source | Value | Description |
|---|---|---|---|
headline |
property | title |
Read from the current node |
author |
static | Jane Smith |
Hardcoded string value |
datePublished |
property | publishDate |
Formatted as ISO date |
publisher |
parent | organisationName |
Read from the parent node |
mainEntity |
blockContent | faqItems |
Built from BlockList items |
inLanguage |
(auto) | Auto-populated from the current culture on variant content |
The auto-mapper suggests assignments using three confidence tiers:
- High (100%) -- exact property name match
- Medium (80%) -- synonym match (e.g.
titletoname,bodyTexttoarticleBody) - Low (50%) -- substring match
The generated output:
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": "10 Tips for Better SEO",
"author": {
"@type": "Person",
"name": "Jane Smith"
},
"datePublished": "2024-01-15",
"inLanguage": "en-US"
}
Notes
- Block content nested types -- complex Schema.org properties (e.g.
acceptedAnswer,reviewRating) require a wrapper type. The auto-mapper pre-configures this for common patterns (FAQ, Product, Recipe). For custom types, see thewrapInTypeguide. - Media picker edge cases -- complex multi-crop scenarios with specific crop aliases may need manual URL configuration. See Property Mappings.
Releasing
Maintainer notes — shipping a new version to NuGet and the Umbraco Marketplace:
- Ensure
NUGET_API_KEYis set in Settings → Secrets and variables → Actions (a single API key with "Push new packages and package versions" scope onUmbraco.Community.SchemeWeaver*). - Tag the commit you want to ship:
git tag v1.0.0-beta.4 && git push origin v1.0.0-beta.4. - The
Release to NuGetworkflow builds, tests, packs and pushes the package to nuget.org, and opens a matching GitHub release. - The Umbraco Marketplace listing is automatic — it discovers packages on nuget.org that carry the
umbraco-marketplacetag (already set in the csproj) and usually updates within 24 hours.
To publish an out-of-band build without tagging, use the workflow's "Run workflow" button on the Actions tab and type the version explicitly.
Contributing
Contributions are very welcome — bug reports, fixes, docs, new property resolvers, extra auto-mapper synonyms, whole new features. Small PRs are fine.
Getting set up
# C#
dotnet build
dotnet test
# Frontend
cd src/Umbraco.Community.SchemeWeaver/App_Plugins/SchemeWeaver
npm install
npm run build
npm test
npm run test:msw # component tests with MSW handlers
npm run test:mocked-backoffice # Playwright drives the real backoffice UI with MSW — needs Umbraco-CMS clone
npm run test:e2e # Playwright against a running Umbraco + .env
npm run test:screenshots # regenerate the docs screenshots (opt-in)
# Test host with 100+ sample content types
dotnet run --project src/Umbraco.Community.SchemeWeaver.TestHost
Note: The TestHost is purely for testing schema mappings and structured data generation. It is not intended as a base site or starter kit.
Read CLAUDE.md for architecture, DI wiring, and naming conventions.
Tests
Please add tests for behavioural changes, and a regression test for bug fixes. CI runs the full suite on every push.
| Layer | Framework | Location |
|---|---|---|
| C# Unit | xUnit + NSubstitute + FluentAssertions | tests/Umbraco.Community.SchemeWeaver.Tests/Unit/ |
| C# Integration | xUnit + WebApplicationFactory<Program> against the SchemeWeaver TestHost, shared via an xUnit collection fixture so every test class reuses a single host (temp SQLite, one file per suite) |
tests/Umbraco.Community.SchemeWeaver.Tests/Integration/ |
| TS Unit / Component | @open-wc/testing + MSW |
App_Plugins/SchemeWeaver/src/**/*.test.ts |
| Mocked Backoffice | Playwright drives the real Umbraco backoffice UI via VITE_EXAMPLE_PATH, with SchemeWeaver's MSW handlers serving all HTTP traffic — no .NET required. Requires a local umbraco/Umbraco-CMS clone plus a small addMockHandlers patch; see tests/mocked-backoffice/README.md |
App_Plugins/SchemeWeaver/tests/mocked-backoffice/ |
| E2E | Playwright + @umbraco/playwright-testhelpers against a running Umbraco |
App_Plugins/SchemeWeaver/tests/e2e/ |
For backoffice UI changes, npm run test:mocked-backoffice verifies manifest wiring, workspace-view conditions, and modal plumbing without a running Umbraco; npm run test:e2e against a real instance is still the only thing that catches issues across the full .NET + backoffice stack.
Using an AI assistant
AI tools (Claude, Codex, Copilot, Cursor, etc.) are welcome to help. The rules are short:
You review it. Read every line before committing. You're accountable for the PR, not the assistant.
MIT-compatible only. Don't submit code copied from incompatible sources.
Add tests, same as any other contribution.
For UI work, install the Umbraco Backoffice Skills and add
umbraco/Umbraco-CMS(src/Umbraco.Web.UI.Client) andumbraco/Umbraco.UI(packages/uui) as working directories so the skills can grep the canonical backoffice source — see the skills repo for setup. Also run theumbraco-extension-revieweragent on UI changes.Tag the commit. When an assistant materially helped, add a git trailer at the bottom of the commit message so we can see which model was used:
Assisted-by: Claude:claude-opus-4-6Format is
Assisted-by: <agent>:<model> [optional tools], e.g.Assisted-by: Copilot:gpt-5 playwright. Just leave a blank line before it, or usegit commit --trailer "Assisted-by=...". Basic tools (git,dotnet,npm, editors) don't need listing. If your tool already adds aCo-authored-by:trailer for the assistant automatically, that's fine too — just don't bother adding both.Don't add
Signed-off-byon a human's behalf. Only the human submitter can sign off their own contribution.
Licence
MIT — see LICENSE. By submitting a pull request you agree to license your contribution under the same terms.
Author
Oliver Picton / Enjoy Digital
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Umbraco.Community.SchemeWeaver (>= 1.4.3)
- uSync.BackOffice (>= 17.3.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.4.3 | 253 | 4/22/2026 |
| 1.4.1 | 96 | 4/21/2026 |
| 1.4.0 | 89 | 4/21/2026 |
| 1.3.0 | 101 | 4/18/2026 |
| 1.2.0 | 99 | 4/18/2026 |
| 1.1.0 | 94 | 4/17/2026 |
| 1.0.1 | 97 | 4/17/2026 |
| 1.0.0 | 103 | 4/16/2026 |
| 1.0.0-beta.10 | 54 | 4/16/2026 |
| 1.0.0-beta.9 | 47 | 4/16/2026 |
| 1.0.0-beta.8 | 54 | 4/15/2026 |
| 1.0.0-beta.7 | 52 | 4/15/2026 |
| 1.0.0-beta.6 | 54 | 4/15/2026 |