Plain HTTP, works with cURL and Guzzle

Screenshot API
for PHP

Capture any website as PNG, JPEG, WebP, or PDF with one GET request. No headless Chrome on the server, no wkhtmltoimage binary, no exec(). Runs on shared hosting.

200 free screenshots/month. No credit card required.

PHP quickstart: screenshot with cURL

The whole API is a GET request. Your key goes in the X-API-Key header, options go in query parameters, the image comes back as the response body.

screenshot.php (ext-curl, no dependencies)
<?php
$params = http_build_query([
    'url'       => 'https://example.com',
    'format'    => 'png',
    'width'     => 1280,
    'height'    => 800,
]);

$ch = curl_init('https://app.snap-render.com/v1/screenshot?' . $params);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 60,
    CURLOPT_HTTPHEADER     => ['X-API-Key: ' . getenv('SNAPRENDER_API_KEY')],
]);

$body   = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

if ($status !== 200) {
    $error = json_decode($body, true);
    throw new RuntimeException($error['error']['code'] . ': ' . $error['error']['message']);
}

file_put_contents('screenshot.png', $body);
Guzzle: full page, mobile device, dark mode, cached
// composer require guzzlehttp/guzzle
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;

$client = new Client([
    'base_uri' => 'https://app.snap-render.com',
    'headers'  => ['X-API-Key' => getenv('SNAPRENDER_API_KEY')],
    'timeout'  => 60,
]);

try {
    $response = $client->get('/v1/screenshot', ['query' => [
        'url'       => 'https://example.com',
        'format'    => 'jpeg',
        'quality'   => 85,
        'full_page' => 'true',
        'device'    => 'iphone_15_pro',
        'dark_mode' => 'true',
        'cache'     => 'true',
        'cache_ttl' => 3600,
    ]]);
    file_put_contents('mobile-dark.jpg', (string) $response->getBody());
    echo 'Cache: ' . $response->getHeaderLine('X-Cache') . "\n";
} catch (ClientException $e) {
    $error = json_decode((string) $e->getResponse()->getBody(), true);
    // 429 RATE_LIMITED: retry after a minute. 429 QUOTA_EXCEEDED: monthly limit reached.
    // 400 INVALID_URL / BLOCKED_URL: fix the input. 401: check the key.
    error_log($error['error']['code'] . ': ' . $error['error']['message']);
}
Webpage to PDF, streamed to the browser
$response = $client->get('/v1/screenshot', ['query' => [
    'url'       => 'https://example.com/invoice/123',
    'format'    => 'pdf',
    'full_page' => 'true',
    'width'     => 1024,
]]);

header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="invoice-123.pdf"');
echo $response->getBody();

Ads and cookie banners are blocked by default. The PDF is a rendered page image, not a print-stylesheet layout. Full parameter reference in the docs.

Take a screenshot in PHP without headless Chrome

The traditional PHP answers are wkhtmltoimage, a Chrome binary driven through exec(), or a Node sidecar running Puppeteer that PHP shells out to. All three need a binary you can install and keep patched, a font stack, and permission to spawn processes. Shared hosting and managed platforms disable exactly that. wkhtmltoimage is also unmaintained and renders with a QtWebKit engine that predates most of modern CSS.

With a screenshot API the rendering happens in current Chrome on our side. PHP makes one HTTP request with the curl extension it already has and receives the finished image. Cookie banners and ads are removed, lazy-loaded content is handled for full-page captures, and there is no browser process to leak memory inside php-fpm.

Using Laravel? The Laravel guide covers the Http facade, a queued job, and storing captures on a disk. WordPress plugin authors should read screenshots in WordPress with wp_remote_get.

Works on shared hosting, Laravel Vapor, and containers

Because the integration is a GET request, it runs anywhere PHP can open an outbound HTTPS connection: cPanel hosts, Laravel Forge and Vapor, Platform.sh, Docker images built from php:fpm-alpine, and WordPress installs on managed platforms that block exec(). Your image stays small and your deploy stays boring.

SnapRender API wkhtmltoimage / Chrome via exec()
Server requirements ext-curl only Binary, fonts, exec() permission
Shared hosting Yes Usually blocked
Modern CSS and JS rendering Current Chrome wkhtmltoimage: QtWebKit from 2012
Cookie banners and ads Blocked by default Custom code per site
Caching cache=true, hits are free Build it yourself
Browser updates Handled for you Yours to patch

Want to see the output first? Try the free website screenshot tool. It uses the same rendering engine as the API.

PHP screenshot API FAQ

How do I take a screenshot of a website in PHP?+

Send one GET request to the /v1/screenshot endpoint with the target in the url parameter and your key in the X-API-Key header, using curl_exec or Guzzle. The response body is the finished PNG, which you write to disk or stream to the browser. Nothing runs on your server except the HTTP call.

Does this work on shared hosting where I cannot install Chrome?+

Yes. The only requirement is the curl extension, which every mainstream PHP host enables. There is no binary to install, no exec() call, and no Composer package to compile, so it runs on shared hosting, managed WordPress, and locked-down containers.

Is there a Composer package for SnapRender?+

Not yet. The API is a plain HTTP endpoint, so the examples on this page use cURL and Guzzle directly and work with any PHP HTTP client. A Composer package is planned; the request format will not change when it ships.

Can I get a PDF of a webpage in PHP?+

Yes. Pass format=pdf and the response is a PDF document of the rendered page. It is a page render rather than a print stylesheet layout, so use full_page=true for long pages. Combine it with width and dark_mode as needed.

Is there a free tier for the PHP screenshot API?+

Yes. The free plan includes 200 screenshots per month with every feature: all formats including PDF, full-page capture, device emulation, dark mode, and caching. No credit card is required to sign up.

Not writing PHP today?

The same API has quickstarts for other languages.

Related guides: Screenshots in Laravel, Screenshots in WordPress, and serverless runtimes.

Or skip the setup entirely

Everything in this guide is one GET request with SnapRender. No browser to babysit, no timeouts to tune.

200 screenshots a month free. First render in under a minute.

One curl_exec between you and the screenshot

Grab a key, paste the snippet, done. 200 free screenshots per month, no credit card.