ScreenshotAPI

PHP

Official screenshotapi/sdk for PHP — capture screenshots, PDFs, and rendered HTML from plain PHP, Laravel, and Symfony.

The official screenshotapi/sdk package is a typed, Guzzle-powered client. It captures screenshots, PDFs, and rendered HTML and throws typed exceptions for API failures.

Package: screenshotapi/sdk on Packagist · Namespace: ScreenshotAPI\ · Source & examples: github.com/miketromba/screenshotapi-php · PHP 8.1+.

Installation

composer require screenshotapi/sdk

Requires PHP 8.1+ and Composer.

Authentication

Create an API key in the dashboard and expose it to your app as an environment variable. The SDK sends it in the x-api-key header.

export SCREENSHOTAPI_KEY=sk_live_your_key_here
<?php

require_once __DIR__ . '/vendor/autoload.php';

use ScreenshotAPI\Client;

$client = new Client(getenv('SCREENSHOTAPI_KEY'));

Keep API keys on the server. Never expose them in client-side code or commit them to source control.

Quick Start

Capture a URL and save it to disk

save() captures the screenshot, writes the file, and returns the response metadata.

<?php

use ScreenshotAPI\Client;
use ScreenshotAPI\ScreenshotOptions;

$client = new Client(getenv('SCREENSHOTAPI_KEY'));

$metadata = $client->save(
    new ScreenshotOptions(url: 'https://example.com'),
    __DIR__ . '/screenshot.png',
);

echo "Screenshot ID: {$metadata->screenshotId}\n";
echo "Credits remaining: {$metadata->creditsRemaining}\n";

Or work with the raw image bytes

screenshot() returns a Result with the image string plus metadata — ideal for streaming from a framework.

$result = $client->screenshot(new ScreenshotOptions(
    url: 'https://example.com',
    type: 'webp',
    quality: 85,
));

file_put_contents('example.webp', $result->image);
echo "{$result->contentType}\n";                 // "image/webp"
echo "{$result->metadata->durationMs}ms\n";

Methods

new Client(apiKey, baseUrl, timeout, httpClient)

ParameterTypeDefaultDescription
apiKeystring— (required)Your API key
baseUrlstringhttps://screenshotapi.toAPI base URL (proxies, tests)
timeoutfloat60Request timeout in seconds
httpClientGuzzleHttp\ClientInterfaceinternal Guzzle clientCustom Guzzle-compatible client
use GuzzleHttp\Client as HttpClient;
use ScreenshotAPI\Client;

$client = new Client(
    apiKey: getenv('SCREENSHOTAPI_KEY'),
    baseUrl: 'https://screenshotapi.to',
    timeout: 30.0,
    httpClient: new HttpClient(['timeout' => 30.0]),
);

$client->screenshot(ScreenshotOptions $options): Result

Result is a readonly object:

$result->image                       // string — raw image or PDF bytes
$result->contentType                 // "image/png", "image/webp", "application/pdf", …
$result->metadata->creditsRemaining  // int
$result->metadata->screenshotId      // string — include this when contacting support
$result->metadata->durationMs        // int

$client->save(ScreenshotOptions $options, string $path): Metadata

Captures, writes the bytes to $path, and returns the Metadata shown above.

Options

Build a ScreenshotOptions with named arguments. Every screenshot parameter is supported.

OptionTypeDefaultDescription
urlstringRequired unless html is setURL to capture
htmlstringHTML document to render (switches to POST)
widthint1440Viewport width in pixels (max 1920)
heightint900Viewport height in pixels (max 10000)
fullPageboolfalseCapture the full scrollable page
typestringpngpng, jpeg, webp, or pdf
qualityint100JPEG/WebP quality, 1–100
colorSchemestringPage defaultlight or dark
waitUntilstringnetworkidle2load, domcontentloaded, networkidle0, networkidle2
waitForSelectorstringCSS selector to wait for
delayint0Extra wait after load (ms, max 30000)
blockAdsboolfalseBlock common ad networks
removeCookieBannersboolfalseAuto-remove cookie consent dialogs
cssInjectstringCSS injected before capture
jsInjectstringJavaScript evaluated before capture
stealthModeboolfalseAnti-bot-detection browser fingerprint
devicePixelRatioint1Retina/HiDPI scale (1, 2, or 3)
timezonestringServer defaultIANA timezone, e.g. America/New_York
localestringServer defaultBCP 47 locale, e.g. en-US
cacheTtlint0Cache identical captures for N seconds
preloadFontsboolfalsePreload Google Fonts before capture
removeElementslist<string>CSS selectors to remove
removePopupsboolfalseRemove common modals/overlays
mockupDevicestringbrowser, iphone, or macbook (PNG output)
geoLocationarray['latitude' => …, 'longitude' => …, 'accuracy' => …]
$result = $client->screenshot(new ScreenshotOptions(
    url: 'https://example.com/pricing',
    width: 1920,
    height: 1080,
    fullPage: true,
    type: 'webp',
    quality: 85,
    colorScheme: 'dark',
    waitUntil: 'networkidle0',
    waitForSelector: '#main',
    delay: 500,
    blockAds: true,
    removeCookieBanners: true,
    devicePixelRatio: 2,
    cacheTtl: 300,
    removeElements: ['.modal', '#promo'],
    geoLocation: ['latitude' => 40.7128, 'longitude' => -74.0060, 'accuracy' => 25],
));

Render HTML & generate PDFs

Pass html to render a raw string — the SDK automatically switches to POST /api/v1/screenshot. Combine with type: 'pdf' for documents.

$pdf = $client->screenshot(new ScreenshotOptions(
    html: '<main><h1>Invoice</h1></main>',
    type: 'pdf',
    width: 1200,
));

file_put_contents('invoice.pdf', $pdf->image);

Error Handling

The SDK throws typed exceptions. All extend APIException, so catch the specific ones first.

use ScreenshotAPI\ScreenshotOptions;
use ScreenshotAPI\Exceptions\APIException;
use ScreenshotAPI\Exceptions\AuthenticationException;
use ScreenshotAPI\Exceptions\InvalidAPIKeyException;
use ScreenshotAPI\Exceptions\InsufficientCreditsException;
use ScreenshotAPI\Exceptions\ScreenshotFailedException;

try {
    $result = $client->screenshot(new ScreenshotOptions(url: 'https://example.com'));
} catch (AuthenticationException $e) {
    // 401: API key is missing or malformed.
} catch (InvalidAPIKeyException $e) {
    // 403: API key is invalid or revoked.
} catch (InsufficientCreditsException $e) {
    echo "Out of credits (402). Balance: {$e->balance}\n";
} catch (ScreenshotFailedException $e) {
    echo "Capture failed server-side (500): {$e->getMessage()}\n";
} catch (APIException $e) {
    echo "Request failed ({$e->statusCode}): {$e->getMessage()}\n";
}
ExceptionWhen
AuthenticationException401 — API key missing or malformed
InsufficientCreditsException402 — no credits remaining (exposes $balance)
InvalidAPIKeyException403 — API key invalid or revoked
ScreenshotFailedException500 — capture failed server-side
APIExceptionBase class (exposes $statusCode, $errorCode). Network failures use errorCode: "request_failed".

Framework Recipes

Laravel

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Http\Response;
use ScreenshotAPI\Client;
use ScreenshotAPI\ScreenshotOptions;
use ScreenshotAPI\Exceptions\APIException;

class ScreenshotController extends Controller
{
    public function show(Request $request): Response
    {
        $request->validate(['url' => 'required|url']);

        $client = new Client(config('services.screenshotapi.key'));

        try {
            $result = $client->screenshot(new ScreenshotOptions(
                url: $request->input('url'),
                type: 'webp',
                quality: 80,
            ));

            return response($result->image)
                ->header('Content-Type', $result->contentType)
                ->header('Cache-Control', 'public, max-age=3600');
        } catch (APIException $e) {
            return response()->json(['error' => $e->getMessage()], 502);
        }
    }
}

Symfony

<?php

namespace App\Controller;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use ScreenshotAPI\Client;
use ScreenshotAPI\ScreenshotOptions;

class ScreenshotController
{
    #[Route('/screenshot', methods: ['GET'])]
    public function show(Request $request): Response
    {
        $url = $request->query->get('url');
        if (!$url) {
            return new Response('url is required', 400);
        }

        $client = new Client($_ENV['SCREENSHOTAPI_KEY']);
        $result = $client->screenshot(new ScreenshotOptions(url: $url, type: 'webp'));

        return new Response($result->image, 200, [
            'Content-Type' => $result->contentType,
            'Cache-Control' => 'public, max-age=3600',
        ]);
    }
}

Runnable examples ship with the package: plain-php.php, laravel-controller.php, and symfony-controller.php.

Next steps

On this page