Laravel Screenshot API: Capture Screenshots and Generate PDFs in PHP
Laravel has 10+ million installations. And almost every Laravel app needs to do something that requires a screenshot or PDF at some point:
- Generate invoice PDFs for orders
- Create social preview images for shared links
- Screenshot user-generated content for moderation
- Generate certificates or badges
- Create email header images with dynamic data
Your options have been limited:
- Use
spatie/browsershot— which requires Chrome binary installed (pain on shared hosting) - Use
barryvdh/laravel-dompdf— which is fine for simple PDFs but limited on styling - Build it yourself with Puppeteer — overkill and adds infrastructure burden
There's a simpler way: a screenshot API.
The Laravel Problem: Screenshots Without Infrastructure
Laravel is excellent at building web applications, but it doesn't come with built-in screenshot or PDF generation from HTML. Here's why each common solution falls short:
Option 1: Browsershot (Requires Chrome)
<?php
use Spatie\Browsershot\Browsershot;
// First, you need Chrome installed on your server
// On shared hosting? Good luck with permissions.
// On serverless? 500MB+ layer just for Chrome.
Browsershot::url('https://example.com')
->screenshot()
->save($pathToImage);
Problems:
- Requires system-level Chrome installation
- Fails on shared hosting (no root access)
- Bloated on serverless
- Unmaintained since 2021
Option 2: DomPDF (Limited CSS)
<?php
use Barryvdh\DomPDF\Facade\Pdf;
$pdf = Pdf::loadView('invoice', ['data' => $data]);
return $pdf->download('invoice.pdf');
// Works fine for basic PDFs, but:
// - CSS Grid? No
// - Modern flexbox? Limited
// - SVG? Limited
// - Fonts? Complicated
Problems:
- Limited CSS support
- Rendering bugs with modern styling
- Not a real browser engine
Option 3: PageBolt API (Zero Dependencies)
<?php
use Illuminate\Support\Facades\Http;
$response = Http::post('https://api.pagebolt.dev/take_screenshot', [
'Authorization' => 'Bearer ' . env('PAGEBOLT_API_KEY'),
], [
'url' => 'https://example.com',
'width' => 1200,
'height' => 630
]);
$imageUrl = $response->json('imageUrl');
// Done. No Chrome. No infrastructure.
Benefits:
- Zero system dependencies
- Works on any hosting
- Modern Chromium rendering
- Scales instantly
Build a Reusable Laravel Service
Create a service class to wrap PageBolt API calls:
<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
class PageBoltService
{
protected $apiKey;
protected $baseUrl = 'https://api.pagebolt.dev';
public function __construct()
{
$this->apiKey = config('services.pagebolt.key');
}
/**
* Take a screenshot of a URL
*/
public function screenshot(string $url, array $options = []): ?string
{
$payload = array_merge(['url' => $url], $options);
$response = Http::withHeaders([
'Authorization' => "Bearer {$this->apiKey}",
'Content-Type' => 'application/json'
])->post("{$this->baseUrl}/take_screenshot", $payload);
if ($response->failed()) {
return null;
}
return $response->json('imageUrl');
}
/**
* Generate a PDF from a URL
*/
public function pdfFromUrl(string $url, array $options = []): ?string
{
$payload = array_merge(['url' => $url], $options);
$response = Http::withHeaders([
'Authorization' => "Bearer {$this->apiKey}",
'Content-Type' => 'application/json'
])->post("{$this->baseUrl}/generate_pdf", $payload);
if ($response->failed()) {
return null;
}
return $response->json('pdfUrl');
}
/**
* Generate a PDF from raw HTML
*/
public function pdfFromHtml(string $html, array $options = []): ?string
{
$payload = array_merge(['html' => $html], $options);
$response = Http::withHeaders([
'Authorization' => "Bearer {$this->apiKey}",
'Content-Type' => 'application/json'
])->post("{$this->baseUrl}/generate_pdf", $payload);
if ($response->failed()) {
return null;
}
return $response->json('pdfUrl');
}
/**
* Take a screenshot from raw HTML
*/
public function screenshotFromHtml(string $html, array $options = []): ?string
{
$payload = array_merge(['html' => $html], $options);
$response = Http::withHeaders([
'Authorization' => "Bearer {$this->apiKey}",
'Content-Type' => 'application/json'
])->post("{$this->baseUrl}/take_screenshot", $payload);
if ($response->failed()) {
return null;
}
return $response->json('imageUrl');
}
}
Real-World Laravel Examples
Example 1: Generate Invoice PDFs
<?php
namespace App\Http\Controllers;
use App\Models\Invoice;
use App\Services\PageBoltService;
class InvoiceController extends Controller
{
public function __construct(protected PageBoltService $pagebolt) {}
public function pdf(Invoice $invoice)
{
// Render the invoice view as HTML
$html = view('invoices.template', ['invoice' => $invoice])->render();
// Convert to PDF
$pdfUrl = $this->pagebolt->pdfFromHtml($html, [
'format' => 'A4',
'margin' => '10mm'
]);
if (!$pdfUrl) {
return response()->json(['error' => 'PDF generation failed'], 500);
}
// Download the PDF
return redirect($pdfUrl);
}
}
Example 2: Create Social Preview Images
<?php
namespace App\Http\Controllers;
use App\Models\BlogPost;
use App\Services\PageBoltService;
class BlogController extends Controller
{
public function __construct(protected PageBoltService $pagebolt) {}
public function generateOGImage(BlogPost $post)
{
$html = view('og-template', [
'title' => $post->title,
'author' => $post->author->name,
'date' => $post->created_at->format('M d, Y')
])->render();
$imageUrl = $this->pagebolt->screenshotFromHtml($html, [
'width' => 1200,
'height' => 630
]);
// Store the URL in your database or cache
$post->update(['og_image_url' => $imageUrl]);
return response()->json(['image_url' => $imageUrl]);
}
}
Example 3: Screenshot Content for Moderation
<?php
namespace App\Jobs;
use App\Models\UserContent;
use App\Services\PageBoltService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
class CaptureContentScreenshot implements ShouldQueue
{
use Queueable;
public function __construct(protected UserContent $content) {}
public function handle(PageBoltService $pagebolt)
{
// Capture a screenshot of user-generated content
$screenshot = $pagebolt->screenshot(
$this->content->url,
['width' => 1280, 'height' => 720]
);
if ($screenshot) {
$this->content->update(['screenshot_url' => $screenshot]);
}
}
}
Configuration Setup
In your .env:
PAGEBOLT_API_KEY=your_api_key_here
In config/services.php:
<?php
return [
'pagebolt' => [
'key' => env('PAGEBOLT_API_KEY'),
],
];
Register the service in AppServiceProvider:
<?php
namespace App\Providers;
use App\Services\PageBoltService;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(PageBoltService::class, function ($app) {
return new PageBoltService();
});
}
}
Why PageBolt for Laravel
| Aspect | Browsershot | DomPDF | PageBolt API |
|---|---|---|---|
| Setup | Install Chrome binary | Composer dependency | API key |
| Works on shared hosting | ❌ No | ✅ Yes | ✅ Yes |
| Works on serverless | ⚠️ Heavy layer | ✅ Yes | ✅ Yes |
| CSS support | ✅ Full modern CSS | ⚠️ Limited | ✅ Full modern CSS |
| SVG/fonts | ✅ Full support | ⚠️ Limited | ✅ Full support |
| Dependencies | Chrome binary | PHP-only | None (HTTP) |
| Maintenance | 🚨 Abandoned (2021) | ⚠️ Community | ✅ Active |
| Time to first PDF | Hours (setup) | Minutes | Minutes |
Getting Started
1. Get an API key (free tier: 100 requests/month)
# Visit pagebolt.dev, create account, copy API key
2. Create the service class (code above)
3. Use in your controllers
// Inject and use
public function __construct(PageBoltService $pagebolt)
{
$this->pagebolt = $pagebolt;
}
// Take a screenshot
$imageUrl = $this->pagebolt->screenshot('https://example.com');
// Generate a PDF
$pdfUrl = $this->pagebolt->pdfFromHtml($htmlString);
4. Deploy and scale
No Chrome binary to manage. No serverless bloat. Just HTTP requests.
Next Steps
- Try PageBolt free — 100 requests/month, no credit card. Perfect for testing.
- Copy the service class above — drop it into your Laravel app.
- Start with one use case — invoice PDFs, OG images, or screenshots. Pick one.
- Scale seamlessly — when you need more requests, just upgrade. No infrastructure changes.
Stop fighting Chrome binaries. Start generating PDFs and screenshots in Laravel.
PageBolt: Screenshots and PDFs for Laravel, without the headache. Get started free →
Top comments (0)