Menu
phptutorialscreenshots

How to Take Website Screenshots in PHP — Complete Guide

SnapSharp Team·March 25, 2026·7 min read

How to Take Website Screenshots in PHP

PHP remains one of the most-used server-side languages, powering WordPress, Laravel, and Symfony. This guide covers three ways to capture website screenshots from PHP code.

Method 1: Browsershot (Puppeteer wrapper)

Browsershot is a popular Laravel/PHP package by Spatie that wraps Puppeteer. It requires Node.js and Puppeteer installed on the server.

Installation

composer require spatie/browsershot
npm install puppeteer

You also need Chrome or Chromium installed on the server.

Basic Screenshot

use Spatie\Browsershot\Browsershot;

Browsershot::url('https://example.com')
    ->windowSize(1280, 720)
    ->save('screenshot.png');

Full-Page Screenshot

Browsershot::url('https://example.com')
    ->fullPage()
    ->save('full-page.png');

Dark Mode

Browsershot::url('https://example.com')
    ->emulateMedia('screen')
    ->setOption('args', ['--force-dark-mode'])
    ->save('dark.png');

PDF Export

Browsershot::url('https://example.com')
    ->format('A4')
    ->savePdf('page.pdf');

Custom Viewport and Quality

Browsershot::url('https://example.com')
    ->windowSize(1440, 900)
    ->setScreenshotType('jpeg', 85)
    ->save('compressed.jpg');

Use with Laravel

// In a Laravel controller
public function capture(Request $request)
{
    $request->validate(['url' => 'required|url']);

    $path = storage_path('app/screenshots/' . Str::random(16) . '.png');

    Browsershot::url($request->input('url'))
        ->windowSize(1280, 720)
        ->waitUntilNetworkIdle()
        ->save($path);

    return response()->download($path);
}

Pros and Cons

Pros: Well-integrated with Laravel, fluent API, supports PDF, widely used in the PHP ecosystem.

Cons: Requires Node.js + Puppeteer + Chrome on the server, heavy resource usage (~250 MB RAM per capture), Chrome installation on shared hosting is often impossible, version conflicts between Node/Puppeteer/Chrome.


Method 2: SnapSharp API via cURL

The simplest approach — use PHP's built-in cURL to call the SnapSharp API. No additional dependencies beyond PHP itself.

Basic Screenshot

function screenshot(string $url, string $output, array $options = []): void
{
    $params = array_merge([
        'url' => $url,
        'width' => 1280,
        'height' => 720,
    ], $options);

    $apiUrl = 'https://api.snapsharp.dev/v1/screenshot?' . http_build_query($params);

    $ch = curl_init($apiUrl);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => [
            'Authorization: Bearer ' . getenv('SNAPSHARP_API_KEY'),
        ],
        CURLOPT_TIMEOUT => 30,
    ]);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($httpCode !== 200) {
        throw new RuntimeException("Screenshot failed: HTTP $httpCode");
    }

    file_put_contents($output, $response);
}

screenshot('https://example.com', 'screenshot.png');

Full-Page + Dark Mode

screenshot('https://example.com', 'dark-full.png', [
    'full_page' => 'true',
    'dark_mode' => 'true',
    'format' => 'webp',
]);

With Guzzle (Laravel / Symfony)

use GuzzleHttp\Client;

$client = new Client([
    'base_uri' => 'https://api.snapsharp.dev/v1/',
    'headers' => [
        'Authorization' => 'Bearer ' . config('services.snapsharp.key'),
    ],
]);

$response = $client->get('screenshot', [
    'query' => [
        'url' => 'https://example.com',
        'width' => 1280,
        'height' => 720,
        'full_page' => true,
    ],
]);

Storage::put('screenshots/example.png', $response->getBody()->getContents());

Error Handling

function screenshotWithRetry(string $url, string $output, int $maxRetries = 3): void
{
    for ($attempt = 0; $attempt < $maxRetries; $attempt++) {
        $ch = curl_init('https://api.snapsharp.dev/v1/screenshot?' . http_build_query([
            'url' => $url,
            'width' => 1280,
        ]));
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . getenv('SNAPSHARP_API_KEY'),
            ],
        ]);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode === 200) {
            file_put_contents($output, $response);
            return;
        }

        if ($httpCode === 429) {
            sleep(pow(2, $attempt) * 5);
            continue;
        }

        throw new RuntimeException("Screenshot failed: HTTP $httpCode");
    }

    throw new RuntimeException("Max retries exceeded");
}

Method 3: SnapSharp PHP SDK

The official PHP SDK provides a typed, object-oriented interface with built-in retry logic.

Installation

composer require snapsharp/snapsharp-php

Basic Screenshot

use SnapSharp\SnapSharp;

$snap = new SnapSharp(getenv('SNAPSHARP_API_KEY'));

$image = $snap->screenshot('https://example.com', [
    'width' => 1280,
    'height' => 720,
]);

file_put_contents('screenshot.png', $image);

Full-Page + Element Selector

$image = $snap->screenshot('https://example.com', [
    'full_page' => true,
    'selector' => '.main-content',
    'dark_mode' => true,
]);

PDF Export

$pdf = $snap->screenshot('https://example.com', [
    'format' => 'pdf',
    'pdf_format' => 'A4',
]);

file_put_contents('page.pdf', $pdf);

Batch Capture in Laravel Queue

// App\Jobs\CaptureScreenshot.php
use SnapSharp\SnapSharp;

class CaptureScreenshot implements ShouldQueue
{
    public function __construct(
        private string $url,
        private string $outputPath,
    ) {}

    public function handle(): void
    {
        $snap = new SnapSharp(config('services.snapsharp.key'));
        $image = $snap->screenshot($this->url, ['width' => 1280]);
        Storage::put($this->outputPath, $image);
    }
}

// Dispatch:
CaptureScreenshot::dispatch('https://example.com', 'screenshots/example.png');

WordPress Integration

// In a WordPress plugin or theme
function snapsharp_capture_thumbnail(string $url): string
{
    $api_key = get_option('snapsharp_api_key');
    $response = wp_remote_get(
        'https://api.snapsharp.dev/v1/screenshot?' . http_build_query([
            'url' => $url,
            'width' => 1200,
            'height' => 630,
        ]),
        ['headers' => ['Authorization' => 'Bearer ' . $api_key]]
    );

    if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
        return '';
    }

    $upload_dir = wp_upload_dir();
    $filename = 'screenshot-' . md5($url) . '.png';
    $filepath = $upload_dir['path'] . '/' . $filename;

    file_put_contents($filepath, wp_remote_retrieve_body($response));

    return $upload_dir['url'] . '/' . $filename;
}

Pros and Cons

Pros: No local browser needed, works on shared hosting, typed SDK with retry logic, Laravel/WordPress friendly.

Cons: Network latency (~2–4s), API costs at scale (100 free/month), requires internet access.


Comparison Table

FeatureBrowsershotcURL (raw API)SnapSharp PHP SDK
DependenciesNode.js + Puppeteer + ChromePHP cURL extensionComposer package
Shared hostingUsually impossibleWorks everywhereWorks everywhere
Full-pageBuilt-inAPI parameterSDK method
Dark modeChrome flagsAPI parameterSDK method
PDFBuilt-inAPI parameterSDK method
Ad blockingManualAPI parameterSDK method
RAM usage~250 MBMinimalMinimal
Laravel integrationNativeGuzzleSDK + Queue
WordPressRequires Node.jswp_remote_getcURL fallback
Best forLocal/VPS with Node.jsMinimal dependency projectsProduction PHP apps

Which Should You Choose?

  • Browsershot if you're on a VPS with Node.js already installed and want everything local.
  • Raw cURL if you want zero Composer dependencies and full control.
  • SnapSharp PHP SDK if you want a clean API, automatic retries, and don't want to install Chrome on your server.

For shared hosting (which rules out Browsershot entirely), the API approach is your only option — and it works beautifully.

Get a free SnapSharp API key →