SEO
The sitemap, robots.txt, RSS feed and Open Graph images of your site.
A new site has these without any setup:
/sitemap.xml, the list of pages for search engines./robots.txt, the rules for crawlers./rss.xml, a feed of your newest pages.<page>.webp, the image shown when a page is shared.
They need full URLs, so set your site URL. Without it, links in these files are relative.
To change one, pass its options to recommendedPreset():
import { createPress, recommendedPreset } from "@fumapress/astro/config";
createPress(content).config({
preset: recommendedPreset({
sitemap: { path: "/sitemap.xml" },
robots: { sitemap: false },
rss: { title: "My Docs", limit: 50 },
ogImage: { width: 1600, height: 840 },
}),
});Sitemap
The sitemap lists your content pages, then your prerendered custom pages and plugin pages. Return undefined from getEntry to leave a page out:
recommendedPreset({
sitemap: {
async getEntry(page) {
if (page.path.startsWith("drafts/")) return;
return {
loc: this.absoluteUrl(page.url),
lastmod: await this.getPageLastModified(page),
changefreq: "weekly",
priority: page.path === "index.mdx" ? 1 : 0.8,
alternates: await this.getPageAlternates(page),
};
},
},
});Entries also accept Google's extensions: images, videos and news.
Leaving Pages Out
A page with noindex in its page data gets a noindex meta tag, and is left out of the sitemap, the RSS feed and /llms-full.txt. Set it from transformPage of a plugin:
createPress(content).plugins({
name: "site:drafts",
transformPage(_data, { page }) {
if (page?.path.startsWith("drafts/")) return { noindex: true };
},
});Pages shown in place of an untranslated page have noindex already.
Additional Pages
Custom pages with params, like /showcase/[slug], aren't listed. Add them yourself:
recommendedPreset({
sitemap: {
additionalEntries() {
return [{ loc: this.absoluteUrl("/showcase/acme"), changefreq: "weekly", priority: 0.5 }];
},
},
});To serve another sitemap, turn entries into XML with buildSitemap of the plugins/sitemap module, in an API route. See Additional Feeds.
Sitemap Options
Prop
Type
robots.txt
The default file allows all crawlers and links to your sitemap. Each rule becomes one section of the file:
recommendedPreset({
robots: {
rules: [
{ userAgent: "*", allow: "/", disallow: ["/private", "/drafts"] },
{ userAgent: "GPTBot", disallow: "/" },
],
},
});For directives without an option, append raw text with additionalContent.
robots.txt Options
Prop
Type
RSS
The feed has the 20 newest pages. Each page links to the feed, so that feed readers can find it.
Pages need a date
A page without a date is left out of the feed. The feed uses the creation date from your content
source, or the last modified date. In MDX pages, the creation date is the date frontmatter.
Use getItem to change an item or filter pages:
recommendedPreset({
rss: {
async getItem(page) {
if (!page.url.startsWith("/blog/")) return;
return {
title: page.data.title,
link: this.absoluteUrl(page.url),
description: page.data.description,
pubDate: await this.getPageCreatedAt(page),
};
},
},
});For entries that aren't pages, add additionalItems. Their link must be a full URL.
Additional Feeds
buildRSS of the plugins/rss module turns a channel into XML. Serve it from an API route:
createPress(content).plugins({
name: "blog-rss",
routes({ createApi }) {
createApi({
path: "/blog/rss.xml",
render: "static",
GET: () =>
new Response(
buildRSS({
title: "My Blog",
link: this.absoluteUrl("/blog"),
description: "Posts from my blog",
items: [
{
title: "Hello World",
link: this.absoluteUrl("/blog/hello-world"),
pubDate: new Date("2026-08-29"),
},
],
}),
{ headers: { "Content-Type": "application/rss+xml" } },
),
});
},
});RSS Options
Prop
Type
Open Graph Images
Each content page gets an image with its title, description and site name, rendered by Takumi.
ogImage in the page data of any page sets its image: title and description for the default design, or a node. Plugin pages get it from createView({ data }), and every page from transformPage:
createPress(content).plugins({
name: "site:og",
transformPage(data, { page }) {
if (page?.path.startsWith("reference/")) return { ogImage: { title: `API: ${data.title}` } };
},
});Custom Image
Return the image from getImage as node, a React element. The default size is 1200x630.
recommendedPreset({
ogImage: {
getImage(page) {
return {
node: (
<div
style={{
width: "100%",
height: "100%",
display: "flex",
flexDirection: "column",
justifyContent: "center",
padding: 80,
background: "#111",
color: "white",
}}
>
<p>{this.siteConfig.name}</p>
<h1>{page.data.title}</h1>
</div>
),
options: { quality: 80 },
};
},
},
});Fonts
googleFonts() of the plugins/takumi module downloads the font files on every call. Call it outside getImage():
const fonts = googleFonts([{ name: "Geist", weight: [500, 800] }]);
recommendedPreset({
ogImage: {
options: { fonts },
},
});fontFromUrl() does the same for a font file you host.
Image Options
Prop
Type
Last updated on