PHP has no built-in function that renders a webpage into an image. To screenshot a URL, PHP must control a browser engine such as Chrome or Chromium. The browser loads HTML, CSS, fonts, images, and JavaScript; your PHP code waits for the page to reach the state you need, captures either the viewport or the full page, and writes an image file.
The most direct PHP implementation uses chrome-php/chrome. Browsershot provides a shorter wrapper but requires Node.js and Puppeteer, while a Playwright PHP package exposes another browser-automation workflow. This guide shows runnable patterns, readiness and full-page decisions, deployment requirements, troubleshooting, and an API alternative.
Choose the PHP screenshot approach
Your choice is mainly a runtime decision, not a difference in image quality. All three library approaches ultimately drive a real browser.
| Approach | PHP call style | Additional runtime | Best fit |
|---|---|---|---|
| chrome-php/chrome | Direct browser and page control | Chrome or Chromium | Applications needing explicit navigation, waits, formats, and browser options |
| Spatie Browsershot | Browsershot::url(...)->save(...) |
Node.js, Puppeteer, and Chrome | Projects that prefer a compact URL/HTML-to-image wrapper |
| Playwright PHP | Launch Chromium, create a page, then call screenshot() |
Playwright browser installation | Teams already using Playwright-style automation |
Check each project’s current release, supported PHP and browser versions, operating-system requirements, and installation instructions before deploying. These details change independently of your PHP code.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstall#1 Best Overall
Requirements before writing code
- A PHP application with Composer.
- A writable output directory.
- Chrome or Chromium installed on the server, or an explicitly configured executable path.
- Network access to the page being captured, unless you are rendering local HTML.
- Enough memory and process limits for a browser. A browser is a separate process; a successful Composer install does not prove that the browser dependency is available.
The chrome-php/chrome README lists PHP 7.4–8.5 and Chrome/Chromium 65 or newer. Treat those as the documented range for that project and verify the current compatibility matrix when you install it. Its documentation also describes the CHROME_PATH environment variable and explicit executable selection when Chrome is not discoverable.
Method 1: chrome-php/chrome (direct PHP control)
Install the package
composer require chrome-php/chrome
Install Chrome or Chromium separately. In containers and CI, make the executable path and required system libraries part of the image rather than assuming a desktop installation exists.
Capture the visible viewport
This complete example starts a headless browser, opens a page, waits for navigation, saves a PNG, and closes the browser even if capture fails.
<?php
require __DIR__ . '/vendor/autoload.php';
use HeadlessChromiumBrowserFactory;
$browser = (new BrowserFactory())->createBrowser();
try {
$page = $browser->createPage();
$page->navigate('https://example.com')->waitForNavigation();
$page->screenshot()->saveToFile(__DIR__ . '/screenshot.png');
} finally {
$browser->close();
}
waitForNavigation() confirms that navigation reached its completion condition; it does not guarantee that a single-page application has fetched its data, that lazy images are decoded, or that web fonts have finished loading. Add an application-specific wait before the screenshot when those details matter.
Configure Chrome explicitly
If Chrome is not on the process PATH, configure the executable using the package’s supported factory options or its documented CHROME_PATH environment variable. Keep the path outside source code when it differs by environment. Run the same command as the web worker or queue user so permissions and sandbox behavior match production.
Choose PNG, JPEG, or WebP
The package documents PNG, JPEG, and WebP output. Use PNG for sharp text and UI elements, JPEG when photographic content and smaller files matter, and WebP when your consumers support it and you want a compact web asset. Image dimensions and device scale affect both visual detail and file size.
Rank #2
Capture the entire page
A normal screenshot is the current viewport. Full-page capture is a separate option or clipping mechanism, and should be enabled deliberately. The exact method depends on the package version; follow its current screenshot API rather than combining syntax from another library. A long page can create a very tall image, consume substantial memory, and exceed downstream upload limits.
Make the capture reliable
Wait for the state your page needs
- Wait for navigation.
- Wait for a selector that proves the main content exists, if your library supports selector waits.
- Wait for a known application event or a short delay when client-side rendering has no stable selector.
- Ensure lazy-loaded images are in view or otherwise triggered before a full-page capture.
- Capture only after fonts and critical assets have loaded if typography is part of the comparison.
“Navigation complete” is not the same as “the page is visually complete.” Define readiness from your own page: a product grid count, a dashboard root element, or an application-loaded flag is more dependable than an arbitrary long sleep.
Free tools Windows power users keep installed
One-click scans. No signup required.
Control viewport and device pixels
Set a viewport that matches the device or breakpoint you are documenting. CSS pixels determine layout; device scale influences raster resolution and file size. A high scale can make text sharper but increases memory and output size. Record the viewport and scale with the file if screenshots will be compared over time.
Use safe cleanup in workers
Always close the browser in a finally block. In queue workers, leaking browser processes eventually exhausts memory or process limits. For high volume, measure your own concurrency and recycle workers before they accumulate stale processes.
Method 2: Spatie Browsershot
Browsershot presents a concise PHP interface for URL or HTML input:
<?php
use SpatieBrowsershotBrowsershot;
Browsershot::url('https://example.com')
->save(__DIR__ . '/screenshot.png');
This convenience layer runs Puppeteer, which drives headless Chrome. Install and configure Node.js, Puppeteer, and Chrome according to the current Browsershot documentation. The project notes that its older Chrome CLI v2 route is no longer maintained, so do not build a new deployment around that legacy path. Browsershot is attractive when your team accepts the Node dependency and wants a short URL-to-image call; direct browser control is preferable when you need detailed lifecycle and readiness control.
Method 3: Playwright PHP
A Playwright PHP package documents the same fundamental sequence: launch headless Chromium, create a page, navigate, then save a screenshot.
<?php
// Namespace and installation details depend on the Playwright PHP package version.
$playwright = PlaywrightPlaywright::create();
$browser = $playwright->chromium()->launch(['headless' => true]);
$page = $browser->newPage();
$page->goto('https://example.com');
$page->screenshot(__DIR__ . '/screenshot.png');
$browser->close();
Use the package’s current namespace, installation command, browser-install command, and method signatures; do not copy APIs between Playwright, Browsershot, and chrome-php/chrome. Verify project maturity, supported PHP versions, and browser releases before making it a production dependency. Playwright’s screenshot API documents options such as full-page capture and scale, but those options must match the PHP binding version you install.
Viewport, element, and full-page decisions
Viewport screenshot
Use the default viewport when you need what a user sees without scrolling, such as a responsive breakpoint check or a support ticket.
Element or region screenshot
Capture a specific element when surrounding navigation, cookie notices, or browser chrome would make the image noisy. Locate the element with a stable selector and wait for it before capturing. A selector that changes between builds will produce an error or an empty result.
Full-page screenshot
Enable the library’s full-page option when documentation, archival, or visual-regression work requires the complete scrollable document. Test very tall pages separately: fixed headers, infinite scrolling, sticky elements, and lazy loading can produce results that differ from a single viewport.
Saving and serving the file safely
- Resolve output paths from a controlled directory; never let an untrusted URL become a filesystem path.
- Check that the process user can create and overwrite the destination.
- Use unique names for concurrent jobs to prevent one capture from replacing another.
- Validate the resulting file and MIME type before publishing it.
- Keep secrets out of page URLs. If authentication is required, use the library’s supported cookies, headers, or authenticated browser context and protect the output.
Troubleshooting PHP screenshots
“Chrome executable not found”
Cause: Chrome is missing or not discoverable by the worker. Fix: install Chrome/Chromium, set the documented executable path or CHROME_PATH, and run a command as the same user that executes PHP.
The Composer package installs but capture fails immediately
Cause: PHP dependencies are present but browser binaries or Linux libraries are not. Fix: install the browser and OS packages in the deployment image, then test a minimal URL capture from the production runtime.
Rank #4
The screenshot is blank or missing application data
Cause: capture occurred before client-side rendering, an API request failed, or the target blocked the automated browser. Fix: inspect page logs and network access, wait for a content selector or application-ready signal, and verify the URL manually from the same host.
Images or fonts are missing
Cause: lazy loading, blocked cross-origin assets, or capture before resources finish. Fix: trigger lazy content, wait for the relevant assets, permit required outbound requests, and use a stable font-loading condition.
Full-page output is enormous
Cause: the document is genuinely tall or device scale is high. Fix: capture a viewport or selected elements, lower the scale, split long documents, or choose JPEG/WebP where appropriate.
Browser processes accumulate
Cause: an exception path skipped cleanup. Fix: close in finally, add worker timeouts, and monitor process and memory usage.
Performance, reliability, and cost considerations
Starting a browser is more expensive than writing a local image, so reuse must be balanced against isolation. A long-lived browser can reduce startup overhead, while a fresh context per job limits state leakage. Whichever model you choose, cap concurrency, set navigation and overall job timeouts, and record the target URL, viewport, format, and failure reason.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →For predictable builds, pin PHP packages and browser versions, run a smoke capture in CI, and keep a known static test page. Network-dependent pages can change without a code deployment; visual comparisons should therefore record the capture time and readiness condition.
Or skip the browser setup
ScreenshotNeo is a hosted website screenshot API and MCP server. One GET request returns PNG, JPEG, WebP, or PDF, so PHP only has to make an HTTP request and save the response.
PHP call
<?php
$url = 'https://stripe.com';
$query = http_build_query([
'access_key' => 'YOUR_API_KEY',
'url' => $url,
]);
$data = file_get_contents(
'https://api.screenshotneo.com/v1/shot?' . $query
);
if ($data === false) {
throw new RuntimeException('Screenshot request failed');
}
file_put_contents(__DIR__ . '/shot.webp', $data);
See the ScreenshotNeo documentation for authentication and options. It accepts 63 options, including full-page capture with lazy images loaded, CSS-selector element capture, dark mode, device presets or custom viewports, retina scale, PDF settings, custom CSS and JavaScript, click-before-capture, selector or network-idle waits, request and resource blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, and a usage API. Parameter names used by other screenshot APIs also work, which can simplify migration.
Equivalent cURL, Python, and Node.js calls
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)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesThe Free plan includes 1,000 shots per month with no card. Paid plans start at $5 for 3,000 shots; yearly billing provides two months free. Create a free ScreenshotNeo account to try the API without a card.
Frequently Asked Questions
Can PHP take a screenshot without Chrome?
Not for a browser-rendered webpage using these methods. PHP needs a browser engine such as Chrome or Chromium, either installed with a PHP library or provided by a hosted screenshot service.
Should I use a viewport or full-page screenshot?
Use a viewport for what is visible without scrolling and explicitly enable full-page capture when the complete document is required.
Why does my screenshot show an old page?
Caching, application state, or a page that has not reached its ready condition can produce stale output. Set an appropriate cache policy, wait for a content-specific condition, and verify the target response from the capture host.
Recommended Free Tools
Quick Recap
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.

