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.

Add SnapAPI to your Laravel app today

Free tier: 200 screenshots/month. No credit card required.

Get Free API Key

Advanced Laravel Screenshot Patterns

Testing Your Screenshot Integration

Laravel's HTTP faking makes it easy to test your SnapAPI integration without making real API calls in the test suite. Fake the SnapAPI endpoint to return a test image, and assert that your service stores it correctly:

// tests/Feature/ScreenshotTest.php
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use App\Jobs\GenerateScreenshot;

it('stores screenshot from SnapAPI', function () {
    Http::fake([
        'api.snapapi.pics/*' => Http::response(
            file_get_contents(base_path('tests/fixtures/test-screenshot.webp')),
            200,
            ['Content-Type' => 'image/webp']
        ),
    ]);

    Storage::fake('local');

    GenerateScreenshot::dispatchSync(
        'https://example.com',
        'screenshots/test.webp'
    );

    Storage::disk('local')->assertExists('screenshots/test.webp');
    Http::assertSentCount(1);
});

Caching Screenshots with Redis

For pages that are screenshotted frequently by multiple users, cache the result in Redis using Laravel's Cache facade. A one-hour cache for dashboard screenshots reduces your SnapAPI usage by an order of magnitude for popular pages while keeping the captures reasonably fresh:

public function getDashboardScreenshot(string $userId): string
{
    $cacheKey = 'screenshot:dashboard:' . $userId;

    return Cache::remember($cacheKey, 3600, function () use ($userId) {
        $url = $this->generateAuthenticatedUrl($userId);
        $response = $this->snap->screenshot($url, ['wait_for' => '.dashboard-ready']);

        if ($response->failed()) {
            throw new \RuntimeException('SnapAPI failed: ' . $response->status());
        }

        $path = 'screenshots/dashboard-' . $userId . '.webp';
        Storage::put($path, $response->body());
        return Storage::url($path);
    });
}

Livewire Component with Screenshot Preview

Build a Livewire component that allows users to preview any URL as a screenshot without leaving the admin panel. The component triggers a queued job, polls for completion, and displays the result inline. This pattern is useful for content moderation tools, link preview generators, and URL verification workflows inside Laravel admin panels.

Rate Limiting and Quota Management

If multiple users in your application can trigger screenshots, implement rate limiting at the application layer to protect your SnapAPI quota. Use Laravel's built-in rate limiter to cap screenshot requests per user per hour, with a higher limit for paid users and a lower limit for free tier users. This prevents a single heavy user from exhausting your monthly SnapAPI quota and ensures equitable access across your user base.

// AppServiceProvider.php
RateLimiter::for('screenshots', function (Request $request) {
    $limit = $request->user()->isPaid() ? 50 : 5;
    return Limit::perHour($limit)->by($request->user()->id);
});

SnapAPI's own rate limits are generous — 50 requests per second — so application-layer rate limiting is primarily about quota management, not about hitting SnapAPI's infrastructure limits. The free tier's 200 screenshots per month is per API key, so a multi-tenant application should use a paid plan to ensure sufficient quota for all users. Get started at snapapi.pics — the free key is ready in under a minute.

Why Teams Choose SnapAPI

SnapAPI is production-hardened screenshot infrastructure that teams use instead of managing their own Playwright or Puppeteer servers. One REST endpoint covers screenshot in PNG, JPEG, and WebP, full-page capture, PDF export, OG image generation, web scraping with JS rendering, and structured data extraction. The free tier is 200 screenshots per month with no credit card required. Paid plans start at $19 per month for 5,000 screenshots. SDKs in JavaScript, Python, Go, PHP, Swift, and Kotlin are available on GitHub. Get your API key at snapapi.pics.

Integration in Under Five Minutes

SnapAPI requires no SDK installation, no configuration files, and no infrastructure setup. Sign up at snapapi.pics, verify your email, and copy your API key. Pass it as the access_key query parameter on any request to the screenshot, scrape, or extract endpoints. The REST API is stateless — no sessions, no OAuth flows, no webhook registration required for basic usage. Your first screenshot can be live in minutes, not days.

For teams evaluating screenshot APIs, SnapAPI's free tier (200 screenshots per month, no credit card required) is genuinely useful for development and testing. Unlike competitors that restrict free tier captures to low resolution or watermarked images, SnapAPI's free tier is full-featured: same resolution, same formats, same wait_for support, same full-page mode as paid tiers. The only limit is monthly volume. Upgrade when your usage grows — no migration required, same API key, same endpoints, higher limits.

Support is available via email and the documentation at snapapi.pics/docs covers all parameters, error codes, rate limits, and SDK usage with examples in JavaScript, Python, Go, PHP, Swift, and Kotlin. If you build something interesting with SnapAPI, the team is always happy to hear about your use case and can often provide custom plan pricing for unusual volume profiles.

SnapAPI works with every Laravel version from 8 onward, and is fully compatible with Laravel Octane, Vapor, Forge, and Envoyer deployments. The HTTP Client integration requires no additional packages beyond what ships with a standard Laravel installation. Your team can be making real API calls within minutes of creating an account at snapapi.pics.