SEO
Xingluo ships with full SEO support: Open Graph, Twitter Card, canonical, JSON-LD structured data, dynamic OG images, RSS, sitemap, and hreflang multilingual declarations.
head Output
The <head> in src/layouts/Layout.astro outputs:
charset,viewportfavicon(public/favicon.svg)canonical(canonical link)title,meta title,meta description,meta authorsitemaplink- Open Graph:
og:type,og:site_name,og:title,og:description,og:url,og:image - Twitter Card:
twitter:card,twitter:title,twitter:description,twitter:image - RSS alternate link
- hreflang alternate links (per language + x-default)
theme-color(filled at runtime bytheme.ts)google-site-verification(conditional)
Post Page meta
src/layouts/PostLayout.astro injects post-specific meta via <Fragment slot="head">:
og:type = articlearticle:published_time(ISO 8601)article:modified_time(ifmodDatetimeis set)- JSON-LD
BlogPostingstructured data:
json{ "@context": "https://schema.org", "@type": "BlogPosting", "headline": "Post title", "image": "OG image URL", "datePublished": "2026-06-19T10:00:00.000Z", "dateModified": "2026-06-20T10:00:00.000Z", "author": [ { "@type": "Person", "name": "Author name", "url": "Author homepage" } ] }
canonical Normalization
The canonical strategy on post detail pages (PostDetailView.astro):
- Custom
canonicalURLin frontmatter → used first - The current post is a real translation for this language (
localematches the page language) → points to its own URL - The current post is fallback content (no translation available, using the original) → points to the default-language original URL
Strategy 3 ensures search engines don’t treat pages without independent translations as duplicate content. Posts with independent translations have canonical pointing to themselves and can be indexed separately.
BreadcrumbList Structured Data
All pages with breadcrumbs (post list, tag index, tag post list, archives, about, search) automatically output BreadcrumbList JSON-LD structured data:
json{ "@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [ { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://..." }, { "@type": "ListItem", "position": 2, "name": "Posts", "item": "https://.../posts/" } ] }
When the last breadcrumb item has no link (current page), the current page URL is used as item. Post detail pages do not use the breadcrumb component and therefore do not output this structured data.
Open Graph Images
Dynamic Generation
With features.dynamicOgImage enabled (default), Xingluo dynamically generates 1200×630 OG images using satori + sharp:
- Site-level:
src/pages/og.png.ts, for pages without a custom OG image - Post-level:
src/pages/posts/[...slug]/og.png.ts, generated only for posts withoutogImage
Fonts
OG images use Noto Sans SC (see the fonts config in astro.config.ts, CSS variable --font-og), loaded via astro:assets’s fontData. The font is for satori only and is not injected into site CSS.
Fallbacks
- Font unavailable (no network) → falls back to a 1×1 placeholder PNG (does not fail the build)
dynamicOgImageoff → uses the static default OG image underpublic/
Post OG Image Resolution
The four-level fallback in PostDetailView.astro:
- frontmatter
ogImageis a string → use directly - frontmatter
ogImageis animage()object → use.src dynamicOgImageenabled → use the post-levelog.pngendpoint- Otherwise → site default static OG image
RSS
src/pages/rss.xml.ts generates the RSS feed:
- Title, description, and site URL come from the
siteconfig - items come from
getSortedPosts(drafts and scheduled posts already filtered) - Each item’s
linkisgetPostUrl(id, filePath, config.site.lang) pubDateismodDatetime ?? pubDatetime
Layout.astro injects the RSS autodiscovery link:
html<link rel="alternate" type="application/rss+xml" title="..." href=".../rss.xml" />
sitemap
The @astrojs/sitemap integration (see astro.config.ts):
filter: filters archive page paths based onfeatures.showArchivesi18n: enables auto hreflang generation, mappingzh-cn → zh-CN,en → en, with defaultLocalezh-cn
Generates sitemap-index.xml and per-language alternate declarations; robots.txt references the sitemap.
hreflang Multilingual Declarations
Layout.astro outputs <link rel="alternate"> for each language:
html<link rel="alternate" hreflang="zh-CN" href="https://.../posts/welcome/" /> <link rel="alternate" hreflang="en" href="https://.../en/posts/welcome/" /> <link rel="alternate" hreflang="x-default" href="https://.../posts/welcome/" />
Paths are normalized via parseLocaleFromPath(stripBase(...)) after stripping prefixes, ensuring each language maps to the correct URL. x-default points to the default language.
robots.txt
src/pages/robots.txt.ts generates:
User-agent: * Allow: / Sitemap: https://site-url/sitemap-index.xml
Site Verification
Google Search Console verification is configured via site.googleVerification in two ways:
- Environment variable
PUBLIC_GOOGLE_SITE_VERIFICATION(runtime injection) - The
site.googleVerificationfield inxingluo.config.ts
Rendered as <meta name="google-site-verification" content="...">.
Related posts
Deployment
2 min readXingluo deployment guide covering static hosting platforms (Netlify/Vercel/GitHub Pages), Nginx self-hosting, Docker, and environment variables.
Search
1 min readXingluo search guide covering Flexsearch full-text search integration, index generation, UI, multilingual search, and performance.