ScreenshotNeo

BlogHow-to

Screenshotlayer API Tutorial in PHP for Indian Developers

Capture website screenshots with Screenshotlayer in PHP. Learn request options, safe image handling, errors, plan limits and alternatives.

By the ScreenshotNeo team4 October 20268 min read

To capture a website with Screenshotlayer from PHP, send a GET request to https://api.screenshotlayer.com/api/capture with your access_key and the complete target url, including https://. Check the HTTP response and content type before saving the body as an image: an unsuccessful request may return an API error instead.

This guide uses PHP cURL and keeps the API key on the server. It also covers capture options, response handling, errors, plan considerations, and an alternative for developers who want an API that removes common page overlays before capture.

1. Get the API key and prepare PHP

Create a Screenshotlayer account and retrieve its access key from the provider. Store the key in a server-side environment variable; do not put it in a public HTML page or browser-side JavaScript. The request endpoint is https://api.screenshotlayer.com/api/capture. The provider’s specification describes access_key and url as required parameters.

The example requires PHP with the cURL extension enabled. Set the key in the environment where PHP runs, for example:

export SCREENSHOTLAYER_ACCESS_KEY='YOUR_ACCESS_KEY'

2. Make a screenshot request in PHP

This runnable script requests a PNG screenshot of https://example.com, checks the response, and saves the file only when the response looks like an image. Replace the target URL and output path as needed.

<?php
$accessKey = getenv('SCREENSHOTLAYER_ACCESS_KEY');
if (!$accessKey) {
    fwrite(STDERR, "Set SCREENSHOTLAYER_ACCESS_KEY first.\n");
    exit(1);
}

$params = [
    'access_key' => $accessKey,
    'url' => 'https://example.com',
    'format' => 'PNG',
];
$endpoint = 'https://api.screenshotlayer.com/api/capture';
$requestUrl = $endpoint . '?' . http_build_query($params, '', '&', PHP_QUERY_RFC3986);

$ch = curl_init($requestUrl);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_CONNECTTIMEOUT => 10,
    CURLOPT_TIMEOUT => 60,
    CURLOPT_HEADER => true,
]);
$response = curl_exec($ch);
if ($response === false) {
    $message = curl_error($ch);
    curl_close($ch);
    fwrite(STDERR, "Network or cURL error: {$message}\n");
    exit(1);
}

$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE) ?: '';
curl_close($ch);
$headers = substr($response, 0, $headerSize);
$body = substr($response, $headerSize);

if ($status < 200 || $status >= 300 || stripos($contentType, 'image/') !== 0) {
    fwrite(STDERR, "Screenshotlayer did not return an image (HTTP {$status}; Content-Type: {$contentType}).\n");
    fwrite(STDERR, substr($body, 0, 2000) . "\n");
    exit(1);
}

$output = __DIR__ . '/screenshot.png';
if (file_put_contents($output, $body) === false) {
    fwrite(STDERR, "Could not write {$output}\n");
    exit(1);
}
echo "Saved screenshot to {$output}\n";
?>

Run it from a terminal with php capture.php. The script checks both the HTTP status and the content type because a successful network connection does not guarantee that the body is an image. Depending on provider behavior, error details may be returned in a structured response; inspect the body while diagnosing failures, but avoid logging the full request URL because it contains the access key.

3. Add capture options

Screenshotlayer documents these useful query parameters:

Parameter Purpose Example
fullpage Request a full-page capture. fullpage=1
width Set the screenshot width. width=1200
viewport Set the viewport dimensions. viewport=1280x800
format Select an output format. The documented default is PNG; the provider lists PNG, JPEG and GIF. format=JPEG

For example, add 'fullpage' => 1 and 'viewport' => '1280x800' to the PHP $params array. The documented default viewport is 1440×900. Confirm exact accepted values and current behavior in the provider documentation before relying on a less common option.

4. Request with cURL, Python or Node.js

These examples use the same endpoint and required parameters. Keep the access key in an environment variable. For image output, write the response bytes to a file only after checking that the response is successful and the content type is an image.

cURL

curl --get 'https://api.screenshotlayer.com/api/capture' \
  --data-urlencode "access_key=$SCREENSHOTLAYER_ACCESS_KEY" \
  --data-urlencode 'url=https://example.com' \
  --data-urlencode 'format=PNG' \
  --output screenshot-response.bin \
  --write-out '\nHTTP %{http_code}; content type %{content_type}\n'

cURL saves the response body whether it is an image or an error. Check the printed status and content type before renaming the output file to an image extension.

Python

import os
import sys
import requests

key = os.environ.get("SCREENSHOTLAYER_ACCESS_KEY")
if not key:
    raise SystemExit("Set SCREENSHOTLAYER_ACCESS_KEY first")

response = requests.get(
    "https://api.screenshotlayer.com/api/capture",
    params={"access_key": key, "url": "https://example.com", "format": "PNG"},
    timeout=60,
)
content_type = response.headers.get("Content-Type", "")
if not response.ok or not content_type.lower().startswith("image/"):
    print(f"Screenshot request failed: HTTP {response.status_code}; {content_type}", file=sys.stderr)
    print(response.text[:2000], file=sys.stderr)
    raise SystemExit(1)

with open("screenshot.png", "wb") as file:
    file.write(response.content)

Node.js

const key = process.env.SCREENSHOTLAYER_ACCESS_KEY;
if (!key) throw new Error('Set SCREENSHOTLAYER_ACCESS_KEY first');

const query = new URLSearchParams({
  access_key: key,
  url: 'https://example.com',
  format: 'PNG',
});
const response = await fetch(
  `https://api.screenshotlayer.com/api/capture?${query}`,
  { signal: AbortSignal.timeout(60_000) }
);
const contentType = response.headers.get('content-type') || '';
if (!response.ok || !contentType.toLowerCase().startsWith('image/')) {
  const detail = await response.text();
  throw new Error(`Screenshot request failed: HTTP ${response.status}; ${contentType}; ${detail.slice(0, 2000)}`);
}
const bytes = Buffer.from(await response.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('screenshot.png', bytes));

5. Handle errors and edge cases

The provider’s specification describes errors for missing or invalid access keys, exhausted usage limits, and invalid URLs. Treat every response as potentially erroneous, and make diagnostics actionable.

Symptom Likely cause What to check
Missing or invalid key error The key is absent, mistyped, revoked, or not being loaded into the process. Check the server environment variable and account key. Never paste the key into public logs or support posts.
Invalid URL error The target is malformed or lacks a protocol. Pass a complete URL such as https://example.com/path, and ensure it is encoded as a query parameter.
Usage limit reached The account has reached its monthly allowance or applicable quota. Check current account usage and plan terms before retrying or upgrading.
HTTP succeeds but body is not an image The provider returned an API error payload or another non-image response. Inspect status, content type, and a bounded portion of the body. Do not save it with a .png extension.
Timeout or cURL failure Network interruption, slow rendering, DNS, TLS, or local PHP cURL configuration. Check outbound HTTPS access, the cURL extension and the target site. Retry transient network failures with a bounded retry policy.
Image file cannot be opened An error body may have been saved as an image, or the chosen extension does not match the requested format. Validate content type and use an extension corresponding to the response format.

Do not blindly retry invalid-key, invalid-URL, or usage-limit errors; those need a configuration or account change. For transient network errors, use a small number of retries with backoff, and avoid retry storms. Do not assume every target site is reachable or renderable from the provider’s service.

6. Compare Screenshotlayer plans and account for India

Screenshotlayer’s published pricing page, accessed October 3, 2026, lists these tiers. Pricing and included features can change, so verify the provider’s current page and terms before choosing a plan.

Plan Published price Monthly snapshots Published details
Free $0 100 Non-commercial use
Basic $19.99 monthly or $215.99 yearly 10,000 Commercial use, Retina/2x and WebP support, 10 dedicated workers
Professional $59.99 monthly or $629.99 yearly 30,000 20 dedicated workers; FTP/S3 export options
Enterprise $149.99 monthly or $1,529.99 yearly 75,000 40 dedicated workers; FTP/S3 export options

Choose using expected monthly captures, commercial-use needs, output requirements such as WebP or Retina, concurrency, export destinations, overage exposure, and monthly versus annual billing. Screenshotlayer says it notifies users at 75%, 90% and 100% of the allowance; its FAQ describes overage charges after quota exhaustion. Confirm the current terms for your account.

The published prices are in USD. The inspected provider information does not establish INR billing, Indian tax treatment, or acceptance of a particular Indian-issued card. Check the account checkout and ask the provider for India-specific billing details. The provider FAQ lists Visa, MasterCard, Discover and Diners Club, but that list does not guarantee acceptance of every card issued in India.

7. Performance, reliability and cost considerations

  • Request latency: Each synchronous call waits for the provider to render the target page and return bytes. Set a finite client timeout appropriate for your application and avoid holding a user-facing request open longer than necessary.
  • Concurrency: If capturing many URLs, account for your plan’s published dedicated-worker allocation. Queue work and cap concurrent calls so a batch does not overwhelm your application or exhaust quota unexpectedly.
  • Reliability: Treat captures as an external dependency. Record status, elapsed time, and error category without recording the access key. Retry only transient failures, with bounded backoff.
  • Cost control: Estimate monthly requests before selecting a tier. Monitor account usage and notifications; a failed local request does not itself tell you how the provider accounts for it, so consult current plan terms.
  • Storage: Save only validated image bodies. Use deterministic filenames or a cache when the same URL and capture settings are requested repeatedly by your application.

8. Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. A GET request returns a screenshot or PDF, and its documented options include full-page capture, element selection, formats, viewport presets, custom CSS and JavaScript, and more. See the ScreenshotNeo API documentation for the request parameters.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

With ScreenshotNeo, cookie banners are accepted or removed before capture, along with known newsletter popups and chat widgets. Bot checks, blank pages, failed loads and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server lets AI agents use screenshot, page-info and PDF tools. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots. Learn about ScreenshotNeo, then sign up for 1,000 free screenshots a month with no card.

Frequently asked questions

Does the target URL need a protocol?

Yes. Send a complete URL, including https:// or http://.

Can I use the free Screenshotlayer tier for a commercial product?

The pricing page describes the free tier as non-commercial and lists commercial use on paid tiers. Check the current terms for your use case.

Does the provider publish India-specific API behavior or INR pricing?

The reviewed information does not establish either. The listed plan prices are in USD; confirm local billing and tax details with the provider.

Why should PHP inspect the response content type?

A request can return an error payload instead of image bytes. Checking status and content type prevents saving an error response as a broken image file.