spatie/browsershot
Convert web pages or HTML to images and PDFs using headless Chrome via Puppeteer. Capture screenshots, generate PDFs, render JS, extract body HTML, and inspect network requests. Simple fluent API for URLs, raw HTML, or local HTML files.
Installation:
composer require spatie/browsershot
npm install puppeteer
Ensure puppeteer is installed globally or locally in your project.
Basic Usage:
use Spatie\Browsershot\Browsershot;
// Save URL as image
Browsershot::url('https://example.com')->save('screenshot.png');
// Save URL as PDF
Browsershot::url('https://example.com')->save('document.pdf');
// Use HTML string
Browsershot::html('<h1>Hello</h1>')->save('html_output.pdf');
First Use Case: Generate a PDF of a dynamic dashboard for email reports:
$dashboardUrl = route('admin.dashboard');
Browsershot::url($dashboardUrl)
->setOption('format', 'A4')
->setOption('margin', '1cm')
->save(storage_path("app/reports/dashboard_{$date}.pdf"));
Browsershot class: Core class with chainable methods for configuration.evaluate(), waitForSelector()).Browsershot::url('https://app.example.com/dashboard')
->waitForSelector('#dashboard-data') // Wait for JS to populate
->setOption('waitUntil', 'networkidle0')
->save('dashboard.png');
Browsershot::html($invoiceHtml)
->setOption('printBackground', true)
->setOption('format', 'Letter')
->setOption('margin', '0.5in')
->setOption('landscape', true)
->save(storage_path("invoices/{$invoiceId}.pdf"));
Browsershot::url('https://example.com')
->newHeadless() // Use Chrome's new headless mode
->setNodeBinaryPath('/usr/local/bin/node') // Custom Node path
->setOption('args', ['--no-sandbox', '--disable-setuid-sandbox'])
->save('output.pdf');
Browsershot::url('https://example.com/login')
->evaluate('document.querySelector("#email").value = "user@example.com"')
->evaluate('document.querySelector("#password").value = "password123"')
->click('#submit-button')
->waitForNavigation()
->save('login_success.png');
$urls = ['https://example.com/page1', 'https://example.com/page2'];
foreach ($urls as $url) {
$filename = str_replace(['https://', '/'], ['', '_'], $url) . '.png';
Browsershot::url($url)->save(public_path("thumbnails/{$filename}"));
}
$html = Browsershot::url('https://example.com')->bodyHtml();
$requests = Browsershot::url('https://example.com')->triggeredRequests();
Browsershot::dispatch($url, $path)->delay(now()->addMinutes(5));
$path = storage_path("exports/{$filename}.pdf");
Browsershot::url($url)->save($path);
Browsershot in unit tests:
$this->partialMock(Browsershot::class, 'url')->shouldReceive('save');
Puppeteer Dependencies:
puppeteer or Chrome binary.npm install puppeteer and ensure Chrome is installed.Failed to launch chrome!.Timeouts:
waitUntil or timeout:
->setOption('waitUntil', 'domcontentloaded') // Faster but less reliable
->setOption('timeout', 30000) // 30 seconds
Localhost/Dev Server:
Browsershot blocking local URLs (e.g., Vite/HMR).->allowInsecureProtocol() or configure trustedProtocols:
->setOption('trustedProtocols', ['http:', 'https:', 'file:'])
Memory Limits:
chrome-headless-shell (legacy mode) or limit resources:
->setOption('args', ['--single-process', '--disable-gpu'])
PDF Generation Quirks:
@page rules or Puppeteer’s pdf options:
->setOption('printBackground', true)
->setOption('margin', { top: '1cm', right: '1cm', bottom: '1cm', left: '1cm' })
Sandboxing:
--no-sandbox errors in Docker/Linux.setOption('args') or configure Docker to allow sandboxing.->setOption('logLevel', 'debug')
bodyHtml() to debug rendered output:
$html = Browsershot::url($url)->bodyHtml();
file_put_contents('debug.html', $html);
->setOption('devtools', true) // Opens DevTools (for local testing)
Custom Puppeteer Scripts:
evaluate() or evaluateOnNewDocument() (v5.4.0+):
->evaluateOnNewDocument('document.body.style.fontSize = "12pt"')
Event Listeners:
request):
Browsershot::url($url)
->on('request', function ($request) {
logger()->debug($request->url());
})
->save('output.pdf');
Service Provider:
Browsershot instance for app-wide configuration:
$this->app->singleton(Browsershot::class, function () {
return new Browsershot(
new Puppeteer([
'args' => ['--disable-setuid-sandbox'],
'timeout' => 60000,
])
);
});
Fallbacks:
try {
Browsershot::url($url)->save($path);
} catch (\Exception $e) {
Log::error("Browsershot failed: {$e->getMessage()}");
// Fallback to static HTML or cached image
}
puppeteer isn’t in PATH:
->setNodeBinaryPath('/custom/node')
->setNpmBinaryPath('/custom/npm')
->setOption('env', ['API_TOKEN' => env('PUPPETEER
How can I help you explore Laravel packages today?