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.

To convert HTML to PNG in PHP, render the HTML in a real browser engine and save the browser screenshot. PHP’s imagepng() function only encodes an existing GD image; it does not interpret HTML or CSS. In practice, use a PHP browser controller such as Spatie Browsershot (Puppeteer plus headless Chrome), chrome-php/chrome, or Playwright PHP, then choose whether to capture the viewport, an element, a clipped rectangle, or the full page.

The two-stage conversion pipeline

HTML-to-PNG conversion has two distinct jobs:

  1. Layout and rendering: a browser resolves HTML, CSS, fonts, images, JavaScript, media queries and web components into pixels.
  2. PNG encoding: the rendered pixels are written to a PNG file.

A browser automation library performs the first job and normally calls the browser’s screenshot function for the second. By contrast, PHP’s imagepng() outputs or saves a PNG from a GdImage object that already exists; it is not an HTML renderer.

This distinction explains why a GD-only script cannot reproduce a modern web page with CSS layout, JavaScript, remote fonts or responsive behavior. If you already have pixels in GD, imagepng($image, $path) is appropriate. If you have HTML, start a browser.

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.

Choose a PHP approach

Approach What it provides Best fit Important dependency
Spatie Browsershot A PHP wrapper around Puppeteer and headless Google Chrome; accepts a URL or supplied HTML and saves an image. Laravel or PHP applications that want a concise, high-level API. A compatible Chrome/Chromium installation and the Puppeteer-based companion runtime.
chrome-php/chrome Direct PHP control of Chrome or Chromium, including navigation, waiting, clipping and full-page screenshots. PNG is the documented default. Applications needing lower-level browser control or explicit capture geometry. A runnable Chrome/Chromium binary and a PHP process able to launch or connect to it.
Playwright PHP Browser automation and screenshots across Chromium, Firefox and WebKit. Projects that need to select among browser engines or share Playwright concepts. Install the browser engine your script launches; the browser guide lists the engines.
PHP GD imagepng() Writes a PNG from an existing GD image. Post-processing or generating pixels yourself, not rendering arbitrary HTML. GD extension and an already-created image resource.

There is no meaningful speed ranking here: rendering time depends on page size, JavaScript, network requests, fonts and the browser environment. Select the library whose browser and runtime dependencies you can operate in your deployment.

Prerequisites and deployment checks

  • Use a PHP version supported by the package release you install. Check the package’s current installation documentation rather than assuming a version from an old blog post.
  • Install Chrome or Chromium where the PHP worker runs, or configure the library to use an existing executable or remote browser.
  • Give the worker permission to create a temporary profile and write the destination file.
  • Allow outbound access to every page, stylesheet, image, font and script required by the capture, unless you are rendering self-contained HTML.
  • Set a process timeout longer than the page’s worst-case load time and close browser objects in long-running workers.
  • For Playwright PHP, install the specific engine (Chromium, Firefox or WebKit) that the application launches; installing one engine does not automatically provide the others. See the browser and context guide.

Exact minimum versions and installation commands change with each release. Verify them in the official project documentation before pinning a production image.

Method 1: Spatie Browsershot

Browsershot delegates rendering to Puppeteer and headless Chrome. Its README documents both URL input and an HTML-input route. The following examples show the capture calls; install and configure the current package and browser prerequisites using the official README.

Capture a URL

<?php

require __DIR__ . '/vendor/autoload.php';

use SpatieBrowsershotBrowsershot;

Browsershot::url('https://example.com')
    ->windowSize(1440, 900)
    ->setOption('deviceScaleFactor', 1)
    ->save(__DIR__ . '/example.png');

The resulting file is a PNG screenshot of the configured viewport. A viewport capture does not automatically include content below the fold. Use the library’s full-page option when the complete document is required, and wait for page-specific content before saving when JavaScript populates the page.

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

Render supplied HTML

<?php

use SpatieBrowsershotBrowsershot;

$html = '<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <style>body{font-family:Arial,sans-serif;padding:40px}h1{color:#163a5f}</style>
  </head>
  <body><h1>Invoice preview</h1><p>Rendered by Chrome.</p></body>
</html>';

Browsershot::html($html)
    ->windowSize(1200, 800)
    ->save(__DIR__ . '/invoice.png');

When HTML refers to relative assets, provide a usable base URL or convert required assets to absolute URLs/data URLs. Otherwise the browser may render the text but omit styles, images or fonts.

Method 2: chrome-php/chrome

chrome-php/chrome exposes Chrome or Chromium more directly. Its documentation demonstrates navigation, waiting for navigation and saving a screenshot; PNG is the default format and the API includes clipping and full-page capture.

<?php

require __DIR__ . '/vendor/autoload.php';

use HeadlessChromiumBrowserFactory;

$browserFactory = new BrowserFactory();
$browser = $browserFactory->createBrowser();

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

    // Viewport screenshot (PNG by default).
    $page->screenshot()->saveToFile(__DIR__ . '/viewport.png');

    // Capture the complete document instead:
    $page->screenshot([
        'fullPage' => true,
    ])->saveToFile(__DIR__ . '/full-page.png');

    // Capture a rectangle in CSS pixels:
    $page->screenshot([
        'clip' => [
            'x' => 0,
            'y' => 0,
            'width' => 800,
            'height' => 600,
        ],
    ])->saveToFile(__DIR__ . '/clip.png');
} finally {
    $browser->close();
}

Use a clip when a fixed region is the deliverable, such as a chart card. Use full-page capture for an article or documentation page, but expect a very tall image for long documents. If the page changes after navigation, wait for a selector, an explicit delay or an application-level readiness signal before taking the screenshot.

Method 3: Playwright PHP

Playwright PHP follows the same model: launch a chosen browser, create a context and page, navigate, then call the page screenshot API. Its documentation covers browser and context creation at playwright-php.dev/guide/browser/browsers-and-contexts and screenshot options at the screenshots guide. The cross-language Page API reference is at playwright.dev/docs/api/class-page.

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

Install the current Playwright PHP package and the browser engine selected by your project, then adapt this minimal flow to the package’s current namespace and launcher syntax:

<?php

// Pseudocode shape matching the documented Playwright flow:
$browser = $playwright->chromium->launch();
$page = $browser->newPage([
    'viewport' => ['width' => 1280, 'height' => 900],
]);
$page->goto('https://example.com');
$page->screenshot([
    'path' => __DIR__ . '/playwright.png',
    'fullPage' => true,
]);
$browser->close();

Treat that snippet as the operation order, not a substitute for the package’s installation-specific class names. The official guide for your installed release is authoritative, especially if you choose Firefox or WebKit instead of Chromium.

Controlling what gets captured

Viewport versus full page

A viewport screenshot is predictable in dimensions and useful for social cards or visual regression at a fixed breakpoint. A full-page screenshot includes content below the fold but can become extremely tall and may expose lazy-loading behavior. Trigger lazy-loaded images or scroll through the page before capture when the page requires it.

Element or clipped region

Element screenshots are preferable for a single invoice, chart or component. If your chosen PHP library does not expose an element helper directly, locate the element in browser code and pass its bounding rectangle as a clip. Record the viewport and device scale factor so repeated captures have consistent pixel dimensions.

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

CSS, fonts and assets

  • Use absolute asset URLs or a correct document base URL.
  • Wait for web fonts before capturing; otherwise text can reflow after the screenshot.
  • Provide a deterministic viewport, timezone, locale and color-scheme when visual consistency matters.
  • Authenticate private pages with the library’s supported cookies, headers or session setup rather than embedding secrets in public HTML.

Common failures and fixes

Symptom Likely cause Fix
“Chrome executable not found” The browser is absent or the worker cannot see its path. Install Chrome/Chromium in the runtime image and configure the executable path according to the package documentation.
Blank or partially styled image Relative assets, blocked network requests or capture before rendering completes. Use absolute URLs, check outbound access, wait for a readiness selector and inspect browser logs.
JavaScript content missing The screenshot occurs immediately after navigation. Wait for navigation plus the application’s loaded selector, network idle condition or a short, measured delay.
Fonts differ from the browser preview Web fonts have not loaded, or the server lacks the font files. Self-host or permit the font requests and wait for font readiness before capture.
Only the visible top portion appears The code captured the viewport. Enable the library’s full-page option or capture the required element/clip explicitly.
Permission or write errors The PHP worker cannot create the temporary profile or destination file. Grant least-privilege write access to dedicated temporary and output directories.
Timeouts on long pages Heavy scripts, slow third-party resources or never-ending requests. Set a bounded timeout, block unnecessary resources where supported, and wait on a meaningful selector instead of an arbitrary long sleep.
Different output on each run Animations, rotating content, ads, current time or responsive layout. Freeze animation with CSS, set fixed viewport/locale/timezone, and remove nondeterministic content in a capture-specific stylesheet.

Performance, reliability and cost considerations

Launching a browser for every request is expensive in CPU and memory. A queue worker, browser reuse strategy or remote browser can reduce startup overhead, but long-lived browsers must be recycled to prevent leaks and stale state. Keep each job isolated with a fresh context or profile when cookies and local storage must not cross tenants.

Cache captures when the source and rendering inputs have not changed. Include the URL or HTML hash, viewport, device scale factor, browser engine, authentication state and relevant options in the cache key. For reliable jobs, persist the original HTML or URL, capture settings, browser logs and failure reason so a retry is diagnosable rather than blind.

Do not claim that a successful HTTP response means a correct image. Validate the output file exists, has nonzero size, opens as PNG and, where practical, contains an expected marker such as a page title. Treat bot challenges, authentication redirects and application error pages as content-validation failures even if Chrome returned status 200.

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

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. It accepts a URL and returns PNG, JPEG, WebP or PDF, handling the browser infrastructure for you. Before capture it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients.

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

For a one-call PNG capture, follow the parameter details in the ScreenshotNeo documentation:

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,
)
r.raise_for_status()
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}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

ScreenshotNeo also supports full-page capture with lazy images loaded, CSS-selector element capture, dark mode, 12 device presets plus custom viewports, retina scale, PDF paper and page-range controls, custom CSS and JavaScript, pre-capture clicks, selector waits, delays or network-idle waits, blocking ads/trackers/requests/resource types, custom headers/cookies/user agents and Authorization, timezone and geolocation, transparent backgrounds, resizing, selectable cache TTLs, signed links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API and an OpenAPI specification. Parameter names used by other screenshot APIs also work, easing migration.

Plans are Free (1,000 shots per month, no card), Starter ($5 for 3,000), Growth ($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 included on every plan. Sign up for the free plan to get 1,000 screenshots a month without a card.

Practical decision checklist

  • Choose Browsershot when a high-level PHP wrapper and Puppeteer/Chrome workflow fit your application.
  • Choose chrome-php/chrome when direct Chrome control, clipping or full-page options are central.
  • Choose Playwright PHP when your project needs Chromium, Firefox or WebKit selection and the Playwright ecosystem.
  • Choose GD only when the image pixels already exist or you are drawing them yourself.
  • Choose ScreenshotNeo when you want an HTTP call, built-in cleanup of consent UI, non-billing for failed or blocked captures, or MCP access for AI agents.

Frequently Asked Questions

Can PHP convert HTML to PNG without Chrome?

Not for general modern HTML and CSS. A browser engine is the practical route; GD’s imagepng() only writes pixels already present in a GD image.

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

Should I use a viewport or full-page screenshot?

Use a viewport for fixed-size cards and visual tests; use full-page capture when content below the fold is part of the deliverable.

Why is my screenshot missing CSS or images?

Relative URLs, blocked requests, unavailable fonts or an early capture are the usual causes. Use resolvable asset URLs and wait for the page’s readiness condition.

Does ScreenshotNeo return only PNG?

No. Its endpoint can return PNG, JPEG, WebP or PDF; the requested format and options are documented at https://screenshotneo.com/docs/.

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.

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