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
- 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');
- Error Handling
- Always implement proper error handling
- Log errors for debugging
- Provide meaningful error messages to users
- Resource Management
- Close cURL handles properly
- Implement proper timeout handling
- Consider caching the returned
urlrather than re-requesting the same image
- Performance
- The returned
urlis 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.