html2img/html2img-php

Official PHP SDK for the html2img HTML-to-image API: render HTML or CSS to PNG, screenshot live URLs, and generate images from templates, built on Guzzle.

Maintainers

Package info

github.com/html2img/html2img-php

Homepage

Documentation

pkg:composer/html2img/html2img-php

Statistics

Installs: 9

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-06-07 13:58 UTC

This package is auto-updated.

Last update: 2026-06-07 14:49:06 UTC


README

html2img — HTML to image API, rendered in real Chrome

html2img PHP client

Packagist Version PHP Version Total Downloads License

The official PHP client for the html2img.com API. Turn HTML and CSS into images, capture screenshots of live URLs, and render named templates, all returning a typed response object.

Every render runs in real Chrome, so flexbox, grid, custom properties, web fonts and inline JavaScript behave exactly as they do in the browser. The package is framework-agnostic and built on Guzzle, so it works in plain PHP and inside any framework. The full API reference lives in the documentation.

What you can build

Browse the full template library, or try the no-signup browser tools to see the output before you write any code.

Requirements

  • PHP 8.3 or newer
  • A html2img API key, issued per account from your dashboard

Installation

composer require html2img/html2img-php

Quick start

use Html2img\Html2imgClient;
use Html2img\Request\HtmlRequest;

$client = new Html2imgClient('your-api-key');

$response = $client->html(new HtmlRequest(
    html: '<!doctype html><html><body><h1>Hello</h1></body></html>',
    width: 1200,
    height: 630,
));

echo $response->url; // https://i.html2img.com/abc123def456.png

The API returns a JSON envelope containing the CDN URL of the generated image, not the raw bytes, so you can cache and re-serve it from your own infrastructure. New to the API? Start with the getting started guide.

Configuration

The constructor takes the API key plus optional overrides:

use Html2img\Html2imgClient;

$client = new Html2imgClient(
    apiKey: 'your-api-key',
    baseUri: 'https://app.html2img.com', // default
    timeout: 35.0,                        // seconds, default
);

Authentication is sent on every request as the X-API-Key header. See the authentication docs for issuing and rotating keys.

Injecting your own Guzzle client

Pass a pre-configured GuzzleHttp\ClientInterface to reuse your own middleware, retry strategy or logging. The SDK still adds the X-API-Key, Accept and Content-Type headers on every request.

use GuzzleHttp\Client;
use Html2img\Html2imgClient;

$guzzle = new Client([
    'base_uri' => 'https://app.html2img.com',
    'timeout' => 60,
    // your own handler stack, middleware, proxy settings, etc.
]);

$client = new Html2imgClient('your-api-key', httpClient: $guzzle);

Usage

Render HTML

POST /api/html. Send a complete HTML document and get back an image of the rendered result. Inline your CSS in a <style> block, or reference remote stylesheets and web fonts via <link> tags in the document head. See the html parameter docs for the full input.

use Html2img\Request\HtmlRequest;

$response = $client->html(new HtmlRequest(
    html: $document,
    css: 'body { background: #0f172a; color: #fff; }', // injected after load
    width: 794,
    fullpage: true,
    dpi: 2,          // retina
));

Capture a screenshot

POST /api/screenshot. Fetch a public URL in a real browser and capture it. Use selector to crop to a single element, and css to hide cookie banners or chat widgets before the capture. See the url parameter docs.

use Html2img\Request\ScreenshotRequest;

$response = $client->screenshot(new ScreenshotRequest(
    url: 'https://example.com',
    width: 1200,
    height: 630,
    selector: '#hero',
    css: '.cookie-banner, .intercom-launcher { display: none !important; }',
    dpi: 2,
));

Render a template

POST /api/v1/templates/{slug}. Render one of your named templates from a JSON data payload. The data is validated server-side per template. Browse the templates to find a slug.

$response = $client->template('invoice', [
    'number' => 1042,
    'amount' => '$240.00',
    'due_date' => '2026-07-01',
]);

echo $response->template; // invoice
echo $response->url;

Options

Both HtmlRequest and ScreenshotRequest accept the following. Any option left null is omitted from the request, so the server applies its own default. The complete reference is in the parameter docs.

Option Type Notes
css string Extra CSS injected after the page loads.
width int Viewport width in CSS pixels (1 to 5000).
height int Viewport height in CSS pixels (1 to 5000). Ignored when fullpage is true.
fullpage bool Capture the full scroll length instead of the viewport.
dpi int Device pixel ratio, 1 to 4. Use 2 for retina.
webhookUrl string Switch to async delivery (see below).
msDelay int Wait this many milliseconds after load before capturing (1 to 5000).
waitForSelector string Wait until this CSS selector appears before capturing.

ScreenshotRequest also accepts selector (string) to crop the capture to a single element. HtmlRequest does not, since you control the markup.

Custom fonts are loaded by referencing them with <link> tags in your HTML document head, or by linking a web font from your captured page.

The response

Every method returns a readonly Html2img\Response\RenderResponse:

$response->success;          // bool
$response->id;               // string|null, the render id
$response->url;              // string|null, the CDN URL of the image
$response->creditsRemaining; // int|null, credits left after this call
$response->status;           // string|null, "processing" for async jobs
$response->message;          // string|null
$response->template;         // string|null, the template slug, when applicable
$response->isProcessing();   // bool
$response->raw();            // array, the full decoded JSON payload

Asynchronous delivery

Synchronous requests have a 30 second budget. For captures likely to exceed it, pass a webhookUrl. The API responds immediately with status: "processing" and url: null, then POSTs the final image URL to your endpoint once rendering finishes. See the webhook_url docs.

$response = $client->screenshot(new ScreenshotRequest(
    url: 'https://example.com/long-report',
    fullpage: true,
    webhookUrl: 'https://your-app.example.com/hooks/html2img',
));

if ($response->isProcessing()) {
    // The final URL will arrive at your webhook, not on this response.
}

Error handling

Every failure throws an Html2img\Exception\Html2imgException. Catch that single type to handle any error, or catch a specific subclass. No raw Guzzle exception escapes the client.

use Html2img\Exception\Html2imgException;
use Html2img\Exception\ValidationException;
use Html2img\Exception\InsufficientCreditsException;

try {
    $response = $client->html(new HtmlRequest(html: $document));
} catch (ValidationException $e) {
    // 400 or 422: inspect the per-field messages
    foreach ($e->details() as $field => $messages) {
        // ...
    }
} catch (InsufficientCreditsException $e) {
    // 402: out of credits
    $left = $e->creditsRemaining();
} catch (Html2imgException $e) {
    // anything else
    $e->statusCode(); // int|null
    $e->errorCode();  // string|null, the API "code" field
    $e->payload();    // array, the decoded body
}
Exception When
AuthenticationException 401, missing or invalid API key.
InsufficientCreditsException 402, no credits remaining.
NotSubscribedException 403, no active subscription.
NotFoundException 404, for example an unknown template slug.
ValidationException 400 or 422, with details() per field.
RateLimitException 429, rate or quota exceeded.
TimeoutException 504, the synchronous render budget was exceeded.
ServerException 5xx, an unexpected renderer error.
ConnectionException the request never reached a response.
Html2imgException base type for all of the above.

Other languages

Anything that can make an HTTP request works with the API. There are worked guides for Laravel, Ruby on Rails, Python, JavaScript and Node.js, React and Vue.

Development

This package uses ddev for a containerised PHP environment. It is optional, and you can use vanilla PHP or whatever you use for local dev if you prefer.

ddev composer install
ddev exec vendor/bin/pest      # tests
ddev exec vendor/bin/phpstan analyse
ddev exec vendor/bin/pint --test

Links

Website · Documentation · Templates · Tools · Features · Comparisons · Articles · Pricing

Licence

MIT. See LICENSE.