Grav CMS SEO audit

Grav is a flat-file PHP CMS — no database, Twig templates, Markdown content in user/pages/, and a plugin ecosystem for extending functionality. Grav's caching layer delivers fast TTFB, but canonical tags, sitemap generation, and JSON-LD structured data all require plugins or theme customisation. DeepSEOAnalysis audits your Grav site's rendered HTML: template meta tag coverage, canonical tag correctness, structured data validation, sitemap and robots.txt configuration, Core Web Vitals from real CrUX data, and AI visibility scoring.

Run free Grav SEO audit →

What the audit checks on Grav CMS sites

Grav theme Twig template meta tag coverage and SEO plugin configuration
Grav's meta tag output depends on the active theme's Twig templates and whether the grav-plugin-seo (or equivalent) is installed and configured. The audit validates what is rendered in the page HTML: whether the <title> tag uses the page title from page.header.title (or the SEO plugin's title override) combined with the site title from site.title in the configuration; whether meta description is populated from the page's frontmatter description field or the SEO plugin's meta description field (Grav does not auto-generate descriptions from content — the field must be explicitly filled in the page editor or blueprint); whether OG title, OG description, og:image, og:url, og:type meta tags are present and use absolute URLs; whether canonical tags output absolute URLs using page.url(true) (not relative paths); whether Twitter Card tags are present; and whether pages marked with routable: false or published: false are correctly excluded from public HTML output. The audit also checks whether modular subpages (components used in page assembly) are accessible at independent URLs — these should be non-routable to prevent thin page indexing.
URL structure and Grav routing configuration
Grav's URL structure is derived directly from the folder structure in user/pages/. The numeric prefix used for ordering (01.home/, 02.blog/) is stripped from URLs by default, producing /home/ and /blog/. Folder names become URL slugs — folder name quality determines URL quality. The audit checks: whether page folder names are keyword-descriptive and hyphenated (spaces in folder names produce URL-encoded %20 paths); whether the site.home alias in system.yaml correctly redirects / to the home page; whether custom routes defined in page frontmatter (routes: /my-custom-path) are used correctly; whether Grav's clean URL mode is enabled (removes .html extensions for clean paths); whether modular pages (folders starting with _) are correctly non-routable; whether slug overrides in page frontmatter (slug: my-custom-slug) are used for pages where the folder name produces a poor URL; and whether trailing slash behaviour is consistent and canonical tags reflect the correct canonical form.
JSON-LD structured data via Twig template customisation or schema plugin
Grav generates no JSON-LD by default. Structured data on Grav sites requires either theme template modification or a dedicated schema plugin. The audit validates: whether Article JSON-LD is present in the page HTML (absent unless a template or plugin has been implemented); whether Article schema includes required properties — headline from page.header.title, datePublished from page.date formatted as ISO 8601 ({{ page.date | date("Y-m-d\TH:i:s") }} in Twig), dateModified from page.modified, author Person with name from page.header.author or the site configuration, image from page.header.og_image or a configured default; whether FAQPage JSON-LD is present on applicable pages; whether BreadcrumbList JSON-LD reflects the page hierarchy (using the ancestors() Twig function to build the breadcrumb chain); whether Organization and WebSite JSON-LD are in the base template; and whether all structured data is in the server-rendered HTML (guaranteed with Grav's PHP-rendered Twig templates — no client-side rendering risk). The grav-plugin-breadcrumbs and grav-plugin-schema (community plugins) provide structured data output without custom template work.
grav-plugin-sitemap, robots.txt, and AI crawler configuration
Grav requires the sitemap plugin for sitemap.xml generation. The audit validates: whether sitemap.xml is accessible at /sitemap.xml; whether the sitemap contains all public pages (pages with published: true and routable: true); whether modular subpages are excluded; whether lastmod dates are populated from page date/modified frontmatter fields; whether the sitemap uses absolute URLs (requires correct site.url in Grav configuration); whether robots.txt is accessible at /robots.txt (Grav has a built-in default robots.txt; customise via user/config/site.yaml or a custom page template); whether robots.txt declares the sitemap URL using the Sitemap: directive; and whether explicit User-agent entries for AI crawlers (GPTBot, ClaudeBot, PerplexityBot, Google-Extended, CCBot) are present with Allow: / directives. For llms.txt: Grav can serve a custom llms.txt by creating a user/pages/llms.txt/ directory with a custom page template that routes to /llms.txt and serves the llms.txt content with appropriate Content-Type headers.
Core Web Vitals for Grav CMS sites
Grav is a flat-file CMS with a built-in caching system (Twig cache, page cache, asset pipeline cache) — when caches are warm, page delivery is fast with good TTFB. The main Core Web Vitals risks on Grav sites are theme-dependent: (1) LCP — Grav's asset pipeline can combine and minify CSS and JS, but hero images require fetchpriority="high" in the theme template to prioritise loading. Default themes vary in whether they implement this. (2) CLS — Grav's image handling does not add width and height attributes automatically; themes must include explicit image dimensions in their img tags to prevent layout shift from undeclared image dimensions. Web font loading from external CDN (Google Fonts is commonly used in Grav themes) requires font-display: swap to prevent FOUT-induced CLS. (3) INP — most Grav sites have minimal JavaScript; INP risk comes from plugins that inject frontend JavaScript (comment systems, contact forms, analytics). Grav's asset pipeline can defer JS loading. Measure with real CrUX field data — not just Lighthouse lab scores — to see actual user experience on real devices and connection speeds.
AI visibility and GEO score for Grav CMS sites
Grav's PHP-rendered Twig templates produce server-side HTML — all content and template-generated structured data is in the initial HTML response, making it immediately accessible to AI crawlers. The five AI visibility signals for Grav: (1) AI crawler access in robots.txt — customise the default Grav robots.txt to add explicit User-agent allowances for GPTBot, ClaudeBot, PerplexityBot, Google-Extended, and CCBot. The default Grav robots.txt allows all crawlers, but explicit configuration is better practice. (2) llms.txt — add a custom Grav page with a template that serves the llms.txt content at /llms.txt; or use a custom route in Grav to serve a static llms.txt file. (3) FAQPage JSON-LD — add via Twig theme template or a community schema plugin for pages with FAQ content. (4) Question-heading ratio — Grav Markdown content supports question-format H2s and H3s natively; the GEO score measures whether ≥20% of H2/H3 headings are phrased as questions. (5) Content chunkability — Grav's Markdown content with section headings creates well-chunked passages; verify sections average ≤400 words for clean AI extraction.

How to audit your Grav site

  1. Enter any URL from your Grav site — the homepage, a blog post, or a category listing page.
  2. DeepSEOAnalysis validates the server-rendered HTML output: Twig template meta tag and canonical tag coverage, JSON-LD structured data completeness, robots.txt AI crawler access, sitemap presence, and Core Web Vitals from real CrUX field data.
  3. Review findings: missing canonical tags, structured data property errors, AI visibility score, and Core Web Vitals issues from real user sessions.
  4. Share the audit URL with your development team or agency — no login required to view results.

Grav CMS SEO frequently asked questions

Does Grav CMS have good SEO out of the box?
Grav provides a reasonable SEO foundation — flat-file performance (no database queries), clean URL routing from the folder structure, and Twig templates that can be customised for any meta tag output. However, several SEO features require plugins or theme customisation: (1) Canonical tags — not generated by default; must be added to the theme\'s base.html.twig template using Grav\'s page.url() function or the built-in {{ page.canonical }} shortcut available in themes using the Grav SEO plugin. (2) Sitemap.xml — not generated by default; requires the grav-plugin-sitemap plugin (install via Admin Panel → Plugins → Add, or bin/gpm install sitemap). (3) JSON-LD structured data — not generated by default; requires theme customisation or a dedicated schema plugin. (4) robots.txt — Grav has a built-in robots.txt route that serves a default allow-all robots.txt, which can be overridden by placing a custom robots.txt in the user/pages/ directory using a special page template, or by using the grav-plugin-robots-txt plugin. The Grav SEO plugin (grav-plugin-seo) adds per-page meta description, OG tags, Twitter Card tags, and canonical URL fields accessible from the Admin Panel page editor — significantly improving SEO capability without requiring custom Twig template work.
How do you add canonical tags to Grav?
Grav canonical tags can be added via three approaches: (1) **Grav SEO Plugin** — the grav-plugin-seo plugin adds a canonical URL field to each page\'s SEO tab in the Admin Panel and automatically outputs the canonical tag in the page <head>. This is the simplest approach. (2) **Theme template** — in the theme\'s templates/partials/base.html.twig (or equivalent), add <link rel="canonical" href="{{ page.url(true) }}"> inside the <head> block. The true parameter in page.url(true) generates the absolute URL using the site.url configuration. Without true, page.url() generates a relative URL, which is invalid for canonical tags. (3) **Blueprint customisation** — for advanced per-page canonical overrides, add a canonical_url field to the page blueprint and reference it in the template: {{ page.header.canonical_url | default(page.url(true)) }}. After implementing canonical tags, verify the output by running a site build or checking rendered HTML — particularly verify that the canonical href is an absolute URL (https://...) not a relative path (/).
How do you install the Grav sitemap plugin?
The Grav Sitemap plugin (grav-plugin-sitemap) generates sitemap.xml automatically. Installation: via Admin Panel (navigate to Plugins → Add → search "sitemap" → Install), or via command line: bin/gpm install sitemap from the Grav root directory. After installation, the sitemap is accessible at /sitemap.xml. Configuration options in the plugin settings (Admin Panel → Plugins → Sitemap): exclude specific pages from the sitemap by setting visible: false in their frontmatter, or by adding URLs to the plugin\'s exclusion list; include or exclude modular pages (sub-pages used as page components); set the default change frequency and priority. The sitemap plugin reads the page\'s date and modified frontmatter fields for <lastmod> values. Pages with published: false in their frontmatter are excluded. Verify the generated sitemap by accessing /sitemap.xml on the live or local Grav installation and checking that all important pages are present with absolute URLs.
What are the most common SEO problems on Grav CMS sites?
The most common Grav SEO issues: (1) **No canonical tags** — most default Grav themes and the base Grav installation do not output canonical tags. Every Grav site needs either the SEO plugin or a theme template modification to add canonical tags. (2) **No sitemap.xml** — Grav does not generate a sitemap by default; the sitemap plugin must be installed separately. Sites without a sitemap may have slower discovery of new pages by Googlebot. (3) **No JSON-LD structured data** — Grav generates no structured data by default. Schema markup requires theme customisation or a plugin. (4) **Slug and URL quality** — Grav uses the folder name as the URL slug (01.home/ generates /home/). The numeric prefix (01., 02.) is for ordering and is stripped from URLs by default. However, folder names with spaces or poor naming choices produce poor URL slugs. (5) **Modular page indexing** — Grav modular pages (page components used in page assembly) are often inadvertently indexed. These should have routable: false and visible: false in their frontmatter to prevent independent indexing as thin pages. (6) **Missing robots.txt configuration** — Grav\'s default robots.txt allows all crawlers; it should be customised to include the sitemap declaration and explicit AI crawler allowances.