SEO Changelog
Release notes for SEO.
2.0.1
🐛 Bug fixes
- Only treat debug mode as active when the
debugoption istrue, as Kirby does. Values such as the string"false"no longer set all pages tonoindex. - Set the error page to
noindexby default. This also removes it from the sitemap,llms.txt, IndexNow submissions and the SEO overview, even if its content file is not namederror.txt. - Output
twitter:cardwithsummary_large_imagewhen the page has an Open Graph image file and "Crop OG image" is active. X, Discord and other platforms then show a large image preview. - Hide AI features in the Panel when the AI provider has no API key. Custom providers can override
Driver::configured(). - Use the site's meta description in
llms.txt - Link the Search Console setup guide in the Search Console section
- Use the
www.andkindness.comdomain for the license API and the user agent
Full Changelog: https://github.com/tobimori/kirby-seo/compare/2.0.0...2.0.1
2.0.0

Kirby SEO 2 🚀 The first stable release for Kirby 5 includes a site-wide SEO overview, AI Assist, an alt text field, Google Search Console, IndexNow and LLM-friendly content. It's a natural upgrade from 1.x: your content and blueprints keep working.
Kirby SEO 2 requires Kirby 5 and PHP 8.3. A license is required for public sites: buy a license. Read the upgrade guide before updating from 1.x.
composer require tobimori/kirby-seo
🎉 Features
SEO overview
We've added a new SEO area to the Panel. It checks titles, descriptions, alt texts and links across the whole site, and each card takes you to the pages, images or links that need work.
- Checks for missing, duplicate, too short and too long titles and descriptions, and values inherited from a fallback
- You can now edit meta titles and descriptions for multiple pages in the table or generate them with AI
- You can now edit alt texts for multiple images at once
- You can now check internal and external links for broken targets. With Kirby Queues, the checks run in the background on a schedule.

AI Assist
AI Assist writes meta titles and descriptions based on the page content. It uses the page's language, takes the length of your title template into account and includes unsaved changes. Editors can generate new text or revise the current one.
OpenAI, Anthropic, Google Gemini and OpenRouter are supported out of the box. You can also add your own providers and replace the built-in prompts with your own snippets.
// site/config/config.php
return [
'tobimori.seo' => [
'ai' => [
'provider' => 'anthropic',
'providers' => [
'anthropic' => [
'config' => [
'apiKey' => 'sk-ant-...',
],
],
],
],
],
];
Alt text field
The new alt-text field generates alt texts with AI based on the image itself and has a toggle for decorative images. With autogenerate: true, alt texts are generated on upload. On multilingual sites, a single request covers all languages.
# site/blueprints/files/image.yml
fields:
alt:
type: alt-text
autogenerate: true
Google Search Console
The new Google Search Console section shows clicks, impressions, click-through rate, position and top search queries for each page, right next to its content. Editors don't need their own Google account.

LLM-friendly content
Kirby SEO can now serve Markdown versions of your pages for AI agents, as well as an llms.txt file for each language. The Markdown comes from a .md.php representation next to the template or from an automatic conversion of the page's main content.
<?php // site/templates/article.md.php ?>
# <?= $page->title() ?>
<?= $page->text()->value() ?>
Agents can open /article.md or request Markdown with the Accept: text/markdown header. Markdown responses send noindex and a link to the original page so search engines don't list them as duplicates.
IndexNow
Kirby SEO now notifies Bing, Yandex and other search engines via IndexNow when pages change. With rules, you can submit related pages as well, such as the parent of a new blog post.
'tobimori.seo' => [
'indexnow' => [
'rules' => [
'article' => ['parent' => true, 'urls' => ['/blog', '/']],
],
],
],
Title templates with variables
Title template fields now show Page Title and Site Title as buttons and chips instead of raw query syntax. Title, description and template fields use the new seo-writer field with AI buttons.
UTM share
We've added a dialog to the page view to create campaign links with UTM parameters and copy them with a click.

Background processing
With Kirby Queues installed, AI alt text generation, IndexNow submissions and link checks run in a queue worker instead of during the Panel request.
Opt out of AI training
You can now opt out of AI training with the new ai and imageai robots types. They output noai and noimageai, and editors can allow AI training again for individual pages or the whole site.
'tobimori.seo' => [
'robots' => [
'types' => ['index', 'follow', 'archive', 'imageindex', 'snippet', 'ai', 'imageai'],
],
],
Optimized head order
You can now use seo/head with slots to output the <title> before your stylesheets and scripts, and the other meta tags after them (#112).
<?php snippet('seo/head', slots: true) ?>
<link rel="stylesheet" href="/assets/css/main.css">
<?php endsnippet() ?>
Kirby Agents
The SEO writer and alt text fields now support Kirby Agents, so agents can read and edit metadata and alt texts.
And more …
- New license activation in the Panel
- Panel previews respect dark mode and use the current Google design
- New
canonical.trailingSlashoption (#136) - Mastodon profile links are output as
<link rel="me">(#92) - New
componentsoption to replace built-in classes
✨ Enhancements
- The sitemap lists each translation of a page as its own entry, with the same
hreflangalternates on every entry hreflangtags only list existing, indexable translations- Pages with a non-canonical URL, for example with query parameters, do not output
hreflangtags (#98) x-defaultpoints to the page's language-neutral URL (#177), with the default language's slug (#146)- The sitemap stylesheet shows language alternates and a cleaner table
- IndexNow skips pages with
noindex - Panel previews use the page's canonical URL (#185, thanks @antons)
⚡ Performance
- Kirby SEO caches indexable pages and page, image and link check results. This speeds up the SEO overview and sitemap on large sites.
- The sitemap index and
llms.txtuse the pages cache
🐛 Bug fixes
og:image:widthandog:image:heightuse the cropped image's dimensions (#91)- The sitemap URL in
robots.txtis correct on multilingual sites (#124) - The sitemap uses the canonical base URL, and its stylesheet loads on sites in a subfolder (#88)
- The sitemap returns content for
HEADrequests. This fixes "Sitemap could not be read" errors in Google Search Console (#164, thanks @tomsl123).
🚨 Breaking changes
The upgrade guide covers the steps for updating.
- Kirby SEO 2 requires Kirby 5 and PHP 8.3
- A license is required for public sites. Kirby SEO 1.x remains available under the MIT license.
lang,sitemap.langanddefault.langare nowlocale,sitemap.localeanddefault.locale. The old names are ignored.- The
spatie/schema-orgpackage is no longer installed with Kirby SEO (#48). Installspatie/schema-org:^5.0(PHP 8.4) if you output Schema.org data. - Twitter options, fields and
twitter:*tags are removed. X reads the Open Graph tags. - A page's meta description now takes priority over the site's Open Graph description for
og:description. ThefallbackFieldscascade level is enabled by default. - Title templates only resolve
{{ title }}and{{ site.title }}, because editors can change them in the Panel. To use all Kirby queries as in 1.x, set the newkqloption totrue. Only enable it if you trust all Panel users. $page->metadata()and$page->robots()take aKirby\Cms\Languageobject instead of a language codeSitemapUrl::lastmod()takes a Unix timestamp instead of a date string
☠️ Deprecated
canonicalBase→ usecanonical.baserobots.active→ userobots.enabledsitemap.active→ usesitemap.enabled
🌐 Translations
- Czech (thanks @jan-herman)
- Dutch (thanks @wietseneven)
- Romanian (thanks @danburzo)
- Swedish (thanks @olach)
📚 Docs
The new documentation includes a quickstart, a page for each feature, customization guides, an options reference and an upgrade guide.
🧹 Housekeeping
- Static analysis with Mago for all PHP code
- Updated dependencies
Thanks to everyone who tested the alphas, betas and release candidates, reported issues and sent pull requests: @olach, @wietseneven, @jan-herman, @ovenum, @lukasleitsch, @danburzo, @tomsl123, @FloWinge, @antons, @notz and @FlorianBoe.
Full Changelog: https://github.com/tobimori/kirby-seo/compare/1.1.2...2.0.0
2.0.0-rc.2
Pre-release⚠️ Breaking changes
- Schema.org support now requires
spatie/schema-org^5.0, which needs PHP 8.4. Composer no longer installs Kirby SEO next to older versions of the package.
✨ Enhancements
- List each indexable translation as its own sitemap entry, with the same
hreflangalternates on every entry - Leave out translations with
noindexfromhreflangtags - Use the Interactions API for the Gemini provider
- Update the default AI Assist models to Claude Haiku 5.5 (Anthropic), GPT-6 Luna (OpenAI and OpenRouter) and Gemini 3.5 Flash-Lite (Gemini). Models set in your config stay unchanged.
🐛 Bug fixes
- Generate a valid IndexNow key. The key was always empty, and search engines could not verify submissions.
- Keep the Search Console OAuth state in the session and only redirect back to Panel URLs
- Build the Search Console connect URL from the site URL, which fixes sites installed in a subfolder
- Send Anthropic system messages as the top-level
systemparameter - Escape
&in sitemap URLs, write URL elements in schema order and link sitemap index entries without a language prefix - Accept an int timestamp in
SitemapUrl::lastmod() - Fix errors in debug mode on pages that use
metaDefaults - Find anchors with numeric IDs such as
#2024in the link audit - Build pagination links in the link audit from the checked page instead of the Panel API URL
- Return the updated row after saving a page with a numeric ID in the SEO overview
- Show the inherited value in empty "Crop OG Image" fields. The site field is now a select like the page field.
- Return Markdown for paginated pages such as
notes.md/page:2 - Reject HTML tags in SEO writer fields edited through Kirby Agents
The first link check after the update checks all links again.
📖 Documentation
- Add a guide for upgrading from Kirby SEO 1.x
- Add pages for the SEO overview and background processing
- Fix outdated statements across the docs, e.g. for robots.txt, the Search Console setup and custom AI providers
Full Changelog: https://github.com/tobimori/kirby-seo/compare/2.0.0-rc.1...2.0.0-rc.2
2.0.0-rc.1
Pre-release✨ Enhancements
- Limit the SEO overview to pages that search engines can index
- Show title-template prefixes and suffixes in the meta title column
⚡ Performance
- Speed up the SEO overview and sitemap on large sites by caching indexable pages and page, image and link audit results
🐛 Bug fixes
- Start the initial link scan when queue processing is enabled
- Keep overview results current after changes to parent pages, languages or relevant SEO options
- Apply page-specific robots rules when built-in robots handling is disabled
- Reload the SEO view after license activation so the activation banner disappears
- Log failed IndexNow requests from queue jobs
🔑 Licensing
- Require a Kirby SEO Enterprise license on sites that use Kirby Enterprise
Full Changelog: https://github.com/tobimori/kirby-seo/compare/2.0.0-rc.0...2.0.0-rc.1
2.0.0-rc.0
Pre-releaseKirby SEO 2 is now a release candidate. A license is required for public sites: buy a license.
✨ New features
- SEO overview in the Panel with stats and tabs for pages, images and links (#195)
- Check titles and descriptions for missing, duplicate, fallback and length issues
- Edit and generate meta fields with AI for many pages at once
- Edit alt texts for many images at once
- Check all links for broken targets
- Kirby Agents integration for the SEO writer and alt text fields (#196)
- Markdown versions of pages and
llms.txtfor LLMs (#191) - License activation in the Panel. Licenses are checked offline, and you can also add a license file manually as
site/config/.seo-license
✨ Enhancements
- AI assist uses the unsaved changes of a page
- IndexNow skips pages with a
noindexrobots rule robots.enabledis now the default for the deprecatedrobots.activeoption
⚡ Performance
- The sitemap index and
llms.txtuse the pages cache - Meta lookups are memoized during a render
- The SEO overview only checks pages again when they change
🐛 Bug fixes
- Return 404 for an unknown sitemap
- Throw an error for invalid sitemap alternates
- Parse the heading structure as UTF-8
- Skip AI alt texts for images that can't be resized without
ext-imagick - Handle requests without a page path
Full Changelog: https://github.com/tobimori/kirby-seo/compare/2.0.0-beta.5...2.0.0-rc.0
2.0.0-beta.5
Pre-release🐛 Bug fixes
- Fix canonical URL comparison when
canonical.trailingSlashis enabled (@notz, #188) - Add missing labels and IDs to SEO Writer and SEO preview form controls (@FlorianBoe, #187)
- Prevent fatal errors for non-resizable Open Graph images and hide them from the default image picker (#190)
Full Changelog: https://github.com/tobimori/kirby-seo/compare/2.0.0-beta.4...2.0.0-beta.5
2.0.0-beta.4
Pre-release✨ Enhancements
Full Changelog: https://github.com/tobimori/kirby-seo/compare/2.0.0-beta.3...2.0.0-beta.4
2.0.0-beta.3
Pre-release🚨 Breaking changes
- Enable
fallbackFieldscascade level by default: a page'sdescriptionis now used asog:descriptionbefore site-wide Open Graph values are reached, preventing site-level OG descriptions from overriding page-specific meta descriptions. RemovefallbackFieldsfrom the cascade to restore the previous behavior. See the Meta Cascade docs for details.
✨ Enhancements
- Improve sitemap XSL stylesheet with language alternate badges, cleaner URL display, and fixed table layout
- Resolve template variable labels in SEO Writer placeholder text
🐛 Bug fixes
- Fix sitemap stylesheet URL not resolving correctly on multi-language sites
- Remove unnecessary
role="presentation"attribute from decorative images in alt text output
2.0.0-beta.2
Pre-release🐛 Bug fixes
- Fix SEO Writer regression
Full Changelog: https://github.com/tobimori/kirby-seo/compare/2.0.0-beta.1...2.0.0-beta.2
2.0.0-beta.1
Pre-release🎉 Features
- Add alt text field (
alt-text) with AI-powered alt text generation from images, with auto-generation on upload - Add Google Gemini as a built-in AI provider
- Add background processing support for alt text generation via kirby-queues
✨ Enhancements
- Add multimodal image support to AI drivers (Anthropic, OpenAI, Gemini)
🐛 Bug fixes
- Fix robots indicator button not displaying correctly (#184)
♻️ Refactored
- Extract shared AI streaming utilities (
useAiStream,consumeSSEStream) from field components
Full Changelog: https://github.com/tobimori/kirby-seo/compare/2.0.0-alpha.13...2.0.0-beta.1
2.0.0-alpha.13
Pre-release🐛 Bug Fixes
- Fix double-encoded HTML entities in meta tag output when using Writer fields (#183)
2.0.0-alpha.12
Pre-release🐛 Bug Fixes
- Fix x-default hreflang pointing to language-specific URL instead of language-neutral switcher URL in multi-language setups (#177)
2.0.0-alpha.11
Pre-release🐛 Bug Fixes
- Fix language code not being passed in page.update:after hook, breaking multi-language page updates
- Fix hook running on pages without SEO tab, breaking compatibility with other plugins like DreamForm
2.0.0-alpha.10
Pre-release2.0.0-alpha.9
Pre-release2.0.0-alpha.8
Pre-release🐛 Bug Fixes
- Fix "using $this when not in object context" error when saving pages (#167)
- Fix favicon not displaying in Google preview component
2.0.0-alpha.7
Pre-release🎉 Features
- Add IndexNow support for instant search engine notifications
- Add components config syntax for easier component customization
2.0.0-alpha.6
Pre-release🎉 Features
- Add AI-powered meta tag generation with OpenAI and Anthropic support
- Add custom SEO writer field with specialized toolbar buttons
🐛 Bug Fixes
- Fix sitemap returning 404 for HEAD requests - caused "Sitemap could not be read" errors in Google Search Console (#164, thanks @tomsl123)
- Fix sitemap XSL stylesheet loading with wrong language prefix on multi-language sites (#160)
✨ Enhancements
- Add proper HTTP method handling for sitemap routes (OPTIONS returns 204, unsupported methods return 405)
- Fix writer toolbar button width (thanks @danburzo)
🌐 Translations
- Add Romanian translation (thanks @danburzo)
2.0.0-alpha.5
Pre-release🎉 Features
- Add custom SEO nodes for writer field
- Add custom SEO writer field
- Strip allowed HTML tags from meta tags for cleaner output
✨ Enhancements
- Improve site preview styling
2.0.0-alpha.4
Pre-release🎉 Features
- Add dark mode support for SEO previews
- Update Google SEO preview component to match current Google design
🐛 Bug Fixes
- Fix "Storage for the page is immutable" error when saving pages with kirby-seo fields (#145, thanks @ovenum)
- Fix x-default alternate link using wrong slug on non-default languages (#146)
- Fix Kirby template braces not being escaped in placeholder text (thanks @lukasleitsch)
♻️ Refactored
- Simplify files query in og-image.php (thanks @ovenum)
2.0.0-alpha.3
Pre-release🐛 Bug Fixes
- Fix all pages returning 404 when robots.index option is set to true (#140)
2.0.0-alpha.2
Pre-release🐛 Bug Fixes
- Fix "Value of type null is not callable" error caused by missing default.lang option (#139)
2.0.0-alpha.1
Pre-release🚨 Breaking Changes
- Requires Kirby 5
- Remove schema-org package from default plugin distribution - install separately if needed (#48)
- Major refactor of language handling for multi-language sites (#128)
🎉 Features
- Add priority meta tags support (#112)
- Add trailing slash configuration (#136)
- Add Mastodon profile link as rel="me" (#92)
- Skip alternate hreflang tags when URL is not canonical (#98)
🐛 Bug Fixes
- Fix OG image width/height not being set correctly (#91)
- Fix wrong sitemap URL on multi-language pages (#124)
- Fix sitemap URL not using canonical base URL (#88)
🌐 Translations
- Add Swedish translation (thanks @olach)
- Add Dutch translation (thanks @wietseneven)
- Add Czech translation (thanks @jan-herman)
1.1.2
🐛 Bug Fixes
- Google Search preview now shows the title correctly with the title preview (#90)
Full Changelog: https://github.com/tobimori/kirby-seo/compare/1.1.1...1.1.2
1.1.1
🐛 Bug Fixes
- Empty robots fields do not throw error when saving anymore
Full Changelog: https://github.com/tobimori/kirby-seo/compare/1.1.0...1.1.1
1.1.0
🚀 Features
/sitemapnow redirects to/sitemap.xml(#84) You can disable this behaviour by settingtobimori.seo.sitemap.redirecttofalse.
🐛 Bug FIxes
- Robots section defaults are now set correctly by Kirby logic & using a page.update hook (#89)
- Robots page settings now don't show up if Robots is disabled (#87)
Full Changelog: https://github.com/tobimori/kirby-seo/compare/1.0.0...1.1.0
1.0.0
First stable production release of kirby-seo.
💣 Breaking changes
If you previously used kirby-seo 0.4.0 or earlier, please follow the Migration guide.
🚀 New Features
- Kirby 4.0 redesign compatibility (#12)
- Complete refactor of the Meta class & cascading behaviour
- Customizable cascade option
- New languages: Turkish 🇹🇷 & Portuguese 🇵🇹 (#49 / #69)
- New Sitemap functionality (#47)
- Custom meta tags with programmatic cascade (#23)
- Use meta tag names instead of field names in programmatic cascade
...and tons of bug fixes! 🐛 (Take a look at early releases for a detailed summary)
This release was a ton of work and is available completely free of charge. If you use kirby-seo in a commercial project, I'd highly appreciate a sponsorship on GitHub (one-time available as well). If you need a commercial invoice or priority support, send me an email at seo@moeritz.io and we can figure things out.
Thanks to all contributors and everyone who created issues as well. @afbora, @JuKra00, @andrepimpao, @luxuryluke, @holmey
Full Changelog: https://github.com/tobimori/kirby-seo/compare/0.4.0...1.0.0
1.0.0-rc.7
Pre-release🐛 Bug Fixes
- Programmatic meta tags are now tracked correctly and no longer output twice
- Robots check for
canonicalandalternatetags no longer causes an infinite loop (#83) - Sitemap title in XSL template is now escaped to support ampersands, thanks to @JuKra00 (#81 / #82)
Full Changelog: https://github.com/tobimori/kirby-seo/compare/1.0.0-rc.6...1.0.0-rc.7
1.0.0-rc.6
Pre-release🐛 Bug Fixes
$site->lang()now returns the config language in the correct format for the<html>tag (#77)canonicalandalternatetags are not output anymore if the page is set tonoindexor therobotsmodule is disabled- Section label of
heading-structurenow looks as expected
📝 Docs
- Schema.org usage is now documented (#70)
- Sitemap docs now hint to robots docs for whether a page is indexed or not (#68)
heading-structuresection is now documented
Full Changelog: https://github.com/tobimori/kirby-seo/compare/1.0.0-rc.5...1.0.0-rc.6
1.0.0-rc.5
Pre-release🐛 Bug Fixes
- Regex pattern used for accessing the page context programmatic blueprints now supports
-and_
Full Changelog: https://github.com/tobimori/kirby-seo/compare/1.0.0-rc.4...1.0.0-rc.5