HTML to Image in PHP

Render HTML to a PNG from any PHP script using cURL or Guzzle.

Best for: any PHP project without a framework, plus services where you want to keep dependencies light. Use the Laravel guide if you are on Laravel and want the Http facade and queue integration.

Worked examples for converting HTML to images and taking screenshots from PHP, including Guzzle, native cURL and a service-class pattern.

Installation

First, make sure you have PHP’s cURL extension enabled. You can use Composer to manage your dependencies, but it’s not required for these examples.

API Response Format

Every successful request returns a JSON body with a url pointing to the generated image:

{
    "success": true,
    "credits_remaining": 95,
    "id": "abc123",
    "url": "https://i.html2img.com/abc123.png"
}

You can either use the url directly, or download the image from it if you need a local copy.

HTML to Image Example

This example shows how to convert HTML content to an image using PHP’s cURL:

<?php

function htmlToImage($html, $css = '') {
    $apiKey = 'your-api-key';
    $endpoint = 'https://app.html2img.com/api/html';

    $data = [
        'html' => $html,
        'css' => $css,
        'width' => 800,
        'height' => 600,
    ];

    $ch = curl_init($endpoint);

    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => [
            'Content-Type: application/json',
            'X-API-Key: ' . $apiKey,
        ],
        CURLOPT_POSTFIELDS => json_encode($data),
    ]);

    $response = curl_exec($ch);
    $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

    if (curl_errno($ch)) {
        throw new Exception('cURL Error: ' . curl_error($ch));
    }

    curl_close($ch);

    $result = json_decode($response, true);

    if ($statusCode !== 200 || empty($result['success'])) {
        throw new Exception('API Error: ' . ($result['message'] ?? 'Unknown error'));
    }

    // Returns: ['success' => true, 'credits_remaining' => 95, 'id' => '...', 'url' => '...']
    return $result;
}

function downloadImage($url, $filename) {
    file_put_contents($filename, file_get_contents($url));
    return $filename;
}

// Example usage
try {
    $html = '
        <div style="padding: 20px; background: #f0f0f0;">
            <h1>Hello, World!</h1>
            <p>This is a test image generated using HTML to Image API.</p>
        </div>
    ';

    $css = '
        h1 { color: #2563eb; }
        p { color: #4b5563; }
    ';

    $result = htmlToImage($html, $css);
    echo "Image available at: " . $result['url'] . "\n";
    echo "Credits remaining: " . $result['credits_remaining'] . "\n";

    // Optionally save a local copy
    $filename = 'output-' . time() . '.png';
    downloadImage($result['url'], $filename);
    echo "Image saved locally as: " . $filename;
} catch (Exception $e) {
    echo "Error: " . $e->getMessage();
}

Screenshot API Example

This example demonstrates how to take a screenshot of a webpage:

<?php

function takeScreenshot($url, $options = []) {
    $apiKey = 'your-api-key';
    $endpoint = 'https://app.html2img.com/api/screenshot';

    $defaultOptions = [
        'width' => 1920,
        'height' => 1080,
        'dpi' => 1,
        'fullpage' => true,
    ];

    $options = array_merge($defaultOptions, $options);
    $data = array_merge(['url' => $url], $options);

    $ch = curl_init($endpoint);

    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => [
            'Content-Type: application/json',
            'X-API-Key: ' . $apiKey,
        ],
        CURLOPT_POSTFIELDS => json_encode($data),
    ]);

    $response = curl_exec($ch);
    $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

    if (curl_errno($ch)) {
        throw new Exception('cURL Error: ' . curl_error($ch));
    }

    curl_close($ch);

    $result = json_decode($response, true);

    if ($statusCode !== 200 || empty($result['success'])) {
        throw new Exception('API Error: ' . ($result['message'] ?? 'Unknown error'));
    }

    return $result;
}

// Example usage
try {
    $options = [
        'width' => 1200,
        'height' => 800,
        'fullpage' => true,
        'dpi' => 2,
    ];

    $result = takeScreenshot('https://example.com', $options);
    echo "Screenshot available at: " . $result['url'];
} catch (Exception $e) {
    echo "Error: " . $e->getMessage();
}

Advanced Usage

Handling Timeouts

For large pages or complex HTML, you might need to increase the timeout:

// Set a longer timeout (30 seconds)
curl_setopt($ch, CURLOPT_TIMEOUT, 30);

Error Handling

Here’s a more detailed error handling example:

function handleApiError($response, $statusCode) {
    $error = json_decode($response, true);

    switch ($statusCode) {
        case 401:
            throw new Exception('Unauthorized: Invalid API key');
        case 402:
            throw new Exception('Payment Required: Please check your subscription');
        case 429:
            throw new Exception('Too Many Requests: Rate limit exceeded');
        default:
            throw new Exception('API Error: ' . ($error['message'] ?? 'Unknown error'));
    }
}

Saving with Custom Filenames

If you’re downloading generated images locally, you can customize the output filename:

function generateFilename($prefix = 'image', $extension = 'png') {
    $timestamp = time();
    $random = substr(md5(uniqid()), 0, 6);
    return sprintf('%s-%s-%s.%s', $prefix, $timestamp, $random, $extension);
}

$filename = generateFilename('my-screenshot');
file_put_contents($filename, file_get_contents($result['url']));

Remember to replace ‘your-api-key’ with your actual API key and handle the API key securely using environment variables.

Best Practices

  1. API Key Security
  • Store your API key in environment variables
  • Never commit API keys to version control
  • Use different API keys for development and production
$apiKey = getenv('HTML2IMG_API_KEY') ?: die('API key not found');
  1. Error Handling
  • Always implement proper error handling
  • Log errors for debugging
  • Provide meaningful error messages to users
  1. Resource Management
  • Close cURL handles properly
  • Implement proper timeout handling
  • Consider caching the returned url rather than re-requesting the same image
  1. Performance
  • The returned url is hosted by HTML to Image - reference it directly in your app rather than re-downloading when possible
  • Use appropriate image dimensions
  • Optimize HTML/CSS before conversion

These examples are for demonstration. In production, add proper error handling, logging and key rotation. See the authentication guide.

Common patterns

Guzzle plus a service class

namespace App\Services;

use GuzzleHttp\Client;

class Html2ImgClient
{
    private Client $client;

    public function __construct(string $apiKey)
    {
        $this->client = new Client([
            'base_uri' => 'https://app.html2img.com/api/',
            'headers' => ['X-API-Key' => $apiKey, 'Content-Type' => 'application/json'],
        ]);
    }

    public function renderHtml(string $html, array $options = []): string
    {
        $response = $this->client->post('html', ['json' => array_merge(['html' => $html], $options)]);
        return json_decode($response->getBody()->getContents(), true)['url'];
    }

    public function screenshot(string $url, array $options = []): string
    {
        $response = $this->client->post('screenshot', ['json' => array_merge(['url' => $url], $options)]);
        return json_decode($response->getBody()->getContents(), true)['url'];
    }
}

Inject Html2ImgClient into your controllers or jobs and call renderHtml() or screenshot() from anywhere in the app.

Templates in PHP

Skip the HTML step entirely with a named template. The same pattern applies to all 25 templates; here is the Invoice Image template:

$ch = curl_init('https://app.html2img.com/api/v1/templates/invoice-image');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => ['X-API-Key: ' . getenv('HTML2IMG_API_KEY'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode([
        'invoice_number' => 'INV-2026-0042',
        'business_name' => 'Coastline Coffee Co',
        'client_name' => 'Riverside Bakery',
        'items' => [['description' => 'Wholesale beans', 'quantity' => '50', 'unit_price' => '$15.00', 'amount' => '$750.00']],
        'total' => '$750.00',
    ]),
]);
$url = json_decode(curl_exec($ch), true)['url'];

The returned url is hosted on i.html2img.com.