Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

PHP can save screenshots, but the right method depends on what you are capturing. GD can copy an existing desktop or window, and Imagick can process an image you already have. For a webpage that must render HTML, CSS and JavaScript, use headless Chrome, the chrome-php/chrome library, or Selenium WebDriver. A hosted API avoids installing and isolating a browser.

Which PHP screenshot method should you use?

Method What it renders or captures Scope Dependencies Best fit
ScreenshotNeo (#1 hosted option) Real webpage rendering with cleanup before capture Viewport, full page, CSS selector, PDF and more HTTP request and API key Production capture without local browser operations; clean shots, only clean shots billed, and a $5 paid plan
GD Existing operating-system screen or window Desktop or window PHP GD extension and an available desktop context Capturing a screen already displayed on the host
Imagick Does not render webpages; edits image data Any image supplied to it Imagick PHP extension and ImageMagick Resize, annotate, compose, convert or optimize a capture
Headless Chrome CLI Chromium-rendered HTML, CSS and JavaScript Viewport; dimensions controlled with a window size Chrome or Chromium executable Simple server-side webpage screenshots
Chrome PHP library Chromium-rendered HTML, CSS and JavaScript Viewport, rectangular clip and full page Composer package plus Chrome or Chromium PHP-native browser control
Selenium WebDriver Current browser context Page or individual element PHP Selenium client, browser and compatible driver Existing browser tests and automation suites

There is no defensible universal speed, memory or fidelity benchmark for these approaches. Choose based on rendering requirements, capture scope, dependencies, isolation and operational cost.

1. Capture a desktop or window with PHP GD

GD’s imagegrabscreen() captures the whole operating-system screen, while imagegrabwindow() captures a window when you provide its window handle. This is an OS-level capture, not a server-side HTML renderer: a headless Linux process with no display will not magically render a URL.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Capture the current screen

<?php
if (!function_exists('imagegrabscreen')) {
    throw new RuntimeException('The GD screen-capture function is unavailable.');
}

$image = imagegrabscreen();
if ($image === false) {
    throw new RuntimeException('The screen could not be captured.');
}

if (!imagepng($image, __DIR__ . '/screen.png')) {
    imagedestroy($image);
    throw new RuntimeException('The PNG could not be written.');
}

imagedestroy($image);

Enable or compile GD in the PHP build before running this code. Use imagejpeg() instead of imagepng() when JPEG output is more appropriate. To capture a particular window, use imagegrabwindow() with a valid window handle supplied by the operating system.

When GD is the wrong tool

  • It does not navigate to a URL or execute page JavaScript.
  • It depends on a real desktop or window context, which complicates ordinary web servers and containers.
  • It cannot select a CSS element from a webpage that is not already displayed.

2. Process a capture with Imagick

Imagick is a native PHP extension for the ImageMagick API. It reads, converts and writes many image formats, but it does not render a webpage by itself. Use it after GD, Chrome, Selenium or another capture method.

Resize and convert an existing screenshot

<?php
if (!extension_loaded('imagick')) {
    throw new RuntimeException('The Imagick extension is not loaded.');
}

$image = new Imagick(__DIR__ . '/capture.png');
$image->setImageFormat('webp');
$image->resizeImage(1200, 0, Imagick::FILTER_LANCZOS, 1);
$image->setImageCompressionQuality(82);
$image->writeImage(__DIR__ . '/capture.webp');
$image->clear();
$image->destroy();

You can also annotate, compose or optimize the image at this stage. Keep the capture step separate so a failed webpage load is not confused with a successful image conversion.

3. Run headless Chrome from PHP

Chrome’s headless shell renders a page in Chromium, making it the direct command-line path when CSS and JavaScript fidelity matter. The --screenshot option writes an image, and --window-size=WIDTH,HEIGHT controls the viewport.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Test the command first

chrome --headless --disable-gpu --screenshot=screenshot.png --window-size=1440,1200 https://example.com

Confirm that Chrome exits successfully and that screenshot.png exists before integrating it into PHP.

Invoke Chrome safely from PHP

<?php
$url = 'https://example.com';
$output = __DIR__ . '/screenshot.png';

$command = sprintf(
    'chrome --headless --disable-gpu --screenshot=%s --window-size=1440,1200 %s',
    escapeshellarg($output),
    escapeshellarg($url)
);

$process = proc_open(
    $command,
    [1 => ['pipe', 'w'], 2 => ['pipe', 'w']],
    $pipes
);

if (!is_resource($process)) {
    throw new RuntimeException('Chrome could not be started.');
}

$stdout = stream_get_contents($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[1]);
fclose($pipes[2]);
$exitCode = proc_close($process);

if ($exitCode !== 0 || !is_file($output) || filesize($output) === 0) {
    throw new RuntimeException("Chrome failed ({$exitCode}): {$stderr}");
}
  • Keep URLs under your control or validate them against an allowlist; escaping prevents shell syntax from being interpreted but does not make arbitrary URL fetching safe.
  • Run the browser with a restricted service account or container and set resource and execution limits.
  • Check both the process exit code and output file. A command can finish without producing a usable screenshot.

4. Use the Chrome PHP library

The chrome-php/chrome Composer library lets PHP start Chrome or Chromium, navigate, wait for navigation and save screenshots. Its documented API supports PNG, JPEG and WebP output, rectangular clipping, and full-page capture with captureBeyondViewport plus a full-page clip. The project describes it this way: “This library lets you start playing with chrome/chromium in headless mode from PHP.”

Install and capture

composer require chrome-php/chrome
<?php
require __DIR__ . '/vendor/autoload.php';

use HeadlessChromiumBrowserFactory;

$browser = (new BrowserFactory())->createBrowser();
try {
    $page = $browser->createPage();
    $page->navigate('https://example.com')->waitForNavigation();

    $page->screenshot([
        'format' => 'png',
        'captureBeyondViewport' => true,
    ])->saveToFile(__DIR__ . '/page.png');

    $page->screenshot([
        'format' => 'jpeg',
        'clip' => [
            'x' => 0,
            'y' => 0,
            'width' => 800,
            'height' => 600,
        ],
    ])->saveToFile(__DIR__ . '/clip.jpg');
} finally {
    $browser->close();
}

For a true full-page image, supply a clip whose width and height match the document’s measured dimensions together with captureBeyondViewport. A fixed clip, such as the 800-by-600 example, intentionally captures only that rectangle.

Advantages and limits

  • You control the browser from PHP rather than assembling shell commands.
  • JavaScript-driven pages can finish rendering before the screenshot is saved.
  • Chrome or Chromium still has to be installed, kept compatible and isolated on the server.

5. Capture pages and elements with Selenium WebDriver

Selenium is a strong choice when screenshots belong inside an existing browser-testing or automation suite. A PHP implementation needs a Selenium client, a compatible browser driver and a browser. WebDriver captures the current browsing context, and the returned screenshot data can be saved as PNG or handled as bytes or base64.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Save a page and an element

<?php
use FacebookWebDriverRemoteDesiredCapabilities;
use FacebookWebDriverRemoteRemoteWebDriver;
use FacebookWebDriverWebDriverBy;

$driver = RemoteWebDriver::create(
    'http://selenium:4444/wd/hub',
    DesiredCapabilities::chrome()
);

try {
    $driver->get('https://example.com');

    $pagePng = $driver->takeScreenshot();
    file_put_contents(__DIR__ . '/page.png', base64_decode($pagePng));

    $element = $driver->findElement(WebDriverBy::cssSelector('.hero'));
    $elementPng = $element->takeElementScreenshot();
    file_put_contents(__DIR__ . '/hero.png', base64_decode($elementPng));
} finally {
    $driver->quit();
}

Use the method names and return format documented by the PHP Selenium client version you install; clients can differ in whether screenshot data is returned as base64 or decoded bytes. The important distinction is that WebDriver can target an individual element, while a basic browser screenshot normally represents the current page context.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Practical selection and troubleshooting

Choose by rendering requirement

  • Existing desktop image: choose GD only when the required screen or window is already displayed.
  • Webpage with JavaScript: choose headless Chrome or the Chrome PHP library.
  • Element inside an automated test: choose Selenium.
  • Post-processing: add Imagick after whichever capture method produced the image.

Check these failure points

  • Blank or missing output: verify the browser binary, executable permissions, display requirements for GD, output-directory permissions and process exit status.
  • Incomplete page: wait for navigation or the page state your application needs before capturing; a viewport screenshot is not automatically a full-page screenshot.
  • Element not found: confirm the selector after navigation and after any client-side rendering has completed.
  • Unsafe URL input: do not pass unrestricted user URLs to a local browser process. Validate destinations and isolate the browser.

Or skip the browser setup

ScreenshotNeo is the hosted option to try first when you want a PHP screenshot API: it removes cookie and consent banners, newsletter popups and chat widgets before capture, and only clean shots are billed. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing; the response identifies the result with X-Page-Verdict and X-Billed headers.

One GET request returns a PNG, JPEG, WebP or PDF. The API supports full-page captures with lazy images loaded, CSS-selector element captures, dark mode, device presets and custom viewports, retina scale, PDF paper and page controls, custom CSS and JavaScript, clicks, waits, hidden selectors, blocked ads or resources, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, configurable caching, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API and an OpenAPI specification. Its MCP server provides take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients.

Call it from PHP

See the ScreenshotNeo API documentation for authentication and all options.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; Growth is $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000 and Business $249 for 1,000,000. Yearly billing gives two months free, and every feature is on every plan. Create a free ScreenshotNeo account to start without a card.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.