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.
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.
<?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);
// 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']);
}
$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.
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.
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.
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.
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.
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.
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.
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.
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.
Grab a key, paste the snippet, done. 200 free screenshots per month, no credit card.