spatie/browsershot
Convert web pages or raw HTML to images and PDFs in PHP using Puppeteer-driven headless Chrome. Capture screenshots, generate PDFs, fetch rendered body HTML, and inspect triggered network requests—ideal for reports, previews, and testing.
## Getting Started
### Minimal Steps
1. **Installation**:
```bash
composer require spatie/browsershot
npm install puppeteer # or globally with `--global`
Ensure Node.js 22.0+ and Puppeteer are installed (see requirements).
First Use Case: Capture a URL as an image:
use Spatie\Browsershot\Browsershot;
Browsershot::url('https://example.com')->save('screenshot.png');
Capture a URL as a PDF:
Browsershot::url('https://example.com')->save('document.pdf');
Where to Look First:
Browsershot facade methods (e.g., url(), html(), htmlFromFilePath()).evaluateOnNewDocument for injecting scripts before page load.Dynamic Content Capture:
Use bodyHtml() to fetch rendered HTML (post-JS execution):
$html = Browsershot::url('https://example.com')->bodyHtml();
Form Interaction: Simulate user actions before capture:
Browsershot::url('https://example.com/login')
->type('#email', 'user@example.com')
->type('#password', 'password123')
->click('#submit')
->save('login_success.png');
PDF Generation with Custom Styling: Emulate print media for cleaner PDFs:
Browsershot::url('https://example.com/report')
->emulateMedia('print')
->save('report.pdf');
Local HTML Processing: Render HTML from a file or string:
// From file
Browsershot::htmlFromFilePath('/path/to/template.html')
->setContentUrl('https://example.com') // Resolve relative assets
->save('template.png');
// From string
Browsershot::html('<h1>Hello</h1>')->save('string_output.pdf');
New: Script Injection with evaluateOnNewDocument
Execute scripts before the page loads (e.g., modify global state, inject CSS):
Browsershot::url('https://example.com')
->evaluateOnNewDocument('document.title = "Custom Title"')
->save('modified_page.png');
// Multiple scripts
Browsershot::url('https://example.com')
->evaluateOnNewDocument([
'document.body.style.backgroundColor = "lightblue"',
'window.customVar = "injected"',
])
->save('styled_page.pdf');
Queue Jobs for Async Processing: Use Laravel queues to avoid blocking requests:
Browsershot::url('https://example.com')->save('async.png')->onQueue('browsershot');
Store Outputs in Storage: Save files to Laravel’s filesystem:
use Illuminate\Support\Facades\Storage;
Browsershot::url('https://example.com')->save(Storage::path('screenshots/example.png'));
Debugging with Redirects: Log redirect history to diagnose issues:
$redirects = Browsershot::url('https://example.com')->redirectHistory();
foreach ($redirects as $redirect) {
logger()->info('Redirect:', ['url' => $redirect['url'], 'status' => $redirect['status']]);
}
Custom Headers for APIs: Authenticate or modify requests:
Browsershot::url('https://api.example.com/protected')
->setExtraHttpHeaders(['Authorization' => 'Bearer token123'])
->save('api_screenshot.png');
Combine evaluateOnNewDocument with Other Features:
Use it alongside delay() or emulateMedia() for complex workflows:
Browsershot::url('https://example.com/dashboard')
->evaluateOnNewDocument('localStorage.setItem("theme", "dark")')
->emulateMedia('print')
->delay(1500)
->save('dashboard_print.pdf');
Missing Dependencies:
PuppeteerException or blank outputs.libx11-xcb1 on Linux) are installed. For Forge servers, follow the custom setup guide.Resource Leaks:
Browsershot::html('<div>...</div>')->disableCaptureURLs();
Stale or Incorrect Outputs:
redirectHistory() for unexpected redirects.emulateMedia() settings (e.g., print vs. screen).Browsershot::url('https://example.com')->delay(2000)->save('page.png');
evaluateOnNewDocument, ensure scripts run before the page loads. Test with console.log in scripts to verify execution order.Font Rendering Issues:
Browsershot::url('https://example.com')
->addChromiumArguments(['font-render-hinting' => 'none']);
POST Requests:
application/x-www-form-urlencoded is supported.evaluateOnNewDocument Limitations:
window or document until after page creation).evaluate() for post-load modifications:
Browsershot::url('https://example.com')
->evaluateOnNewDocument('window.__INJECTED__ = true')
->evaluate('document.body.style.color = "red"')
->save('modified.png');
Log Puppeteer Output: Enable verbose logging via Chromium arguments:
Browsershot::url('https://example.com')
->addChromiumArguments(['log-level' => 'debug']);
Inspect Triggered Requests: Debug API calls or resource loading:
$requests = Browsershot::url('https://example.com')->triggeredRequests();
dd($requests); // Inspect URLs, statuses, and headers.
Test evaluateOnNewDocument Scripts:
Use console.log to verify script execution:
Browsershot::url('https://example.com')
->evaluateOnNewDocument('console.log("Script ran!");')
->save('debug.png');
Check Puppeteer logs for output.
Test Locally First:
Use newHeadless() for debugging (slower but easier to attach Chrome DevTools):
Browsershot::url('https://example.com')->newHeadless()->save('debug.png');
Custom Puppeteer Scripts: Override the default script path:
Browsershot::html('...')->setBinPath('/path/to/custom-script.js');
Environment-Specific Config:
Use Laravel’s config to centralize settings (e.g., config/browsershot.php):
// In a service provider
Browsershot::macro('configure', function () {
$this->setChromePath(config('browsershot.chrome_path'));
$this->addChromiumArguments(config('browsershot.chromium_args'));
});
Event Listeners: Extend functionality by tapping into Puppete
How can I help you explore Laravel packages today?