Open Graph / Twitter Card Meta Tags
Overview
Eigen auto-injects Open Graph (og:*) and Twitter Card (twitter:*) meta tags into every page's <head> during the build pipeline. This ensures shared links on social media (Twitter/X, Facebook, LinkedIn, Slack, Discord, etc.) display rich preview cards with title, description, and image.
No template changes are required. The feature is always-on.
How It Works
SEO values are resolved from a three-layer cascade:
- Auto-derived defaults (title = site.name, og:type = "website", canonical URL = base_url + page path)
- Site-level defaults from
[site.seo]insite.toml - Per-page overrides from
[seo]in template frontmatter
The rendered HTML is scanned for existing OG/Twitter meta tags.
Only missing tags are generated and injected into
<head>.
Configuration
Site-level defaults (site.toml)
[site]
name = "My Blog"
base_url = "https://blog.example.com"
[site.seo]
title = "My Blog" # optional, falls back to site.name
description = "A blog about interesting things" # optional
image = "/assets/default-share.jpg" # optional, site-relative or absolute URL
og_type = "website" # default: "website"
twitter_site = "@myblog" # optional, Twitter @handle
twitter_card = "summary_large_image" # default: "summary_large_image"
All fields are optional. If [site.seo] is omitted entirely, sensible defaults are used.
Per-page frontmatter
---
seo:
title: About Us
description: Learn about our team and mission
image: /assets/about-hero.jpg
og_type: website
twitter_card: summary_large_image
canonical_url: https://example.com/about
---
All fields are optional. When absent, site-level defaults are used.
Dynamic pages with template expressions
For dynamic pages, SEO field values can reference collection item data using minijinja template expressions:
---
collection:
source: blog_api
path: /posts
item_as: post
seo:
title: "{{ post.title }} | My Blog"
description: "{{ post.excerpt }}"
image: "{{ post.cover_image }}"
og_type: article
---
Expressions are resolved per-item using the same template context used for the page template.
Generated Tags
For a fully configured page, these tags are generated:
<!-- Open Graph -->
<meta property="og:title" content="Page Title">
<meta property="og:description" content="Page description">
<meta property="og:image" content="https://example.com/assets/share.jpg">
<meta property="og:url" content="https://example.com/about.html">
<meta property="og:type" content="website">
<meta property="og:site_name" content="My Site">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Page Title">
<meta name="twitter:description" content="Page description">
<meta name="twitter:image" content="https://example.com/assets/share.jpg">
<meta name="twitter:site" content="@mysite">
<!-- Canonical URL -->
<link rel="canonical" href="https://example.com/about.html">
Tags are omitted when their value is not available:
- No description at any level:
og:descriptionandtwitter:descriptionomitted - No image at any level:
og:image,twitter:imageomitted,twitter:cardforced to"summary" - No
twitter_siteconfigured:twitter:siteomitted
Duplicate Detection
If a template already contains OG/Twitter meta tags or a canonical link, the build pipeline detects them and does not inject duplicates. This allows template authors to manually control specific tags when needed.
URL Resolution
- Image paths starting with
/are resolved to absolute URLs usingsite.base_url - Already-absolute URLs (
http://orhttps://) are used as-is - Canonical URLs are auto-generated from
site.base_url + page_path /index.htmlpaths are normalized to/in canonical URLs
Pipeline Position
SEO injection runs after preload/prefetch hints and before HTML minification. It does not run during dev server rendering.
Module
src/build/seo.rs -- single file containing all resolution, detection, generation, and injection logic.