Skip to content
Pro Analyzer — Available with ShieldCI Pro

Fallback Routes SEO Analyzer

Analyzer IDCategorySeverityTime To Fix
fallback-routes⚡ PerformanceLow15 minutes

What This Checks

Detects the use of Route::fallback() and root-level catch-all routes that can cause "soft 404" issues, negatively impacting SEO by returning 200 OK for non-existent pages.

PatternExampleDetected
Route::fallback()Route::fallback(fn() => view('404'))✅ Always
/{any} catch-allRoute::get('/{any}', ...)✅ Root-level only
/{any?} optionalRoute::get('/{any?}', ...)✅ Root-level only
/{path?} optionalRoute::get('/{path?}', ...)✅ Root-level only
/{catchall}, /{all}Route::get('/{all}', ...)✅ Root-level only
->where($param, '.*')Route::get('/{slug}')->where('slug', '.*')✅ Regex catch-all

Catch-all detection applies only when the parameter is the entire URI (e.g., {any}, not /posts/{any}). API routes (URIs starting with api/ or carrying api middleware) and routes registered by vendor packages (controllers outside App\) are always exempt.

Why It Matters

  • SEO Impact: Search engines like Google will index garbage URLs because they receive 200 OK instead of 404
  • Crawl Budget Waste: Search engine bots waste crawl budget on non-existent pages
  • Search Console Warnings: Google Search Console will report "soft 404" issues
  • User Experience: Users may be confused when non-existent URLs don't show proper 404 pages

When a fallback route returns 200 OK for any URL, search engines assume the content is valid and index it. This can result in thousands of junk pages appearing in search results.

How to Fix

Quick Fix (5 minutes)

Ensure the fallback or catch-all route handler returns a 4xx status code instead of 200 OK:

Before (❌):

php
Route::fallback(function () {
    return view('not-found');  // Returns 200 OK — soft 404
});

After (✅):

php
Route::fallback(function () {
    return response()->view('errors.404', [], 404);
});

The same applies to catch-all routes used for SPAs:

Before (❌):

php
Route::get('/{any}', [SpaController::class, 'index'])->where('any', '.*');
// Controller returns view() with implicit 200

After (✅):

php
Route::get('/{any}', function () {
    // Frontend router decides; server always returns 404 for unrecognised paths
    return response()->view('spa', [], 404);
})->where('any', '.*');

Proper Fix (15 minutes)

Remove the fallback route entirely and rely on Laravel's native 404 handling, which always returns the correct status code. Customise the 404 page via app/Exceptions/Handler.php:

php
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

public function render($request, Throwable $exception)
{
    if ($exception instanceof NotFoundHttpException) {
        return response()->view('errors.404', [], 404);
    }

    return parent::render($request, $exception);
}

Or simply create resources/views/errors/404.blade.php: Laravel auto-renders it for all 404 responses without any handler changes.

For SPAs that must handle all paths client-side, configure your frontend router to return a distinct 404 state for unknown routes (e.g., a Vue { path: '/:pathMatch(.*)*', component: NotFound } entry), so both server and client agree on which URLs are valid.

References