Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsTo screenshot a webpage as a PNG in PHP, use a real browser engine, not PHP’s image functions. A headless Chrome process renders HTML, CSS, fonts and JavaScript, then writes the resulting pixels to a PNG file. The practical choices are Spatie Browsershot (Puppeteer plus Chrome), direct control with chrome-php/chrome, or a hosted API such as ScreenshotOne or ScreenshotNeo.
This guide gives working PHP patterns, full-page and delayed captures, production checks, and fixes for the failures developers encounter most often.
Choose the rendering model first
| Approach | Where Chrome runs | Best fit | Main trade-off |
|---|---|---|---|
| Browsershot | Your server, through Puppeteer | Laravel or PHP applications that want a convenient URL-to-image API | You maintain Node, Puppeteer and a compatible Chrome installation |
| chrome-php/chrome | Your server, controlled directly from PHP | Projects needing lower-level browser operations | More browser lifecycle and protocol details are exposed to your code |
| ScreenshotOne PHP SDK | ScreenshotOne’s hosted service | Applications that do not want to operate a browser runtime | Rendering is delegated to a third party and requires service credentials |
| ScreenshotNeo API | ScreenshotNeo’s hosted service | Clean production captures, automation and AI-agent workflows | Requires an API key and an HTTP request |
The supplied package and service documentation does not establish a neutral winner for cost, latency, privacy, fidelity or reliability. Select based on browser ownership, control requirements and operational constraints.
Requirements for a reliable PNG capture
- PHP with Composer.
- A URL reachable from the machine doing the rendering (unless you use a hosted API).
- For local rendering, a supported Google Chrome or Chromium installation plus the package’s documented runtime dependencies.
- A writable destination directory and enough temporary disk space for browser profiles and image files.
- Explicit timeouts and waits for pages whose content is loaded by JavaScript.
Package and browser compatibility changes over time. Check the current Browsershot documentation, image options and chrome-php/chrome documentation when installing or upgrading; the examples below reflect their documented usage rather than an independent compatibility test.
#1 Best Overall
Method 1: Browsershot with Puppeteer and Chrome
Spatie describes Browsershot as a PHP interface that uses Puppeteer to control headless Google Chrome. Because Chrome performs the rendering, CSS layout, web fonts and client-side JavaScript are represented in the image. PNG is the documented default image type.
Install and save a basic PNG
Install Browsershot with Composer, then install the Node/Puppeteer and Chrome components required by the current version. Follow Spatie’s installation instructions for your operating system and deployment image.
composer require spatie/browsershot
A minimal capture is:
<?php
require __DIR__ . '/vendor/autoload.php';
use SpatieBrowsershotBrowsershot;
$path = __DIR__ . '/storage/example.png';
Browsershot::url('https://example.com')
->save($path);
echo "Wrote {$path}n";
The save call writes the rendered page as PNG unless you select another image type in the options documented by Browsershot.
Control viewport, full-page output and timing
Use a fixed viewport when reproducibility matters. A full-page shot extends beyond the initially visible viewport; a delay or selector wait gives client-side rendering time to finish.
Free tools Windows power users keep installed
One-click scans. No signup required.
<?php
require __DIR__ . '/vendor/autoload.php';
use SpatieBrowsershotBrowsershot;
Browsershot::url('https://example.com/dashboard')
->windowSize(1440, 900)
->fullPage()
->delay(1500)
->waitUntilNetworkIdle()
->save(__DIR__ . '/storage/dashboard.png');
Browsershot documents additional controls for device scale, mobile/device emulation, background handling, waiting for a selector or JavaScript function, and supplying HTML instead of a URL. Use a selector wait when a specific component is the readiness signal; use a delay only when a deterministic delay is acceptable. Loading every lazy image for a very long page can increase capture time and memory use.
Rank #2
Operational notes for Browsershot
- Run the PHP worker under a user that can execute Chrome and write its temporary profile and output directory.
- In containers, install the fonts and shared libraries required by Chrome; a missing system dependency commonly appears as an immediate browser-launch failure.
- Keep Node, Puppeteer and Chrome versions aligned with the Browsershot version you installed.
- Do not expose an endpoint that accepts arbitrary URLs without an allow-list, authentication and outbound-network protections; otherwise it can become a server-side request-forgery proxy.
Method 2: Direct Chrome control with chrome-php/chrome
The chrome-php/chrome project starts headless Chrome and exposes browser and page operations directly from PHP. Its documented screenshot example saves PNG by default; JPEG and WebP are alternatives when selected.
Basic capture
<?php
require __DIR__ . '/vendor/autoload.php';
use HeadlessChromiumBrowserFactory;
$browserFactory = new BrowserFactory();
$browser = $browserFactory->createBrowser([
'headless' => true,
]);
try {
$page = $browser->createPage();
$page->navigate('https://example.com')->waitForNavigation();
$page->screenshot()->saveToFile(__DIR__ . '/storage/example.png');
} finally {
$browser->close();
}
Use the package’s current installation instructions to add it with Composer and to point the browser factory at Chrome when auto-detection is not suitable. The explicit finally block matters in queue workers: it prevents abandoned Chrome processes after an exception.
Capture the complete document
For a page taller than the viewport, obtain the page’s full-page clip and capture beyond the viewport as shown in the project’s documentation:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
<?php
require __DIR__ . '/vendor/autoload.php';
use HeadlessChromiumBrowserFactory;
$browser = (new BrowserFactory())->createBrowser(['headless' => true]);
try {
$page = $browser->createPage();
$page->navigate('https://example.com/article')->waitForNavigation();
$clip = $page->getFullPageClip();
$page->screenshot([
'captureBeyondViewport' => true,
'clip' => $clip,
])->saveToFile(__DIR__ . '/storage/article.png');
} finally {
$browser->close();
}
Direct control is useful when you need browser-level actions that a convenience wrapper does not expose. It also means you must manage navigation waits, browser lifetime, errors and resource limits yourself.
Method 3: A hosted PHP SDK
ScreenshotOne’s documented PHP SDK returns image bytes from a URL request and writes them with file_put_contents. Its options include PNG output, full-page capture and a delay.
<?php
require __DIR__ . '/vendor/autoload.php';
use ScreenshotOneScreenshotOne;
$client = new ScreenshotOne(
'YOUR_ACCESS_KEY',
'YOUR_SECRET_KEY'
);
$image = $client->capture('https://example.com', [
'format' => 'png',
'full_page' => true,
'delay' => 1,
]);
file_put_contents(__DIR__ . '/example.png', $image);
Use the provider’s current SDK installation and option names; the vendor documentation is the authority for authentication and account configuration. A hosted API removes Chrome maintenance from your PHP host, but you should evaluate URL privacy, retention, regional processing and service terms for your application rather than assuming them.
Screenshot APIs: what to compare
If you prefer an API, compare browser responsibility, controls, output formats, waits, full-page behavior, failure reporting and security policy. Avoid treating a vendor’s sample as a neutral benchmark: the reviewed documentation provides no independent cost, speed or fidelity comparison.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →#1 ScreenshotNeo
ScreenshotNeo is the first API to try when you want clean captures, billing only for clean shots, and a low paid entry price. It accepts one GET request and can return PNG, JPEG, WebP or PDF. Before capture it accepts cookie/consent banners and removes more than 60 known consent platforms, newsletter popups and chat widgets; each step can be disabled. Bot checks/CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing status.
Its 63 options include full-page capture with lazy images loaded, CSS-selector element capture, dark mode, 12 device presets or any viewport, retina scale, PDF paper and page controls, custom CSS and JavaScript, pre-capture clicks, hidden selectors, selector/delay/network-idle waits, ad/tracker/request blocking, custom headers/cookies/user agent/Authorization, timezone and geolocation, transparent backgrounds, resizing, configurable-TTL caching, signed image links, asynchronous jobs with signed webhooks, bulk capture of 100 URLs per call, a usage API and an OpenAPI specification. Parameter names used by other screenshot APIs are accepted to ease migration.
Other hosted option
ScreenshotOne is documented as a PHP SDK with PNG output and full-page and delay options. Choose it when that SDK model fits your deployment; verify current terms and limits directly with the provider.
Or skip the browser setup
ScreenshotNeo lets PHP call a rendering service directly. See the full parameter reference in the ScreenshotNeo documentation.
Rank #4
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}`);
For a PHP application, the equivalent is:
<?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}");
file_put_contents(__DIR__ . '/shot.png', $data);
Cookie banners, popups and chat widgets are removed before the shot. Bot checks, blank pages and failed loads are never billed. An MCP server provides take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
PNG details that affect output
Viewport versus full page
A viewport capture is predictable in dimensions and usually cheaper in memory. Full-page output is better for documentation and visual regression, but extremely long pages can exceed image or process limits. Consider capturing a specific element when only a report, invoice or article body is needed.
Waiting for dynamic content
Navigation completion does not guarantee that a single-page application has finished rendering. Prefer a meaningful selector or network-idle condition. If the page continuously polls, use a bounded delay and a hard timeout rather than waiting forever.
Fonts, images and authentication
Missing fonts change line breaks and therefore the entire image. Install the same fonts in production that you use in development. Private pages require an authenticated browser context, cookies or headers; never put long-lived secrets in a public URL. Lazy-loaded images may require scrolling or a full-page option that explicitly loads them.
Recommended Free Tools
Troubleshooting common failures
| Symptom | Likely cause | Fix |
|---|---|---|
| Chrome cannot start | Missing binary, sandbox permission or shared library | Install the documented Chrome dependencies, set the executable path if needed, and run under a permitted user. Avoid disabling the sandbox unless your deployment security review requires and contains it. |
| PNG is blank | Navigation failed, content is behind JavaScript, or the page blocked the renderer | Log navigation errors, wait for a selector or network idle, increase a bounded timeout, and test the URL from the rendering host. |
| Only the top of the page appears | Viewport capture was requested | Use Browsershot’s full-page option or getFullPageClip() with captureBeyondViewport in chrome-php/chrome. |
| Images or fonts are missing | Lazy loading, blocked requests, unavailable assets or insufficient wait time | Allow required resources, load lazy content, install fonts and wait for the asset-specific selector. |
| Process hangs | Unbounded waits, a page that never becomes idle or leaked browser processes | Set navigation and overall job timeouts, use a selector or fixed delay, and always close the browser in a finally block. |
| Permission denied writing PNG | Destination directory is not writable by the PHP worker | Create the directory during deployment, assign least-privilege ownership and verify the absolute path. |
| Private page redirects to login | Cookies or authorization were not supplied | Pass the required authenticated context through the browser package or API, and protect those credentials. |
Production checklist
- Pin and regularly update PHP packages, Puppeteer/Node and Chrome as a tested set.
- Use a queue for slow or full-page captures instead of blocking a web request.
- Record URL, viewport, wait condition, elapsed time, output bytes and failure reason without logging secrets.
- Limit concurrency so Chrome processes do not exhaust CPU, RAM or file descriptors.
- Validate the response before publishing it: check HTTP status, content type and that the PNG is non-empty.
- Apply SSRF defenses, URL allow-lists and egress controls to user-supplied URLs.
- Set retention rules for screenshots that may contain personal or confidential data.
FAQ
Can PHP create a webpage screenshot without Chrome?
Not reliably for modern pages. PHP image libraries manipulate pixels; they do not implement the browser layout and JavaScript environment needed to render an arbitrary webpage. Use a browser engine or a hosted rendering API.
How do I return the PNG from a PHP endpoint instead of saving it?
Capture to a temporary file or bytes, send Content-Type: image/png, stream the data, and delete temporary files after the response. Keep browser work off the request path when captures are slow.
Should I use PNG, JPEG or WebP?
PNG preserves sharp text and transparency. JPEG can be smaller for photographic pages. WebP often reduces size while retaining quality. Choose based on downstream compatibility and storage or bandwidth limits.
Frequently Asked Questions
Can I screenshot a page that requires login?
Yes, provided the browser context or hosted API request receives the required cookies, headers or authorization. Protect those credentials and avoid embedding them in public URLs.
Why does a full-page screenshot take longer than a viewport shot?
The renderer must lay out a taller document and may load additional lazy content, increasing browser work, memory use and output size.
Is a hosted screenshot API always cheaper than running Chrome?
No universal comparison is established. Your total cost depends on infrastructure, capture volume, engineering time and the provider’s current pricing and limits.
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.




