rankbeam / laravel-seo
Laravel SEO package for metadata, canonical URLs, Open Graph, linked JSON-LD, XML sitemaps and crawler controls - free and MIT licensed.
Requires
- php: ^8.2
- illuminate/cache: ^11.0|^12.0|^13.0
- illuminate/console: ^11.0|^12.0|^13.0
- illuminate/database: ^11.0|^12.0|^13.0
- illuminate/filesystem: ^11.0|^12.0|^13.0
- illuminate/http: ^11.0|^12.0|^13.0
- illuminate/routing: ^11.0|^12.0|^13.0
- illuminate/support: ^11.0|^12.0|^13.0
Requires (Dev)
- laravel/pint: ^1.0
- orchestra/testbench: ^9.0|^10.0|^11.0
- pestphp/pest: ^2.0|^3.0
- spatie/browsershot: ^4.0|^5.0
- spatie/laravel-sitemap: ^7.0|^8.0
Suggests
- spatie/browsershot: Generate 1200x630 OG images with a real browser (config seo.og_image)
- spatie/laravel-sitemap: Generate XML sitemaps for your models (^7.0|^8.0)
Provides
None
Conflicts
None
Replaces
None
- dev-master / 3.x-dev
- v3.21.1
- v3.21.0
- v3.20.1
- v3.20.0
- v3.19.0
- v3.18.0
- v3.17.0
- v3.16.3
- v3.16.2
- v3.16.1
- v3.16.0
- v3.15.0
- v3.14.0
- v3.13.0
- v3.12.0
- v3.11.2
- v3.11.1
- v3.11.0
- v3.10.0
- v3.9.0
- v3.8.1
- v3.8.0
- v3.7.0
- v3.6.2
- v3.6.1
- v3.6.0
- v3.5.0
- v3.4.0
- v3.3.0
- v3.2.0
- v3.1.1
- v3.1.0
- v3.0.0
- v2.0.1
- v2.0.0
- dev-docs/multilingual-support-visibility
- dev-fix/navigation-alignment
- dev-fix/localized-sample-report
- dev-fix/navigation-link-indicators
- dev-docs/blog-subdirectory
- dev-fix/sitemap-export-integrity
- dev-feat/public-ko
- dev-feat/public-zh-cn
- dev-feat/public-ja
- dev-feat/public-el
- dev-feat/public-cs
- dev-feat/public-ru
- dev-feat/public-pl
- dev-feat/public-tr
- dev-feat/public-nl
- dev-feat/translation-workflow
- dev-feat/ai-provenance
- dev-feat/founding-service-scope
- dev-docs/self-hosted-distribution
- dev-docs/final-localization-links
- dev-docs/released-scan-sitemap-behavior
- dev-fix/sitemap-resolution-reuse
- dev-fix/docs-portuguese-complete
- dev-fix/docs-portuguese-core
- dev-fix/docs-spanish-complete
- dev-fix/docs-spanish-core
- dev-fix/docs-french-complete
- dev-fix/docs-french-core
- dev-fix/docs-german-complete
- dev-fix/docs-german-core
- dev-fix/docs-italian-finish
- dev-fix/docs-italian-complete
- dev-docs/r13-review-status
- dev-docs/r11-portuguese-reference
- dev-docs/r11-portuguese
- dev-docs/r11-spanish-reference
- dev-docs/r11-spanish
- dev-docs/r11-french-reference
- dev-docs/r11-french
- dev-docs/r11-german-reference
- dev-docs/r11-german
- dev-docs/r11-italian-reference
- dev-docs/r11-localization
- dev-fix/r9-editor-integration
- dev-docs/r8-ai-evaluation
- dev-fix/r7-installation-floor
- dev-fix/r7-consumer-exit
- dev-fix/r7-render-evidence
- dev-fix/r6-display-locales
- dev-fix/r5-language-tag-validation
- dev-docs/r4-readability-contract
- dev-docs/r3-stemmer-contract
- dev-docs/r2-keyword-contract
- dev-fix/docs-build-postcss
- dev-fix/keyboard-code-regions
- dev-fix/docs-capture-quality
- dev-docs/pro-walkthrough
- dev-docs/design-review
- dev-fix/r1-content-locale
- dev-docs/indexnow-config-cache
This package is auto-updated.
Last update: 2026-09-27 17:18:11 UTC
README
Rankbeam is a Laravel SEO package built for production applications. The free MIT core resolves metadata through a layered precedence chain and renders canonical URLs, Open Graph and Twitter cards, a linked @id JSON-LD graph, XML sitemaps and crawler controls straight from your Laravel models and config.
composer require rankbeam/laravel-seo
Production auditing and monitoring (Pro) and the Filament admin UI ship as separate packages. This package never pulls them in.
Built for multilingual sites. Store SEO metadata per content locale, render
hreflang and inLanguage, and use title and description budgets suited to the
content's script. Package messages ship in 17 languages. Your application
supplies the translated content; Core does not translate ordinary model attributes
automatically. See multilingual content,
interface translations, or the free
Filament editor's language tabs.
Upgrading from
fibonoir/laravel-seov1? See UPGRADING.md — v2 renames the vendor and carves the old "full suite" down to this core; the analyzer, scanner, redirect manager, 404 monitor, and admin UI live on as separate packages (laravel-seo-filament, free;laravel-seo-pro, commercial).
What this package does
| Area | Details |
|---|---|
| Meta resolution | SEOResolver merges six layers — config → global DB defaults → model-type defaults → route defaults → computed model values → explicit seo_meta values. Null never overwrites a lower layer. |
| Computed fallbacks | Title/description/image/robots derived from model attributes. Description candidates are configurable (seo.computed.description_fields), normalized (HTML stripped, entities decoded), and truncated at a word boundary (default 160 chars, no ellipsis). Per-model robots/noindex is built in — a getSEORobots() hook or an is_indexable attribute, overridable per page via saveSEO(['robots' => …]). |
| Rendering | TagRenderer outputs HTML (@seo Blade directives), structured arrays (Vue/React), or Inertia Head format. JSON-LD is emitted with JSON_HEX_* escaping so </script> in content cannot break out of the script element. |
| Canonical policy | Derived canonicals (model URL / current URL) get the query string stripped; explicitly set canonicals are preserved verbatim. |
| Schema (JSON-LD) | Builders for Article, Breadcrumb, FAQ, LocalBusiness, Organization, Product; SchemaGraph for Organization/WebSite/WebPage nodes cross-linked via stable @ids; breadcrumbs from a page's ancestor chain with a loop guard. |
| Sitemaps | SitemapBuilder (wraps spatie/laravel-sitemap) with config-driven model sources, programmatic named sources via SEO::sitemaps()->register(...), sitemap index support, seo:sitemap command, and /sitemap.xml routes that can be disabled. Sitemaps open as a readable, branded page in the browser via a styled XSL stylesheet (on by default; search engines ignore it). |
| llms.txt | seo:llms-txt writes an optional markdown llms.txt index from the same sources as the sitemap (the registry + seo.sitemap.models), so the two never disagree. It's a compatibility file for tools that choose to consume it — Google Search does not use it. Served at /llms.txt, gated by config. |
| AI crawler control | seo:robots-txt renders a managed robots.txt (and ai.txt) from a doc-verified catalog of AI crawlers tagged by purpose — allow the AI-search and assistant crawlers (ai_search/ai_assistant), disallow the ones that train on you (ai_training) by default. SEO::robotsTxt()->aiDirectives() for a paste-able block; SEO::aiCrawlers() for the catalog + policy. Bots that ignore robots.txt are flagged advisory. |
| Markdown for bots | Content negotiation that serves clean markdown to AI crawlers instead of HTML — on Accept: text/markdown, ?format=md, or (opt-in) a known AI crawler — from a model's toSeoMarkdown(), a SEO::markdown()->register() source, or a built title+description+content fallback. Off by default; never touches a normal visitor's response. |
| Indexing guard | Ties indexability to the Laravel environment: outside seo.indexing_guard.allowed_environments (default ['production']) every page is forced to noindex,nofollow (above the whole precedence chain — overrides even a stored per-page value), robots.txt/ai.txt go disallow-all, and seo:audit warns. Stops a staging/local copy leaking into the index. Off by default, one-line opt-in SEO_INDEXING_GUARD=true, inert on production. See Indexing guard. |
| Generated OG images | Optional 1200×630 Open Graph images rendered by a real headless browser (spatie/browsershot) — correct multi-line wrapping, CJK/accents and truncation. Three publishable templates (default / article / product, selectable per model) + bundled OFL font; seo:og-images pre-generates and caches each card (content-hashed); the resolver serves it as a computed og:image fallback (existence-gated — never renders on a web request). Off by default, browser is a suggested dependency, static pre-generation only. See Generated OG images. |
| Warnings | SEOWarningEvaluator for admin UIs: title / description over the script's budget (60/160 for Latin, ~30/80 for CJK — see Multilingual content), manual-vs-fallback indicators, social-image dimension checks (min 200x200, ideal 1200x630, local files only). |
| Free audit | seo:audit — an in-process "what's wrong with my SEO right now" command (no queue, license, or network). Runs the metadata-class checks (missing / over- / under-length title & description, OG image, robots conflicts, canonical format/cross-domain/shared/insecure, hreflang code/duplicate/self-reference, focus keyword) and prints a per-page pass/warn/fail table with an explicit capability matrix. --strict for CI, --json for tooling. No numerical score (that's Pro). |
| Multilingual content | The package understands the language of your content, not only yours: per-script title/description budgets (LengthPolicy, graphemes not bytes), grapheme-safe truncation that cuts CJK at a sentence mark, locale-aware casing (Turkish İ/ı, Greek final sigma, ß), hreflang normalisation + self/x-default policies + audit codes, inLanguage on the schema graph, Yandex/Baidu/Naver/Seznam/Sogou/360/Cốc Cốc/DuckDuckGo in the crawler catalog, site-verification tags for eight engines, per-script OG-image font stacks with a missing-font pre-flight, IDN-tolerant canonical validation. Seventeen UI languages via --tag=seo-lang. See Multilingual content. |
| Explain resolution | seo:explain "App\Models\Post" 42 — the resolver precedence trace: per field, the winning layer + value, the losing layers it overrode, and post-processing notes (title suffix, canonical strip, og:url derivation, image absolutization, indexing guard). Plus a site-level ledger (site name, default locale, canonical host) naming each value's source. Human route:list-style output + --json. Read-only; can't drift from what renders. See Explain resolution. |
| Migration importer | seo:import-from ralphjsmit — bulk-import SEO data from a competing Laravel package's storage into seo_meta. Idempotent, --dry-run, --model= scoping, explicit field mapping, morph rows re-resolved to the live model. See Migrating from other packages. |
| WordPress importer | seo:import-from wordpress-csv (a CSV export) and seo:import-from yoast / rank-math (the live WordPress DB via --connection=). Maps Yoast/Rank Math keys explicitly (incl. OG/Twitter overrides), resolves %%title%%-style template tokens, matches posts to your models by slug, and emits a redirects CSV for Pro. See Migrating from WordPress. |
Database tables: seo_meta (per-model explicit values, morph + locale) and seo_defaults (global/model-type/route defaults). Nothing else.
Requirements
- PHP 8.2+
- Laravel 11, 12, or 13 (CI runs the full matrix; Laravel 13 requires PHP 8.3+; PHP 8.5 requires Laravel 12 or 13)
spatie/laravel-sitemap^7.0 or ^8.0 (suggested, required for sitemap generation)
Installation
composer require rankbeam/laravel-seo php artisan vendor:publish --tag=seo-config php artisan migrate
Quick start
use Rankbeam\Seo\Traits\HasSEO; class Post extends Model { use HasSEO; public function getUrlForSEO(): string { return route('posts.show', $this); } }
<head> @seo($post) </head>
Explicit values from the admin side:
$post->saveSEO([ 'title' => 'Custom SEO Title', 'description' => 'Custom meta description', ]);
Headless / Inertia:
use Rankbeam\Seo\Facades\SEO; return Inertia::render('Post', [ 'seo' => SEO::forInertia($post), ]);
Sitemap sources:
// config/seo.php 'sitemap' => ['models' => [Post::class => ['priority' => 0.8]]], // or programmatically (e.g. in a service provider) SEO::sitemaps()->register('pages', fn () => ['/about', '/contact']);
Then generate the files (requires spatie/laravel-sitemap) — the package's
/sitemap.xml route serves what this command writes:
composer require spatie/laravel-sitemap php artisan seo:sitemap
Serving your own static /sitemap.xml? Disable the package routes:
// config/seo.php 'routes' => ['enabled' => false],
Audit your SEO
# Audit the models under seo.audit.models / seo.sitemap.models php artisan seo:audit # Or target specific models, CI-fail on any issue, or emit JSON php artisan seo:audit --model="App\Models\Post" --strict php artisan seo:audit --json
A free, in-process pass/warn/fail report over the metadata-class checks. The rendered-HTML and live-canonical checks, and the numerical score, are part of the Pro scan — the command prints that boundary every run.
Generate llms.txt
php artisan seo:llms-txt # writes public/llms.txt php artisan seo:llms-txt --print # print to stdout (dry run)
A markdown index of your site for AI crawlers (llms.txt),
built from the same sources as your sitemap — registered sources plus
seo.sitemap.models, with the same noindex/unpublished exclusions — so the two
never disagree. It is served at /llms.txt (disable that route via
seo.llms_txt.route), and you can schedule it alongside the sitemap:
Schedule::command('seo:llms-txt')->daily();
AI crawler control (robots.txt / ai.txt)
php artisan seo:robots-txt # writes public/robots.txt php artisan seo:robots-txt --print # print to stdout (dry run) php artisan seo:robots-txt --ai-txt # also write public/ai.txt
A managed robots.txt for the AI era, rendered from a doc-verified catalog of
AI crawlers tagged by purpose. The default policy allows the AI-search and
assistant crawlers (ai_search / ai_assistant) and disallows the ones that
train on your content (ai_training); override per purpose or per bot in
seo.ai_crawlers. Grab
just the managed block for an existing file with SEO::robotsTxt()->aiDirectives(),
or serve /robots.txt dynamically (off by default — it won't shadow a static
file). Bots documented not to honour robots.txt are flagged advisory. See
AI crawler control.
Guides
Long-form articles on the Rankbeam blog, a Laravel app that runs this package on itself:
- Laravel SEO: the complete guide
- Best Laravel SEO packages compared
- Laravel meta tags
- Canonical URLs in Laravel
- JSON-LD schema graphs
- Laravel sitemaps
- Laravel SEO audit in CI
- hreflang done right
- Answer engine optimization
- Filament SEO fields
Test status
Recorded full suite for core 3.20.0: 1036 passed (4363 assertions), 0 failed under PHP 8.4 / Laravel 13, with 17 default skips (16 opt-in Chrome image checks and one ext-xsl check). Real OG/PDF rendering and runtime-consumer checks run separately; default skips are not evidence that those paths ran. Public CI covers the supported PHP 8.2–8.5 / Laravel 11–13 combinations; Laravel 13 requires PHP 8.3 or newer, and PHP 8.5 is tested with Laravel 12 and 13.
git clone https://github.com/rankbeam/laravel-seo.git
cd laravel-seo
composer install
vendor/bin/pest
What is not in this package
Queued site scans, content analysis, redirect manager, 404 monitor, and the SEO dashboard ship in laravel-seo-pro (commercial); the Filament admin form fields ship in laravel-seo-filament (free). The old seo:install stub-publishing flow is gone.
Contributing
Translations are welcome — see TRANSLATING.md (language files, glossary, the parity test).
Bug reports, fixes and features are welcome — see CONTRIBUTING.md for the package boundary (what belongs in core vs. the Filament/Pro packages), how to run the suite, the rendering contract, and the versioning/BC policy.
Security
Please report security vulnerabilities privately, not in a public issue — see SECURITY.md.
License
MIT — see LICENSE.md.