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/sdkRequires 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)
| Parameter | Type | Default | Description |
|---|---|---|---|
apiKey | string | — (required) | Your API key |
baseUrl | string | https://screenshotapi.to | API base URL (proxies, tests) |
timeout | float | 60 | Request timeout in seconds |
httpClient | GuzzleHttp\ClientInterface | internal Guzzle client | Custom 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.
| Option | Type | Default | Description |
|---|---|---|---|
url | string | Required unless html is set | URL to capture |
html | string | — | HTML document to render (switches to POST) |
width | int | 1440 | Viewport width in pixels (max 1920) |
height | int | 900 | Viewport height in pixels (max 10000) |
fullPage | bool | false | Capture the full scrollable page |
type | string | png | png, jpeg, webp, or pdf |
quality | int | 100 | JPEG/WebP quality, 1–100 |
colorScheme | string | Page default | light or dark |
waitUntil | string | networkidle2 | load, domcontentloaded, networkidle0, networkidle2 |
waitForSelector | string | — | CSS selector to wait for |
delay | int | 0 | Extra wait after load (ms, max 30000) |
blockAds | bool | false | Block common ad networks |
removeCookieBanners | bool | false | Auto-remove cookie consent dialogs |
cssInject | string | — | CSS injected before capture |
jsInject | string | — | JavaScript evaluated before capture |
stealthMode | bool | false | Anti-bot-detection browser fingerprint |
devicePixelRatio | int | 1 | Retina/HiDPI scale (1, 2, or 3) |
timezone | string | Server default | IANA timezone, e.g. America/New_York |
locale | string | Server default | BCP 47 locale, e.g. en-US |
cacheTtl | int | 0 | Cache identical captures for N seconds |
preloadFonts | bool | false | Preload Google Fonts before capture |
removeElements | list<string> | — | CSS selectors to remove |
removePopups | bool | false | Remove common modals/overlays |
mockupDevice | string | — | browser, iphone, or macbook (PNG output) |
geoLocation | array | — | ['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";
}| Exception | When |
|---|---|
AuthenticationException | 401 — API key missing or malformed |
InsufficientCreditsException | 402 — no credits remaining (exposes $balance) |
InvalidAPIKeyException | 403 — API key invalid or revoked |
ScreenshotFailedException | 500 — capture failed server-side |
APIException | Base 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
- Screenshot API reference — every parameter in detail
- Authentication — create and rotate API keys
- Credits — how billing works (200 free screenshots/month)
- Integrations — framework and platform guides