KIRBY CMS SEO AUDIT · PANEL BLUEPRINTS · PHP SNIPPETS · FLAT-FILE

Free Kirby CMS SEO Audit

Kirby SEO depends on Panel blueprint field configuration, PHP snippet meta tag output, custom JSON-LD in site snippets or a Kirby Schema plugin, sitemap generation via plugin or custom template, and flat-file PHP performance. DeepSEOAnalysis audits your live Kirby site — validating meta tag output, structured data, sitemap coverage, real CrUX Core Web Vitals, and AI visibility — with PHP snippet code, blueprint YAML, and Panel field references for every finding.

Audit my Kirby site →How we score

WHAT WE CHECK

6 Kirby-specific SEO checks

Kirby SEO auditing covers Panel blueprint field configuration and PHP snippet meta tag output, URL structure and custom routing, JSON-LD in Kirby snippets via custom PHP or Kirby Schema plugin, sitemap plugin or custom template configuration, Core Web Vitals from real CrUX data, and AI visibility — with PHP snippet code, blueprint YAML, and Kirby thumb() references for each finding.

🔧

Panel blueprint fields and meta tag snippet output

Kirby\'s Panel-driven SEO depends on two layers: the blueprint field configuration that provides editors with SEO fields, and the PHP snippet that outputs those fields as HTML meta tags. The audit checks: meta title presence and format across crawled pages (Kirby\'s `$page->seoTitle()->or($page->title())` fallback chain means pages without a custom `seoTitle` fall back to the navigation title — the audit detects whether the title format is keyword-descriptive or just the navigation label); meta description presence (the `seoDescription` textarea field must be filled per page — the audit checks for empty descriptions across crawled pages); canonical tag correctness (`$page->url()` outputs the canonical URL in Kirby\'s routing — for multi-language Kirby sites, verify that language variants each have their own canonical pointing to the language-specific URL, not the default language URL); noindex control (the `seoNoindex` toggle or the Kirby Meta plugin\'s noindex field must render `meta name="robots" content="noindex"` correctly — the audit checks that pages set to noindex are noindex in the HTML and that pages without noindex have no accidental noindex tag); Open Graph tag coverage (og:title, og:description, og:image — particularly important for Kirby sites used for portfolio or editorial content where social sharing is significant); and title uniqueness across crawled pages (Kirby\'s flat-file nature means all content lives in `content/` folder pages — duplicate titles indicate pages without custom seoTitle fields that all fall back to the same generic navigation label).

🔗

URL structure and Kirby routing

Kirby uses a content-folder-based URL structure: the `content/` directory hierarchy maps directly to URLs (`content/01_about/` → `/about/`). The prefix numbers (`01_`, `02_`) are for Panel ordering and are stripped from public URLs. The audit checks: URL slug quality (Kirby\'s default slug is generated from the folder name — non-descriptive folder names like `page-3` or `item-12` produce poor URLs; the slug can be overridden in the Panel\'s "title" field or via Kirby\'s slug plugin); URL structure depth (Kirby\'s nested folder structure maps directly to URL depth — deep nesting creates deep URLs; typical Kirby site structure: home → section → page, with depth 3 being the common maximum); custom routes (Kirby supports custom routing in `site/config/config.php` via `\'routes\'` — custom routes can override the content-folder URL structure for specific page types, enabling cleaner URLs for blog posts or portfolio items; the audit checks that routed URLs have canonical tags pointing to the routed URL, not the content-folder URL); and multi-language URL configuration (Kirby\'s multi-language setup prefixes URLs with language codes `/de/`, `/fr/` — the audit checks hreflang implementation across language variants, verifying that each language page has corresponding `link rel="alternate" hreflang` tags for all available languages and `x-default`).

📋

JSON-LD structured data in Kirby snippets

Kirby\'s PHP template system makes structured data implementation straightforward — a PHP snippet can output JSON-LD using Kirby\'s page object values directly. The audit validates all JSON-LD blocks found in the server-rendered HTTP response. For Article/BlogPosting on editorial pages: `headline` (from `$page->title()`), `datePublished` (from a date field: `$page->date()->toDate(\'Y-m-d T\'H:i:sP\')`), `dateModified` (from `$page->modified(\'Y-m-dTH:i:sP\')`), `author` (from a user field or custom author text field — nested `Person` with `name` and optionally `url`), `publisher` (site Organization with name and logo), `image` (from a cover image file field: `$page->cover()->toFile()->url()`). For FAQPage on pages with a structure field of question/answer pairs: iterate with `foreach ($page->faqs()->toStructure() as $faq)` to build the `mainEntity` array. For BreadcrumbList: use `$page->parents()` to iterate the Kirby parent chain and output `itemListElement` entries. For the site-wide WebSite and Organization: include once in the main layout template via a global snippet. Common issues the audit catches: JSON-LD blocks that are correct syntactically but missing required properties (e.g., FAQPage with `@type: "FAQPage"` but no `mainEntity`), and schema injected via JavaScript after page load (not indexable by Google).

🗺️

XML sitemap for Kirby

Kirby CMS does not include an XML sitemap in its core. Sitemap options: (1) Kirby Sitemap plugin (multiple plugins available on GetKirby.com) — automatically generates a `/sitemap.xml` from all public, non-draft Kirby pages; configuration options typically include: excluding specific page templates from the sitemap, setting page-type-specific `changefreq` and `priority` values, and controlling `lastmod` from the page\'s content modification date. (2) Custom PHP template — create `site/templates/sitemap.xml.php` with a custom Kirby template that iterates the site\'s pages (`$site->index()->published()`) to generate the sitemap. Set the page blueprint to `template: sitemap`, create the content file `content/sitemap/sitemap.txt`, and add a route in `config.php` to serve it at `/sitemap.xml`. The audit checks: sitemap accessibility at the URL declared in `robots.txt` (the `Sitemap:` directive must match the actual sitemap path); URL format in sitemap entries (Kirby multi-language sites should list language-specific URLs, not just the default language); `lastmod` population (plugin-based sitemaps use file modification dates from the content folder; custom template sitemaps should use `$page->modified(\'c\')`); draft/unlisted exclusion (Kirby\'s page status system — draft, unlisted, published — should ensure that draft and unlisted pages aren\'t included in the public sitemap); and Sitemap directive in `robots.txt` (Kirby doesn\'t auto-add the Sitemap directive — it must be added manually to the `robots.txt` file in the public root or generated via a robots.txt template).

Core Web Vitals for Kirby

Kirby is a PHP flat-file CMS — pages are generated server-side (or cached as static files) with no JavaScript rendering gap for content. Performance characteristics depend heavily on whether Kirby is running with its built-in page cache and the server/hosting configuration. **LCP** — Kirby sites typically render the hero image or main content block in the first viewport. Add `fetchpriority="high"` and `loading="eager"` to the LCP image in the Kirby template: `img src="<?= $image->url() ?>" fetchpriority="high" loading="eager" width="<?= $image->width() ?>" height="<?= $image->height() ?>"`. Use Kirby\'s built-in `thumb()` method with webp format: `$image->thumb([\'width\' => 1200, \'format\' => \'webp\'])->url()`. **INP** — Kirby sites with minimal JavaScript have naturally low INP. Kirby\'s Panel JavaScript doesn\'t load on the public frontend. Third-party scripts (analytics, chat widgets, social embeds) are the primary INP concern on Kirby sites. Defer all non-essential JavaScript. **CLS** — Kirby\'s thumb() method returns images with the dimensions from the thumb configuration — verify the template outputs `width` and `height` attributes on all `img` tags to prevent layout shift during image load. **TTFB** — Kirby\'s page cache (`\'cache\' => [\'pages\' => [\'active\' => true]]` in `site/config/config.php`) caches rendered HTML to the filesystem, making subsequent page loads essentially static file serves. Enable the page cache in production. For PHP hosting without page caching, Nginx/Apache page caching or Cloudflare Page Rules can cache Kirby\'s PHP output. The audit uses real CrUX field data for LCP, INP, and CLS.

🧠

AI visibility for Kirby sites

Add `llms.txt` to Kirby\'s public root directory (the same directory as `index.php` — typically the public web root, which in modern Kirby installations may be the project root or a `public/` subdirectory). The file lists the site\'s content sections, key pages, and primary topics in plain text, accessible at `/llms.txt`. Verify AI crawlers are not blocked in `robots.txt` — check that GPTBot, ClaudeBot, and PerplexityBot are not caught by any broad `Disallow:` rules. Kirby doesn\'t generate a `robots.txt` automatically — it must be created manually in the public root or via a Kirby template/route (`site/config/config.php` route for `/robots.txt`). For FAQPage JSON-LD: add a Kirby structure field named `faqs` to the page blueprint (with `question` and `answer` fields), fill it in the Panel, and iterate in the seo snippet to output FAQPage JSON-LD. For question-format headings in Kirby\'s content: use Kirby\'s Blocks field (the visual block editor) with a dedicated Heading block and encourage editors to phrase H2 headings as questions for FAQ-style content. The audit checks all five AI visibility signals — llms.txt, AI crawler access, FAQPage/HowTo JSON-LD in server-rendered HTML, question-heading ratio (≥20%), and content chunkability (avg section ≤400w) — with Kirby PHP snippet code, blueprint YAML, and Panel field references for each fix.

HOW IT WORKS

Audit your Kirby site in 60 seconds

  1. Enter your Kirby site URL. No Panel access, filesystem access, or PHP credentials needed — the audit crawls the public HTTP output as Googlebot would. Works with all Kirby versions (3.x, 4.x), any custom template structure, and with or without SEO plugins installed.
  2. We crawl and analyse. The engine checks meta tag output across crawled pages, validates JSON-LD in the raw server HTTP response, checks sitemap coverage and URL format, measures CrUX Core Web Vitals from real Chrome field data, evaluates all five AI visibility signals, and detects any content only available in the JavaScript-rendered DOM vs the PHP-rendered response.
  3. You get a prioritised report. Kirby-specific issues first — missing seo snippet output, empty Panel fields, missing JSON-LD, sitemap gaps, llms.txt absence — then general SEO, each with the PHP snippet code, blueprint YAML field definition, or Panel field reference for the fix.

FAQ

Questions about the Kirby CMS SEO audit

Does Kirby CMS have built-in SEO features?

Kirby CMS does not have built-in SEO features in its core — it provides a flexible field system in the Panel (the admin interface) and a Kirby template engine (PHP snippets and templates), so SEO functionality must be built into the blueprint field configuration and the PHP templates. In practice, most Kirby sites use one of two approaches: (1) A custom SEO snippet — a PHP file (e.g., `site/snippets/seo.php`) that outputs meta title, meta description, canonical URL, Open Graph tags, and optionally JSON-LD from custom Panel fields. The snippet is included in the main layout template (`<?php snippet(\'seo\') ?>`). Common Panel fields for SEO: `seoTitle` (text field), `seoDescription` (textarea), `seoNoindex` (toggle). (2) The Kirby SEO plugin or Kirby Meta plugin — third-party Kirby plugins that add a dedicated SEO section to the Panel with field groups for meta tags, Open Graph, structured data, and sitemap control. The Kirby Meta plugin (by Tobias Möritz) is widely used and includes automatic title/description fallbacks, OpenGraph/Twitter card fields, and robots tag control. The audit validates what\'s present in the server-rendered HTML regardless of whether a custom snippet or a plugin provides it.

How do I add meta tags in Kirby CMS?

Adding meta tags in Kirby requires two steps: (1) Define fields in the page blueprint (e.g., `site/blueprints/pages/article.yml`): add a sections group with `seoTitle` (type: text), `seoDescription` (type: textarea, maxlength: 160), `seoNoindex` (type: toggle, text: [Indexed, Noindex]). (2) Output the fields in a PHP snippet (`site/snippets/seo.php`): `title><?= $page->seoTitle()->or($page->title())->html() ?> | <?= $site->title()->html() ?></title`. For the meta description: `<?php if ($page->seoDescription()->isNotEmpty()): ?><meta name="description" content="<?= $page->seoDescription()->html() ?>">...`. For the canonical: `link rel="canonical" href="<?= $page->url() ?>"`. Include the snippet in your main layout template: `<?php snippet(\'seo\') ?>` inside the `head` section. For Open Graph tags, add `ogTitle`, `ogDescription`, and `ogImage` fields to the blueprint. The Kirby Meta plugin simplifies this considerably by adding a pre-built meta section to any blueprint with a single include.

How do I add JSON-LD structured data in Kirby CMS?

Kirby CMS doesn\'t output JSON-LD by default. Options for adding structured data: (1) Custom PHP snippet — create `site/snippets/schema.php` that outputs a `script type="application/ld+json"` block using Kirby page object values: `$page->title()->value()` for the name, `$page->date()->toDate(\'Y-m-d\')` for datePublished, `$page->url()` for the canonical URL, and `$page->cover()->toFile()->url()` for the image URL. For Article schema: author via `$page->author()->toUser()` or a custom field. (2) Kirby Schema plugin — the Kirby Schema plugin by Johannes Tolly provides a PHP API for adding structured data without manually building JSON: `$kirby->snippet(\'schema/article\', [\'page\' => $page])`. (3) Blueprint-driven JSON-LD — define a `schemaType` select field in the blueprint and switch the JSON-LD output type in the snippet based on the selected value. For FAQPage: create a structured field block in the Panel (structure field with question/answer columns) and iterate in the snippet: `foreach ($page->faqs()->toStructure() as $faq)`. The audit checks that JSON-LD appears in the server-rendered PHP response (not JavaScript-injected) and validates all required properties.

Is the Kirby CMS SEO audit free?

Yes. The complete audit is free with no signup and no email gate. Paid plans add saved history, scheduled monitoring, larger crawls (up to 1,000 pages), and agency workflows.