ScreenshotNeo

BlogHow-to

How to Call a Screenshot API from PHP

Capture a website from PHP, save or stream the image, and handle credentials, rendering options, errors, and output storage.

By the ScreenshotNeo team4 October 202611 min read

To call a screenshot API from PHP, send a server-side request with your API credentials and the page URL, receive the rendered image bytes, then save them to a file or stream them to the caller. A provider SDK can handle request construction and response details; PHP cURL or Guzzle can also call a documented REST endpoint directly. API options, authentication, output types, and limits vary by provider.

Choose an integration path

Start by deciding what the application needs: a file it controls, image bytes to return immediately, or a hosted URL for delivery. Also check the provider’s required PHP version and whether it accepts a URL, generated HTML, or both.

Path Good fit Check first
Provider SDK Typed options, provider-specific error handling, and less request boilerplate. Package name, PHP baseline, dependencies, and SDK support status.
Raw REST request Existing HTTP-client conventions or a small integration. Exact endpoint, HTTP method, authentication, payload, binary or JSON response, and limits.
Hosted rendering workflow Generated HTML, templates, or work that may exceed a synchronous request window. Whether the result is bytes or a hosted URL and how long the URL remains available.

Examples documented by vendors illustrate why these details are not interchangeable: ScreenshotOne’s SDK documents PHP 7.4 or later; ScreenshotAPI.to documents PHP 8.1 or later; HTML to Image documents PHP 8.3 or later. Check current package and API documentation before choosing because requirements can change. [ScreenshotOne package requirements; ScreenshotAPI.to PHP documentation; HTML to Image PHP documentation]

Prepare credentials and output handling

  1. Create or select an API account and obtain the credentials the chosen provider requires.
  2. Store secrets in environment variables or your deployment’s secret manager. Do not commit them, return them in HTML or JavaScript, or log full request URLs if credentials are query parameters.
  3. Choose a destination: private application storage, object storage, or a controlled HTTP response. Validate the capture result before writing it to a public path.
  4. Set application and HTTP-client timeouts to fit the provider’s render behavior. A screenshot request includes page loading and rendering, so it can take longer than a typical database query.

The ScreenshotAPI.to PHP documentation specifically advises keeping keys on the server and out of client-side code and source control. [ScreenshotAPI.to PHP documentation]

Use a PHP SDK

ScreenshotOne SDK: capture a URL and save the bytes

The documented flow installs the SDK, initializes a client with an access key and secret key, configures a URL and options, calls the capture method, then writes the returned image bytes. Put the credentials in the process environment before running the script.

composer require screenshotone/sdk:^1.0
<?php
declare(strict_types=1);

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

use ScreenshotOne\Sdk\Client;
use ScreenshotOne\Sdk\TakeOptions;

$accessKey = getenv('SCREENSHOTONE_ACCESS_KEY');
$secretKey = getenv('SCREENSHOTONE_SECRET_KEY');

if (!$accessKey || !$secretKey) {
    throw new RuntimeException('Screenshot credentials are not configured.');
}

$client = new Client($accessKey, $secretKey);
$options = TakeOptions::url('https://example.com')
    ->fullPage(true)
    ->delay(2);

$image = $client->take($options);
if (!is_string($image) || $image === '') {
    throw new RuntimeException('The screenshot response was empty.');
}

$written = file_put_contents(__DIR__ . '/example.png', $image, LOCK_EX);
if ($written === false) {
    throw new RuntimeException('Could not write the screenshot.');
}

The SDK also documents generating a capture URL with generateTakeUrl($options) when you need to construct a URL without making the capture request in that call. Follow its current documentation for supported option names and authentication details. [ScreenshotOne PHP SDK guide]

ScreenshotAPI.to SDK: save to a path or return bytes

The documented package uses PHP 8.1 or later, Composer, the ScreenshotAPI\ namespace, and an x-api-key header through its client. Its save method writes a capture to a path and returns metadata; its byte-returning screenshot method can be used when a framework response should stream the image.

composer require screenshotapi/sdk
<?php
declare(strict_types=1);

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

use ScreenshotAPI\Client;
use ScreenshotAPI\ScreenshotOptions;

$key = getenv('SCREENSHOTAPI_KEY');
if (!$key) {
    throw new RuntimeException('SCREENSHOTAPI_KEY is not configured.');
}

$client = new Client($key);
$options = new ScreenshotOptions(url: 'https://example.com');

$metadata = $client->save($options, __DIR__ . '/capture.png');
var_dump($metadata);

For streaming, use the SDK’s documented byte-returning method and return its bytes with the framework’s response object and the correct content type. Avoid assuming the provider returns the same metadata or exception classes as another SDK. [ScreenshotAPI.to PHP documentation]

Call a REST API directly from PHP

There is no universal screenshot API request shape. Before writing raw HTTP code, take the endpoint, method, authentication format, request parameters, response type, and error model from that provider’s current API reference. The following is a cURL template for an API that accepts a GET request and returns image bytes; replace the endpoint and parameter names with those documented by your provider.

<?php
declare(strict_types=1);

$endpoint = getenv('SCREENSHOT_ENDPOINT');
$apiKey = getenv('SCREENSHOT_API_KEY');
if (!$endpoint || !$apiKey) {
    throw new RuntimeException('Endpoint and API key must be configured.');
}

$query = http_build_query([
    'url' => 'https://example.com',
    // Add only options supported by the chosen provider.
]);
$ch = curl_init($endpoint . '?' . $query);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_CONNECTTIMEOUT => 10,
    CURLOPT_TIMEOUT => 90,
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = curl_exec($ch);
$status = (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$contentType = (string) curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
$error = curl_error($ch);
curl_close($ch);

if ($body === false) {
    throw new RuntimeException('Screenshot request failed: ' . $error);
}
if ($status < 200 || $status >= 300) {
    throw new RuntimeException('Screenshot API returned HTTP ' . $status);
}
if (!str_starts_with($contentType, 'image/')) {
    throw new RuntimeException('Expected image bytes; received ' . $contentType);
}
if ($body === '') {
    throw new RuntimeException('Screenshot API returned an empty body.');
}
if (file_put_contents(__DIR__ . '/capture.png', $body, LOCK_EX) === false) {
    throw new RuntimeException('Could not write screenshot file.');
}

This template deliberately does not claim that all providers use Bearer authentication or return image bytes on success. Some return JSON metadata or an image URL, and some use a key header or signed query parameters. Adapt the response handling to the actual API contract.

Capture a URL with ScreenshotNeo

ScreenshotNeo is a website screenshot API and MCP server for developers. It accepts one GET request with a URL and returns PNG, JPEG, WebP, or PDF output. See the ScreenshotNeo website and API documentation for request options and response details.

<?php
declare(strict_types=1);

$apiKey = getenv('SCREENSHOTNEO_API_KEY');
if (!$apiKey) {
    throw new RuntimeException('SCREENSHOTNEO_API_KEY is not configured.');
}

$url = 'https://stripe.com';
$query = http_build_query([
    'access_key' => $apiKey,
    'url' => $url,
]);
$ch = curl_init('https://api.screenshotneo.com/v1/shot?' . $query);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CONNECTTIMEOUT => 10,
    CURLOPT_TIMEOUT => 90,
]);
$bytes = curl_exec($ch);
$status = (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$error = curl_error($ch);
curl_close($ch);

if ($bytes === false) {
    throw new RuntimeException('ScreenshotNeo request failed: ' . $error);
}
if ($status < 200 || $status >= 300) {
    throw new RuntimeException('ScreenshotNeo returned HTTP ' . $status);
}
if ($bytes === '') {
    throw new RuntimeException('ScreenshotNeo returned an empty response.');
}
if (file_put_contents(__DIR__ . '/shot.webp', $bytes, LOCK_EX) === false) {
    throw new RuntimeException('Could not save shot.webp.');
}

Render HTML generated by your application

If the page is assembled in PHP, decide whether the provider accepts raw HTML directly or requires a reachable URL. Raw HTML can be useful for invoices or reports, but rendering often depends on external assets such as fonts, images, and stylesheets. A renderer may not be able to access private application routes without appropriate authentication or network access.

HTML to Image documents URL, generated HTML, and named-template inputs. Its PHP integration describes PNG and PDF results and a hosted URL that can be downloaded to local or object storage. It also documents synchronous and background rendering, recommending a webhook for captures expected to exceed the synchronous render budget. Follow its specific API contract rather than assuming those behaviors apply to other services. [HTML to Image PHP integration]

Choose rendering options deliberately

Use only options documented by the provider you select. Similar names may behave differently across services.

Need Option to look for Practical consideration
Capture below the fold Full-page mode Long pages take longer and can produce large images; verify maximum dimensions.
Wait for a dynamic component Selector wait, delay, or network-idle condition A fixed delay can waste time or still be too short. Prefer a documented selector wait when a specific element signals readiness.
Match user appearance Viewport, device pixel ratio, color scheme, locale, timezone, or geolocation These can affect layout, text, and page content. Keep them consistent if captures are compared or cached.
Capture a component CSS selector or element capture Ensure the selector is unique and visible after rendering.
Produce a report PDF format and paper/layout controls PDF pagination and image output are distinct response types; set the correct content type and extension.
Remove irrelevant content Custom CSS, hide selectors, or request blocking Check that hiding or blocking elements does not remove content needed by the page.

For example, ScreenshotAPI.to documents a default viewport of 1440×900, maximum width of 1920, maximum height of 10,000, and a maximum delay of 30,000 ms. These are provider-specific limits, not general browser or API limits. [ScreenshotAPI.to PHP documentation]

Save, stream, or serve the result

Save a durable copy

Write bytes to a private temporary path first, validate the operation, then move the file into the intended storage location. For durable retention or delivery across application instances, use the application’s object-storage layer. Treat a vendor-hosted URL as a delivery convenience unless its documentation promises the retention and access behavior your application needs.

Stream bytes from a PHP endpoint

When the provider returns image bytes, set the response content type to the actual format and avoid printing debug output before the bytes. In a framework, return a binary response rather than echoing from a controller. For a plain PHP endpoint, the shape is:

<?php
// $bytes and $contentType should come from a successful, validated API response.
header('Content-Type: ' . $contentType);
header('Content-Disposition: inline; filename="capture.png"');
echo $bytes;

Do not accept an arbitrary user-supplied URL and fetch it from a privileged server without controls. Restrict schemes to HTTP/HTTPS, consider an allowlist for internal applications, and prevent access to private network or metadata addresses to reduce server-side request forgery risk.

Handle failures and retries

Distinguish transport errors from API errors and rendering outcomes. Log the provider, HTTP status, request correlation identifier if available, and a sanitized target identifier. Do not log secrets or sensitive query parameters from the captured URL.

Symptom Likely cause Response
Connection or DNS error Network, DNS, TLS, or firewall issue between PHP and provider. Check outbound access and certificate configuration; retry only transient failures.
Timeout Slow destination, heavy page, long wait condition, or client timeout shorter than render time. Raise a bounded timeout, reduce unnecessary waits, or use the provider’s documented asynchronous workflow.
Authentication error Missing, invalid, expired, or incorrectly formatted credential. Check the secret configuration and required header or signing method; never expose the key to the browser.
Insufficient credits or quota Account balance or plan limit reached. Handle as a non-transient failure and alert or route to an approved fallback.
Non-image response API returned JSON error details, a hosted URL, or a different format. Inspect status and content type, then parse according to the API documentation instead of saving error JSON as an image.
Blank or incomplete capture Page did not finish rendering, content is delayed, or the target blocks automated access. Use an appropriate documented wait, verify the URL is reachable to the rendering service, and inspect the provider’s reported outcome.
File write failure Directory does not exist, permissions deny writes, or storage is full. Check the destination and permissions; write to a managed temporary directory or object storage.

Retry only when the failure is plausibly transient, such as a connection reset or selected server error. Use a small attempt limit and backoff, and avoid blindly retrying authentication errors, invalid options, quota failures, or deterministic page errors. If the provider supports idempotency keys or cached captures, follow its documented semantics.

Performance, reliability, and cost

  • Keep the render focused. Full-page captures, large viewports, high device pixel ratios, and long waits increase response size or render work.
  • Use async jobs for long work. If the provider offers jobs and signed webhooks, move slow captures out of a user-facing PHP request and verify webhook signatures before acting on them.
  • Cache intentionally. Cache only when the page can be reused for the chosen period. Consider freshness, URL query parameters, authentication, viewport, and other render options in the cache key.
  • Protect worker capacity. Limit concurrent captures and queue bursts so a batch of slow pages does not exhaust PHP workers.
  • Estimate cost from actual API terms. Providers differ in quotas, billing units, and whether failed captures are billable. This research did not establish comparable current pricing for the third-party services discussed, so check their current pricing and billing documentation before rollout.

ScreenshotNeo states that bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing; responses identify page verdict and billing status in headers. It offers 1,000 shots per month free without a card; paid plans start at $5 for 3,000, and yearly billing gives two months free. Every feature is on every plan. Confirm current terms on the product site before purchase.

Or skip the browser setup

Use ScreenshotNeo’s one-call API when you want the service to render the page and return the image. Store the API key server-side. The request below saves the returned WebP bytes:

<?php
$apiKey = getenv('SCREENSHOTNEO_API_KEY');
$query = http_build_query(['access_key' => $apiKey, 'url' => 'https://stripe.com']);
$bytes = file_get_contents('https://api.screenshotneo.com/v1/shot?' . $query);
file_put_contents('shot.webp', $bytes);

See the ScreenshotNeo API docs for response handling and available options. Cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents use screenshot tools. One thousand screenshots a month are free with no card; paid plans start at $5 for 3,000.

Sign up free for 1,000 screenshots a month, with no card required.

FAQ

Can I call a screenshot API without Composer?

Yes. PHP cURL or another HTTP client can call a provider’s REST API. You still need to implement its authentication, response parsing, timeouts, and error handling.

Should I store the image or keep the provider’s URL?

Store a copy when your application needs controlled retention or durable delivery. Keep a hosted URL only when its access and retention guarantees match your needs.

Can I capture a page that requires login?

Only if the provider supports the needed cookies or authentication and the target is reachable from its renderer. Check the provider’s security guidance before sending session credentials.

Why does a screenshot differ from what I see in my browser?

The renderer may use a different viewport, locale, timezone, network location, session state, or load timing. Make those inputs explicit where the API supports them.