backstage/laravel-seo-scanner
Laravel SEO Scanner audits your application's pages for common SEO issues, checking meta tags, titles, headings, links, images, and more. It integrates smoothly into Laravel projects and generates clear reports with actionable recommendations to improve search visibility.
Install it as a development dependency so it never ships to production:
composer require --dev backstage/laravel-seo-scanner
Publish the package config and inspect it first — this is where the scanner learns which URLs to crawl and which checks to run:
php artisan vendor:publish --tag="seo-scanner-config"
Look at these three places before writing any code:
config/seo-scanner.php) — base URL, paths/routes to scan, ignored URLs, thresholds.src/ directory — the exact artisan command signature and available checks change between releases; run php artisan list | grep -i seo to confirm the command name.php artisan route:list) — the scanner audits rendered HTTP responses, so you need to know which routes are publicly reachable and return HTML.The first useful use case is a pre-deploy audit of a staging environment: point the config at your staging URL, run the scan, and read the report for missing titles, descriptions, canonical tags, heading structure, and image alt attributes. Treat the first run as a baseline rather than a pass/fail gate — most apps have dozens of pre-existing findings.
A typical minimal workflow:
# 1. Configure the base URL and paths to scan
# 2. Clear cached config
php artisan config:clear
# 3. Run the scan (confirm exact signature from the README)
php artisan seo:scan
# 4. Fix the highest-impact issues first:
# missing/duplicate titles, missing meta descriptions,
# multiple H1s, images without alt text, non-canonical URLs
CI regression gate. The highest-leverage pattern is running the scanner in CI against a booted application and failing the build when the score drops below a threshold. Boot the app on a fixed port, run the scan against http://127.0.0.1:8000, and publish the report as a build artifact. Store the previous score and compare, so you catch regressions instead of chasing an absolute number.
# conceptual CI step
- run: php artisan serve --port=8000 &
- run: php artisan seo:scan --url=http://127.0.0.1:8000
Scheduled production auditing. Add the scan to the scheduler weekly and notify the team on new failures. This is more useful than a one-off audit because content teams continuously add pages that silently miss metadata. Keep it read-only and rate-limited.
Route- or sitemap-driven coverage. Rather than hardcoding URLs, feed the scanner your sitemap.xml or derive paths from route:list. This keeps coverage aligned as routes are added. For parameterized routes, seed a small set of representative URLs (a product page, a category page, a CMS page) instead of trying to enumerate everything.
Authenticated and gated pages. For pages behind login or feature flags, configure the scanner to send the headers/cookies it needs, or run it in an environment where those gates are open. Do not disable auth globally just to scan.
Baseline-and-diff workflow. On the first adoption run, record the findings as a baseline. In PRs, diff against the baseline so reviewers see only new SEO problems. This is the difference between a tool the team ignores and one they act on.
Pair with a rendering test for JS-heavy pages. If your meta tags are injected client-side, the scanner will not see them. Combine it with a browser-based test (Dusk, Pest browser plugin, or Playwright) that asserts the rendered <head> for your SPA-ish pages.
Extension points. Most scanners of this style expose custom checks or a way to register additional rules. When your team has a house rule — e.g. “every page must have an Open Graph image” — implement it as a custom check rather than a code-review convention, so it is enforced automatically.
APP_URL and the scan base URL are different things. A mismatch between the URL the scanner crawls and the URL Laravel generates for canonicals/links produces confusing redirect and canonical failures.noindex creates false positives. If staging is protected by basic auth or has X-Robots-Tag: noindex, the scanner may flag robots issues that do not exist in production. Scan a production-like environment, or explicitly configure exclusions.config/seo-scanner.php, run php artisan config:clear. In CI, ensure config is not cached from an earlier step with stale values.noindex anyway.^1.0 (or the exact current minor) and read the changelog before upgrading.require-dev and out of request handling.How can I help you explore Laravel packages today?