SeoMetadataRenderer
SeoMetadataRenderer writes the head metadata for a content page: the <title>, description, canonical URL,
robots directives, Open Graph and Twitter Card tags, and schema.org JSON-LD. Give it one item (Content) for an
article or several (ContentItems) for a list page. ArticlePage and ContentList already render it; add it
yourself when you build a page from ContentView or ContentPage. It writes into the page head and renders nothing
visible, and a live demo would replace the title and tags of this page, so this page has no demo.
Package Osirion.Blazor.Cms.Web, namespace Osirion.Blazor.Cms.Web.Components. Source on GitHub.
Usage
Place it inside <HeadContent>, and keep <HeadOutlet /> in your App.razor:
@using Osirion.Blazor.Cms.Web.Components
@if (item is not null)
{
<HeadContent>
<SeoMetadataRenderer Content="@item"
SchemaTypes="@(new[] { SchemaType.BlogPosting })" />
</HeadContent>
}
Render it only when you have content: with neither Content nor ContentItems it writes only an empty title.
Site-wide defaults come from SeoMetadataOptions, either in code:
using Osirion.Blazor.Cms.Web.DependencyInjection;
builder.Services.AddOsirionSeoMetadata(seo =>
{
seo.SiteName = "Contoso Docs";
seo.OrganizationName = "Contoso";
seo.SiteLogoUrl = "/logo.png";
seo.DefaultImageUrl = "/assets/images/cover.png";
seo.TwitterSite = "@contoso";
});
or in appsettings.json under Osirion:Seo, which AddOsirion(builder.Configuration) reads:
{
"Osirion": {
"Seo": {
"SiteName": "Contoso Docs",
"SiteUrl": "https://docs.contoso.com",
"SiteLogoUrl": "/logo.png",
"DefaultImageUrl": "/assets/images/cover.png"
}
}
}
Parameters
A parameter you leave unset takes the matching SeoMetadataOptions value (see Behavior). The component renders no
element of its own, so the Theme, Class and Style parameters it inherits from the component base class have no
effect.
| Parameter | Type | Default | Description |
|---|---|---|---|
Content |
ContentItem? |
null |
The item a single content page writes its metadata for. Set this or ContentItems, not both. With neither (or an empty list), the component writes only an empty page title and no other tag. |
ContentItems |
IReadOnlyList<ContentItem>? |
null |
The items of a list page. The title becomes {CollectionTitle} \| {site name}, og:type is website, and the JSON-LD holds a BlogPosting per item, plus a CollectionPage when SchemaTypes lists it. An empty list counts as not set. |
CollectionTitle |
string? |
null |
The title of a list page, used in the page title as {CollectionTitle} \| {site name} and, cut to 60 characters, as og:title. Read only with ContentItems. |
CollectionDescription |
string? |
null |
The description of a list page: the meta description (cut to 160 characters), og:description (cut to 200) and the source of the summary tags. Read only with ContentItems. |
SiteNameOverride |
string? |
null |
The site name written after the title and as og:site_name. When empty, the configured SiteName applies, then OrganizationName, then the host name of the site address. |
SiteDescription |
string? |
null |
A site description. The component accepts it but writes nothing from it. MapOsirionFeeds uses the configured SiteDescription as the feed description when the feed options set none. |
SiteLogoUrl |
string? |
null |
The address of the publisher logo in structured data, absolute or relative to the site address. When empty, the configured value applies, then /logo.png on the site address. |
TwitterSite |
string? |
null |
The handle of the site for twitter:site, for example @contoso. Nothing is written when empty. |
TwitterCreator |
string? |
null |
The handle of the author for twitter:creator, for example @author. Nothing is written when empty. |
FacebookAppId |
string? |
null |
The Facebook app ID written as fb:app_id. Nothing is written when empty. |
SchemaTypes |
SchemaType[]? |
null |
The JSON-LD types to generate, such as Article, BlogPosting, TechArticle, WebPage, HowTo, BreadcrumbList or CollectionPage. When empty, the configured DefaultSchemaTypes apply, then the front matter type, then WebPage. The first type also sets og:type when the front matter has no og_type. FAQ generates no data: use EnableGeneratedFaq. A single type gets a BreadcrumbList added when GenerateMultipleSchemas is on. |
AllowAiDiscovery |
bool |
true |
Whether the crawler opt-in meta tags are written (true) or the opt-out tags (false). With false, the training tag says disallow whatever AllowAiTraining is. These meta names are not a standard; use robots.txt to control crawlers. When not set, the configured value applies, then true. |
AllowAiTraining |
bool |
true |
Whether the training tags (ai-training and Google-Extended) opt in (true) or out (false). Ignored when AllowAiDiscovery is false. When not set, the configured value applies, then true. |
AllowSearchIndexing |
bool |
true |
Whether search engines may index the page. false writes noindex, nofollow as robots, googlebot and bingbot; true writes the front matter robots value, or index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1 when it has none. When not set, the configured value applies, then true. |
EnableGeoOptimization |
bool |
true |
Whether the summary meta tags are written (entity-summary, content-type, primary-category, content-author, content-expertise-level and content-freshness). They are written only when the item or list has a description. When not set, the configured value applies, then true. |
EnableAeoOptimization |
bool |
true |
Whether the generated answer tags are allowed. It must be on for EnableGeneratedFaq to have an effect. When not set, the configured value applies, then true. |
GenerateMultipleSchemas |
bool |
true |
Whether a BreadcrumbList is added when exactly one schema type is generated for an item with a path. Several types given in SchemaTypes are used as listed. When not set, the configured value applies, then true. |
AuthorUrl |
string? |
null |
A page that identifies the author, such as an About page, named as the author url in structured data. It is meant for a site with one author: every article and every posting in a list names it. Without one the author is named alone, because a guessed address that answers 404 is worse than none. |
DefaultImageUrl |
string? |
null |
The social image used when the item has no og_image_url, no image and no featured image. A relative address becomes absolute with the site address. |
DefaultImageWidth |
int? |
null |
The width written as og:image:width, in pixels. When not set, the configured width applies, then 1200. |
DefaultImageHeight |
int? |
null |
The height written as og:image:height, in pixels. When not set, the configured height applies, then 630. |
OrganizationName |
string? |
null |
The publisher name in structured data. It is also the site name when no site name is set. |
ApplicationCategory |
string |
"DeveloperApplication" |
The applicationCategory of the SchemaType.SoftwareApplication schema, one of the app types search engines support, such as DeveloperApplication or BusinessApplication. |
AlternateLanguageUrls |
List<string>? |
null |
The hreflang links of other language versions, each entry a language code and an address joined by a vertical bar, such as de\|https://example.com/de/page. Malformed entries are skipped with a logged warning. |
PrevPageUrl |
string? |
null |
The address written as rel="prev". Nothing is written when empty. |
NextPageUrl |
string? |
null |
The address written as rel="next". Nothing is written when empty. |
BreadcrumbHomeText |
string |
"Home" |
The name of the first BreadcrumbList entry. When empty, the configured value applies. |
CustomBreadcrumbs |
List<ValueTuple<string, string>>? |
null |
The breadcrumb entries after the home entry, as name and address pairs, in place of the ones built from the item path. |
CanonicalQueryParameters |
IReadOnlyCollection<string>? |
null |
The query parameters kept in the canonical URL, og:url and structured data addresses (for example page for paginated lists, where each page is its own document). All other parameters and the fragment are dropped. A canonical address declared in the front matter always wins. |
EmitMobileMetaTags |
bool |
false |
Whether the viewport, theme-color and mobile web app meta tags are written. Off by default: the host document owns these, and writing them again duplicates its tags. When not set, the configured value applies, then false; a value set on the page wins over the configured one in both directions. |
EnableGeneratedFaq |
bool |
false |
Whether FAQ structured data and answer meta tags are built from the title and description (requires EnableAeoOptimization). Off by default because the question is derived, not authored. When not set, the configured value applies, then false; a value set on the page wins over the configured one in both directions. |
Theme |
ThemeMode |
ThemeMode.System |
The component's color mode. Light or Dark writes it to data-theme (data-bs-theme under Bootstrap) on the root element; System writes nothing. |
Class |
string? |
null |
Extra CSS classes for the component's root element. |
Style |
string? |
null |
An inline style for the component's root element. |
The crawler tags controlled by AllowAiDiscovery and AllowAiTraining use meta names that are not a standard; use
robots.txt to control crawlers reliably.
What is read from the item
| Output | Source, first match wins |
|---|---|
<title> |
seo_properties.title, then title; the site name follows after a vertical bar. The title is not cut |
| description | seo_properties.description, then description, cut to 160 characters |
| canonical | seo_properties.canonical, then the current URL without query string and fragment, on SiteUrl when it is set |
| robots | AllowSearchIndexing, then seo_properties.robots; an item that sets none gets index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1 |
og:title, og:description |
seo_properties.og_title and og_description, then the title and description above; cut to 60 and 200 characters |
og:type |
seo_properties.og_type, then article when the first schema type is Article, BlogPosting or TechArticle, product for Product, video.other for VideoObject, profile for ProfilePage, otherwise website |
og:image |
seo_properties.og_image_url, then seo_properties.image, then featured_image, then DefaultImageUrl; the width, height and alt tags are written only when there is an image |
| Twitter Card | seo_properties.twitter_card, twitter_title, twitter_description, twitter_image_url, then Open Graph; the title is cut to 70 characters and the description to 200, and twitter:image:alt repeats the Twitter title |
| keywords | tags |
og:locale |
seo_properties.lang, then the item's locale, written with an underscore (de-DE becomes de_DE); en_US when neither is set |
| extra meta elements | seo_properties.meta_tags, one meta element per entry. Names start with a letter and hold only letters, digits and - _ . :; others are skipped with a logged warning, as are the names the component writes itself (description, keywords, author, generator, language, robots, googlebot, bingbot, referrer). Values are HTML encoded |
article:* tags |
Written only when og:type is article: article:published_time, article:modified_time, article:author, article:section (the first of categories) and one article:tag per tag |
| JSON-LD | seo_properties.json_ld, then SchemaTypes, then seo_properties.type (front matter default Article), then WebPage |
Relative image URLs become absolute with the site's base URL.
Page types
| Type | Use it for | What it holds |
|---|---|---|
TechArticle |
Documentation and technical guides | The Article schema with the more specific type. |
SoftwareApplication |
A product page about an app or a library | Name, description, image, ApplicationCategory, last modified date and keywords. Search engines show software rich results only with a price and a rating or review; put the full schema in json_ld when you have them. |
ProfilePage |
An author's page | The person as mainEntity: the author (or the title), description and image, with tags that are absolute links as sameAs. |
AboutPage |
The about page | A WebPage with the site's organization as mainEntity. |
ContactPage |
The contact page | A WebPage with the more specific type. |
FAQ generates no data by itself, and Google no longer shows FAQ or HowTo rich results.
Behavior
- Rendering. It renders on the server as part of the head, with no script, and recomputes everything when its parameters change, so a reused instance never keeps the previous page's canonical URL or structured data.
- List pages. With
ContentItems, the title is{CollectionTitle} | {site name}(the site name alone when there is noCollectionTitle),og:typeiswebsite, the image is the first item's featured image orDefaultImageUrl, and JSON-LD holds a CollectionPage (when listed inSchemaTypes) plus a BlogPosting per item. - Breadcrumbs. A single schema type for an item with a path gets a BreadcrumbList added when
GenerateMultipleSchemasis on. Several types inSchemaTypesare used as listed. - Security. Meta values are HTML-encoded. JSON-LD is serialized with HTML-sensitive characters escaped; custom
json_ldfrom front matter is parsed and re-serialized the same way, and ignored with a logged warning when it is not a JSON object or array. When customjson_ldis used,SchemaTypesgenerates nothing. - Fixed values. It also writes
generator,referrer,languageandcontent-language, the robots value again asgooglebotandbingbot, publish date, last-modified and reading time meta tags,dns-prefetchandpreconnecthints for the site's own address. The Article schema gives the author aurlonly whenAuthorUrlis set. - Crawler tags. With
AllowAiDiscoveryon, it writesai-crawling,ai-trainingand a tag per named crawler; with it off, the opt-out versions. The component makes no AI content declaration of its own: writeai-content-declaration(orai-content-detection,ai-content-attribution) undermeta_tagsin the front matter, or underAdditionalMetaTagsinSeoMetadataOptionsfor every page. These names are not a standard either. - Options.
SeoMetadataOptionsfills the parameters you leave unset:SiteName(asSiteNameOverride),SiteDescription,OrganizationName,SiteLogoUrl,DefaultImageUrl,DefaultImageWidth,DefaultImageHeight,TwitterSite,TwitterCreator,FacebookAppId,AuthorUrlandDefaultSchemaTypes. The switchesAllowSearchIndexing,AllowAiDiscovery,AllowAiTraining,EmitMobileMetaTags,EnableGeneratedFaq,EnableGeoOptimization,EnableAeoOptimizationandGenerateMultipleSchemascome from the options unless the page sets them as parameters,trueorfalse.BreadcrumbHomeTextapplies when the parameter is empty.DefaultImageWidthandDefaultImageHeightare nullable: the option applies when the parameter is not set, and an explicit1200or630stands. - Public address.
SiteUrl(for examplehttps://example.com) makes the canonical URL,og:urland the addresses in structured data use the site's address with the page's path, whatever host served the request: a proxy, a preview host or a second domain. Only an absolutehttporhttpsaddress is used; otherwise they follow the request.
Related
- ContentList: renders this for list pages
- Feeds and sitemap:
sitemap.xml, RSS and Atom - ContentView: the article body to pair it with
- Blazor SEO checklist for SSR and SSG