April 2026 · 7 min read · Blog
Screenshot API for Laravel — Jobs, Queues, and Blade Integration
A complete guide to integrating SnapAPI into Laravel applications: HTTP Client usage, queued screenshot jobs, Blade component patterns, and Horizon monitoring.
Why Laravel Apps Need Screenshot Automation
Laravel powers a significant share of the world's web applications — invoicing tools, project management platforms, content management systems, analytics dashboards, and e-commerce backends. All of these generate a common need: reliable, server-side screenshot generation for PDF exports, email previews, social sharing images, and visual audit logs. SnapAPI integrates with Laravel's HTTP Client and Job system to make screenshot automation a first-class feature of your application.
Installation and Basic HTTP Client Usage
Add your SnapAPI key to .env:
SNAP_KEY=your_api_key_here
SNAP_BASE_URL=https://api.snapapi.pics/v1
Configure a service in config/services.php:
'snapapi' => [
'key' => env('SNAP_KEY'),
'base_url' => env('SNAP_BASE_URL', 'https://api.snapapi.pics/v1'),
],
Make your first screenshot using Laravel's HTTP Client:
use Illuminate\Support\Facades\Http;
$response = Http::get(config('services.snapapi.base_url') . '/screenshot', [
'url' => 'https://your-site.com/invoice/1234',
'format' => 'png',
'width' => '1200',
'wait_for' => '.invoice-loaded',
'access_key' => config('services.snapapi.key'),
]);
if ($response->successful()) {
Storage::put('screenshots/invoice-1234.png', $response->body());
}
Building a SnapAPI Service Class
Wrap the HTTP Client in a service class for reuse and testability:
<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
use Illuminate\Http\Client\Response;
class SnapApiService
{
private string $key;
private string $baseUrl;
public function __construct()
{
$this->key = config('services.snapapi.key');
$this->baseUrl = config('services.snapapi.base_url');
}
public function screenshot(string $url, array $options = []): Response
{
return Http::timeout(30)->get($this->baseUrl . '/screenshot', array_merge([
'url' => $url,
'format' => 'webp',
'width' => '1280',
'access_key' => $this->key,
], $options));
}
public function ogImage(string $url): Response
{
return $this->screenshot($url, ['width' => '1200', 'height' => '630', 'format' => 'webp']);
}
public function fullPage(string $url): Response
{
return $this->screenshot($url, ['full_page' => 'true']);
}
}
Register it in AppServiceProvider and inject it anywhere in your Laravel app via the container.
Queued Screenshot Jobs with Laravel Horizon
Screenshot generation takes 1-4 seconds per capture. For bulk operations — generating invoice screenshots for all customers at month end, refreshing OG images for a product catalog — you need to queue these jobs and process them asynchronously. Laravel's job queue and Horizon monitoring make this straightforward:
<?php
namespace App\Jobs;
use App\Services\SnapApiService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Support\Facades\Storage;
class GenerateScreenshot implements ShouldQueue
{
use Dispatchable, Queueable;
public int $tries = 3;
public int $timeout = 60;
public function __construct(
private string $url,
private string $storagePath,
private array $options = []
) {}
public function handle(SnapApiService $snap): void
{
$response = $snap->screenshot($this->url, $this->options);
if ($response->failed()) {
$this->fail('SnapAPI returned ' . $response->status());
return;
}
Storage::put($this->storagePath, $response->body());
}
}
Dispatch it anywhere:
GenerateScreenshot::dispatch(
'https://your-app.com/reports/' . $reportId,
'screenshots/reports/' . $reportId . '.webp',
['wait_for' => '.report-ready', 'full_page' => 'true']
)->onQueue('screenshots');
Blade Component for Screenshot Previews
Build a reusable Blade component that displays a screenshot preview with a fallback skeleton loader:
{{-- resources/views/components/screenshot-preview.blade.php --}}
@props(['url', 'alt' => 'Page screenshot', 'width' => 640, 'height' => 400])
<div class="screenshot-preview" style="width:{{ $width }}px;height:{{ $height }}px">
@php
$key = 'snap_' . md5($url);
$cached = Cache::get($key);
@endphp
@if($cached)
<img src="{{ $cached }}" alt="{{ $alt }}" style="width:100%;height:100%;object-fit:cover">
@else
<div class="skeleton" style="width:100%;height:100%;background:#e2e8f0;border-radius:8px"
data-snap-url="{{ $url }}"></div>
@endif
</div>
A lightweight Alpine.js snippet can load uncached previews on demand by calling a Laravel route that proxies to SnapAPI, caches the result in Redis, and returns the image. This pattern gives users immediate visual feedback while keeping your SnapAPI usage efficient through Laravel's cache layer.
Scheduled Screenshot Refresh with Laravel Scheduler
Use Laravel's built-in scheduler to refresh screenshots for key pages on a regular cadence:
// app/Console/Kernel.php
protected function schedule(Schedule $schedule): void
{
$schedule->call(function () {
$pages = Page::where('needs_screenshot_refresh', true)->limit(50)->get();
foreach ($pages as $page) {
GenerateScreenshot::dispatch($page->url, 'screenshots/' . $page->slug . '.webp')
->onQueue('screenshots');
$page->update(['needs_screenshot_refresh' => false]);
}
})->hourly()->name('screenshot-refresh');
}
Add SnapAPI's free tier (200 screenshots/month) to your staging environment and the $19/month plan to production. Get your API key at snapapi.pics in under a minute — sign up with your work email, verify, and your key is ready immediately.