ScreenshotRender
← Back to blog
Tutorials

How to Screenshot a Website in PHP: 3 Ways

Robert Belt·9 min read
Updated On :
Orange minimalist illustration of PHP code turning a URL into a screenshot

PHP can render an HTML page all day, but it cannot open a browser, and a screenshot needs a browser. By the end of this you'll know the three ways to screenshot a website in PHP, which one survives production, and how to do it in a single HTTP call when you don't want Chromium anywhere near your web host.

The three are wkhtmltoimage (an old WebKit binary you drive through a PHP wrapper), headless Chrome (a real browser you launch from PHP and maintain yourself), and a single HTTP call to a screenshot API with no browser on your server at all. They run from least to most hands-off, and each one fits a different job.

How do you take a screenshot of a website in PHP?

The shortest path to a screenshot of a website in PHP is one HTTP request to a screenshot API: send a URL, get back a hosted image, with no browser to install on your host. With ScreenshotRender the whole capture is one line: https://screenshotrender.com/api/v1/screenshot?apiKey=YOUR_API_KEY&url=https://en.wikipedia.org/wiki/PHP&fullPage=true. Call that from any PHP HTTP client and the JSON response carries a hosted image URL at data.screenshot.

If you'd rather keep everything on your own server, the wkhtmltoimage and headless Chrome routes below stay local, at the cost of running and patching a renderer yourself. The rest of this post shows all three, so you can pick by how much infrastructure you want to own.

Why is taking a screenshot harder in PHP than in Node or Python?

Taking a screenshot is harder in PHP than in Node or Python because PHP has no first-class browser binding, so it cannot drive a page in-process the way Puppeteer does in Node. PHP was built to take a request, run, and return a response, not to hold an event loop open and steer a browser across navigations.

That leaves three shapes of solution. You can shell out to an external binary with proc_open or exec and let that binary do the rendering. You can install a wrapper package that launches and talks to headless Chrome for you. Or you can hand the whole job to a remote service and just read back an image URL. Python at least ships Selenium and Playwright bindings; PHP's strongest options all wrap a process or a service, which is the constraint every method below works around.

How do you screenshot a website in PHP with wkhtmltoimage?

You screenshot a website in PHP with wkhtmltoimage by calling a command line tool that renders a URL to an image, usually driven through the knplabs/snappy wrapper. Install the binary on the server, pull the package in with Composer, and the capture is two lines: $image = new Image('/usr/local/bin/wkhtmltoimage'); then $image->generate('https://en.wikipedia.org/wiki/PHP', 'php.jpg');.

What just happened is that Snappy shelled out to wkhtmltoimage, which loaded the URL in a bundled WebKit engine and wrote a JPEG to disk. It is genuinely quick for simple, static pages, and it needs nothing running in the background. The catch is the engine. wkhtmltoimage renders with an old fork of WebKit, and the wkhtmltopdf project is archived and no longer actively maintained. Modern JavaScript frameworks, newer CSS grid and flexbox layouts, and any site behind bot protection tend to come back broken or blank. For an internal invoice or a static report it is fine. For the live web in 2026 it is a gamble.

How do you capture a screenshot with headless Chrome in PHP?

You capture a screenshot with headless Chrome in PHP by launching a real Chromium and driving it, most commonly through the spatie/browsershot or chrome-php/chrome packages. With Browsershot a capture is one fluent call: Browsershot::url('https://en.wikipedia.org/wiki/PHP')->save('php.png');, and a full page version is Browsershot::url($url)->fullPage()->save('php.png');.

Because it drives a real browser, this route renders modern pages correctly: JavaScript runs, web fonts load, and you can wait for a selector before the shot. If you want to skip the package and go raw, you can even shell out to the browser directly with exec('chrome --headless --screenshot=php.png --window-size=1280,720 https://en.wikipedia.org/wiki/PHP');, documented in Chrome's headless mode docs.

The cost is everything around that one call. Browsershot does not bundle a browser; it shells out to Node and Puppeteer, so the server now needs Node, a Puppeteer install, and a Chromium binary you keep patched. You give each concurrent capture enough memory, install the fonts the page expects, and absorb the version drift that turns a green deploy red after an unrelated upgrade. On a box you fully control that is workable. On shared PHP hosting, where exec is often disabled and you cannot install system packages, it is frequently a non-starter.

Don't run Chromium on your web host.

Browsershot means a Node process, a Puppeteer install, and a Chromium binary to patch on every PHP server. ScreenshotRender renders the page for you and returns a hosted image, with cookie banners and ads already stripped. 100 free screenshots a month, no credit card.

Try a render

How do you screenshot a website in PHP with a screenshot API?

You screenshot a website in PHP with a screenshot API by sending the URL to one HTTP endpoint and reading the image URL out of the JSON response, with no browser on your server. The full request is one copy-pasteable line: https://screenshotrender.com/api/v1/screenshot?apiKey=YOUR_API_KEY&url=https://en.wikipedia.org/wiki/PHP&fullPage=true.

From PHP you can fire that with Guzzle in a couple of lines: $res = $client->get('https://screenshotrender.com/api/v1/screenshot', ['query' => $params]); then pull the image URL with $url = json_decode($res->getBody())->data->screenshot;. There is no SDK to install, so a one-off script can lean on plain file_get_contents($endpoint) instead and the same call works from any HTTP client.

The parameters are the whole surface. url is the page to capture, fullPage=true grabs the entire scrollable document instead of the default 1280 by 720 viewport, wait takes a millisecond delay for pages that finish rendering after the initial load, and timeout caps how long a slow page can take. The response also carries the page title, description, and favicon, which is handy if you are building a link preview card.

The other thing you stop doing yourself is cleanup. Cookie consent banners, ad overlays, and chat widgets are removed automatically before every capture, on every plan including the free one, so the image is the page rather than the page plus three popups. Repeat captures of the same URL and options are served from an edge cache, so a dashboard that re-renders the same thumbnails does not pay for them twice.

When does PHP website screenshot capture fail?

PHP website screenshot capture fails in a few predictable ways, and the cause is rarely the PHP code itself.

  • Bot protection. A vanilla headless browser gets served a challenge page on bot-protected sites, so the capture is the challenge, not the site. ScreenshotRender ships Stealth Mode on the Hobby plan and above; our guide to screenshotting Cloudflare-protected sites covers what changes.
  • Lazy loading and JS timing. Content that loads after the first paint, like images that appear on scroll or a view that swaps in late, is missing if you capture too early. A short wait lets the page settle before the shot.
  • Login walls. A URL-only API takes a URL, not a session cookie, so it cannot reach a page behind a sign-in. That is the one case where driving the browser yourself wins, because you can script the login first.
  • Shared-host memory limits. wkhtmltoimage and Chromium are memory-hungry, and a cheap PHP host will kill the process or block exec outright. Moving the render off your host removes the whole class of problem, since nothing heavy runs on the web server.

Most failures are timing or access, not the capture itself. Match the fix to the cause and the image comes back clean.

Common questions about taking screenshots in PHP

How do I take a full page screenshot in PHP?

Capture the whole scrollable document instead of the visible viewport. With Browsershot you chain ->fullPage() before ->save(); with a screenshot API you add fullPage=true to the request. Both stitch the entire page from top to bottom no matter how long it is, while the default capture is just the 1280 by 720 viewport. The mechanics of the scroll-and-stitch are in our guide to screenshotting an entire webpage.

Can I screenshot a website in Laravel?

Yes. Browsershot from Spatie is the most common choice in Laravel because it is a Composer package that drives headless Chrome through Node and Puppeteer. If you would rather not install Chromium and Node on the server, call a screenshot API with Guzzle or the Laravel HTTP client and read the returned image URL from the JSON response.

Is wkhtmltoimage still maintained?

No. The wkhtmltopdf project, which ships wkhtmltoimage, is archived and no longer actively maintained, and it renders with an old fork of WebKit. It is fine for simple static or internal pages, but modern JavaScript frameworks, newer CSS layouts, and bot-protected sites often come back wrong, so it is a risky default for the live web.

How do I screenshot a JavaScript-heavy page in PHP?

Use a real browser. wkhtmltoimage's old WebKit misrenders modern React, Vue, and Svelte pages, so you need headless Chrome through Browsershot or chrome-php, or a screenshot API that runs Chromium for you. Add a short wait so lazy-loaded images and late JavaScript content land before the capture rather than after it.

Do I need to install Chrome to take screenshots in PHP?

Only for the local headless route. Browsershot and chrome-php both need a Chromium binary on the server, and Browsershot also needs Node and Puppeteer. A screenshot API needs no browser on your host at all, since the rendering happens on the service, which is exactly why it works on shared hosting that forbids exec.

The honest takeaway: match the method to the host. For a simple internal page on a server you control, wkhtmltoimage through Snappy is the least to install. For full control over a real browser, Browsershot or chrome-php gives you Chromium and the bill that comes with it. And to turn any public URL into a clean image without putting a browser on your PHP host at all, the single HTTP call is the least to maintain.

Keep reading