nutsweb/laravel-prerender
Laravel middleware that serves prerendered HTML to search engine crawlers and social bots, improving SEO for JavaScript-heavy pages. Integrates with Prerender.io, with configurable crawler detection, tokens, and caching for fast bot-friendly responses.
Install the package and publish its config:
composer require nutsweb/laravel-prerender
php artisan vendor:publish --provider="JeroenNoten\LaravelPrerender\PrerenderServiceProvider"
On Laravel 5.5+ the service provider is usually auto-discovered. On older versions, register JeroenNoten\LaravelPrerender\PrerenderServiceProvider in config/app.php. Verify the actual middleware class under vendor/.../src/Middleware; it is typically JeroenNoten\LaravelPrerender\Middleware\Prerender.
Register the middleware globally so crawlers are intercepted before your SPA/auth/session stack runs:
// app/Http/Kernel.php (Laravel <= 10)
protected $middleware = [
\App\Http\Middleware\TrustProxies::class,
\JeroenNoten\LaravelPrerender\Middleware\Prerender::class,
// ...
];
// bootstrap/app.php (Laravel 11+)
->withMiddleware(function (Middleware $middleware) {
$middleware->append(\JeroenNoten\LaravelPrerender\Middleware\Prerender::class);
})
Configure it in .env:
PRERENDER_ENABLE=true
PRERENDER_URL=https://service.prerender.io
PRERENDER_TOKEN=your-prerender-io-token
For a self-hosted Prerender server, point at it instead and leave the token empty:
PRERENDER_URL=http://prerender:3000
PRERENDER_TOKEN=
First use case: a Vue/React/Inertia marketing site where Google can render JS but Facebook, LinkedIn, Slack, Discord, and Twitter cannot. Test immediately with curl:
curl -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" \
-I https://example.com/pricing
curl -A "facebookexternalhit/1.1" https://example.com/
Look first at config/prerender.php — especially prerender_crawler_user_agents, prerender_skip, and prerender_ignore — then at where you registered the middleware. If the response is still your normal SPA shell, the bot user-agent is not matching, the URL is being skipped, or the middleware is running too late.
Global middleware for public pages only. The simplest setup is global middleware plus a skip list. This ensures bots hit prerender before sessions, auth, and route model binding:
// config/prerender.php
'prerender_skip' => [
'admin',
'admin/*',
'api/*',
'login',
'logout',
'account/*',
'checkout/*',
],
Route-group middleware for tighter control. If you do not want a global intercept, register an alias and apply only to public, indexable routes:
// app/Http/Kernel.php
protected $routeMiddleware = [
'prerender' => \JeroenNoten\LaravelPrerender\Middleware\Prerender::class,
];
Route::middleware('prerender')->group(function () {
Route::get('/', HomeController::class);
Route::get('/pricing', PricingController::class);
});
Cloud vs self-hosted. Use https://service.prerender.io plus a token for zero infrastructure. For cost control or privacy, run the open-source Prerender server in Docker and set PRERENDER_URL to its internal address. Self-hosted is usually the better day-to-day choice for teams already running containers, and it avoids sending URLs to a third party.
Keep asset requests out of the prerender pipeline. Configure ignored extensions so bot requests for JS/CSS/images do not get proxied:
'prerender_ignore' => [
'js', 'css', 'png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'ico',
'woff', 'woff2', 'ttf', 'eot', 'pdf', 'xml', 'txt', 'json',
],
Expand the crawler list for social and chat bots. The default list covers major search engines, but social/chat previews are often the real reason to use this package. Add agents such as facebookexternalhit, twitterbot, linkedinbot, slackbot, discordbot, telegrambot, whatsapp, pinterest, redditbot, embedly, and applebot if they are not already present.
Use URL-based locales. A prerender service fetches the URL as an anonymous crawler. If your locale comes from a session or cookie, bots will get the default language. Put locale in the path (/en/..., /de/...) or query string so the prerendered page matches the indexed URL.
Test with real user agents in integration, not only unit tests. Because the package uses its own HTTP client, Laravel's Http::fake() will not intercept it. Feature tests can assert skip/matching behavior with withHeader('User-Agent', ...), but actual prerender calls are best verified in staging with curl or a local Prerender container.
Pair with caching. The middleware proxies every matching bot request unless the prerender service caches. Prerender.io caches cloud responses; self-hosted Prerender has its own cache TTL. After deploys, purge or recache important URLs so bots do not receive stale HTML.
This is a 2018-era package. Its last release predates modern Laravel versions. Check composer show and dependency constraints before installing on Laravel 9/10/11; older Guzzle constraints can conflict with current Laravel. If installation fails, fork the middleware rather than forcing dependency downgrades.
Verify the Composer package name. The upstream repository is jeroennoten/Laravel-Prerender; the package name in your environment may be a fork or mirror. Confirm the vendor/name on Packagist and that the namespace matches what is in vendor/.
Middleware order matters. Put it after TrustProxies so the scheme, host, and client IP are correct, but before StartSession and auth middleware. If it runs too late, bots create sessions, trigger auth redirects, or get URLs with the wrong scheme/host.
User-agent matching is spoofable. Anyone can send Googlebot and force your app to call the prerender service, which can cost money or amplify load. Rate-limit prerender requests at the edge, skip private routes, and consider bot verification or CDN bot management if abuse is a concern.
Do not send sensitive URLs to a third party. The full URL, including query strings, is forwarded to the prerender service. Skip account, checkout, password-reset, signed-URL, and API routes. Prefer self-hosted Prerender if URLs may contain sensitive data.
Failure handling is limited. If the prerender service is slow or down, bots may receive errors or time out. Check whether the middleware falls through to your app on exceptions; if not, wrap it or fork it to catch transport failures and call $next($request).
Headers and cookies may not survive. The middleware returns the prerendered response, so Laravel middleware that normally adds security headers, CORS, analytics, or cookies may not run. Set critical headers at the web server/CDN level, and verify Content-Type, cache headers, and status codes with curl -I.
Prerender skip patterns need testing. Confirm whether your version matches paths, full URLs, or wildcard patterns, and whether query strings affect matching. Test /admin, /admin/users, and /admin/users?page=2 explicitly.
Local development usually fails. A cloud prerender service cannot reach http://localhost. Use a tunnel, or run a local Prerender container and point PRERENDER_URL at it. If the middleware is enabled locally without a reachable service, you will see connection errors for bot user agents.
Remember config caching. After changing .env or config/prerender.php, run php artisan config:clear or php artisan config:cache. A cached config is a common reason changes appear to have no effect.
Google is not the main beneficiary anymore. Modern Googlebot executes JavaScript reasonably well; social preview bots and some secondary crawlers do not. Use this package primarily to fix Open Graph/Twitter card previews and to serve static HTML to crawlers that cannot render your SPA.
How can I help you explore Laravel packages today?