How to Convert an HTML Invoice or Receipt to an Image
Render an invoice or receipt as a PNG. Useful for transactional emails, customer dashboards and accounting integrations.
Want it faster? Use the Invoice Image template and skip the markup. Send line items, totals and party details as JSON and get a 1240x1754 A4 PNG back.
HTML Content
<div class="receipt">
<div class="header">
<h1>INVOICE</h1>
<p class="invoice-number">#INV-2025-001</p>
</div>
<div class="business-details">
<h2>ACME Corporation</h2>
<p>123 Business Street</p>
<p>San Francisco, CA 94105</p>
<p>[email protected]</p>
</div>
<div class="invoice-details">
<div class="date">
<strong>Date:</strong> January 8, 2025
</div>
<div class="due-date">
<strong>Due Date:</strong> February 8, 2025
</div>
</div>
<table class="items">
<thead>
<tr>
<th>Item</th>
<th>Quantity</th>
<th>Price</th>
<th>Total</th>
</tr>
</thead>
<tbody>
<tr>
<td>Premium Subscription</td>
<td>1</td>
<td>$99.00</td>
<td>$99.00</td>
</tr>
<tr>
<td>Additional Users</td>
<td>5</td>
<td>$10.00</td>
<td>$50.00</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3">Subtotal</td>
<td>$149.00</td>
</tr>
<tr>
<td colspan="3">Tax (10%)</td>
<td>$14.90</td>
</tr>
<tr class="total">
<td colspan="3">Total</td>
<td>$163.90</td>
</tr>
</tfoot>
</table>
<div class="footer">
<p>Thank you for your business!</p>
<div class="payment-info">
<p><strong>Payment Terms:</strong> Net 30</p>
<p><strong>Bank Details:</strong> ACME Bank - ACC: 1234567890</p>
</div>
</div>
</div>
CSS Styles
body {
margin: 0;
padding: 24px;
background: white;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
color: #333;
}
.receipt {
max-width: 800px;
margin: 0 auto;
background: white;
padding: 40px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
}
.header {
text-align: center;
margin-bottom: 40px;
}
.header h1 {
margin: 0;
color: #2c3e50;
font-size: 32px;
}
.invoice-number {
color: #7f8c8d;
font-size: 16px;
margin: 8px 0 0;
}
.business-details {
margin-bottom: 30px;
}
.business-details h2 {
color: #2c3e50;
margin: 0 0 8px;
}
.business-details p {
margin: 4px 0;
color: #666;
}
.invoice-details {
display: flex;
justify-content: space-between;
margin-bottom: 30px;
}
table.items {
width: 100%;
border-collapse: collapse;
margin: 30px 0;
}
table.items th,
table.items td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #eee;
}
table.items th {
background: #f8f9fa;
font-weight: 600;
}
table.items tfoot tr {
border-top: 2px solid #eee;
}
table.items tfoot tr.total {
font-weight: bold;
font-size: 1.1em;
color: #2c3e50;
}
.footer {
margin-top: 40px;
text-align: center;
color: #666;
}
.payment-info {
margin-top: 20px;
font-size: 14px;
}
.payment-info p {
margin: 4px 0;
}
API Request
POST https://app.html2img.com/api/html
{
"html": "<div class=\"receipt\"><div class=\"header\"><h1>INVOICE</h1><p class=\"invoice-number\">#INV-2025-001</p></div><div class=\"business-details\"><h2>ACME Corporation</h2><p>123 Business Street</p><p>San Francisco, CA 94105</p><p>[email protected]</p></div><div class=\"invoice-details\"><div class=\"date\"><strong>Date:</strong> January 8, 2025</div><div class=\"due-date\"><strong>Due Date:</strong> February 8, 2025</div></div><table class=\"items\"><thead><tr><th>Item</th><th>Quantity</th><th>Price</th><th>Total</th></tr></thead><tbody><tr><td>Premium Subscription</td><td>1</td><td>$99.00</td><td>$99.00</td></tr><tr><td>Additional Users</td><td>5</td><td>$10.00</td><td>$50.00</td></tr></tbody><tfoot><tr><td colspan=\"3\">Subtotal</td><td>$149.00</td></tr><tr><td colspan=\"3\">Tax (10%)</td><td>$14.90</td></tr><tr class=\"total\"><td colspan=\"3\">Total</td><td>$163.90</td></tr></tfoot></table><div class=\"footer\"><p>Thank you for your business!</p><div class=\"payment-info\"><p><strong>Payment Terms:</strong> Net 30</p><p><strong>Bank Details:</strong> ACME Bank - ACC: 1234567890</p></div></div></div>",
"width": 900,
"height": 815,
"css": "body{margin:0;padding:0;background:white;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,sans-serif;color:#333}.receipt{max-width:800px;margin:0 auto;background:white;padding:40px;box-shadow:0 1px 4px rgba(0,0,0,0.1)}.header{text-align:center;margin-bottom:40px}.header h1{margin:0;color:#2c3e50;font-size:32px}.invoice-number{color:#7f8c8d;font-size:16px;margin:8px 0 0}.business-details{margin-bottom:30px}.business-details h2{color:#2c3e50;margin:0 0 8px}.business-details p{margin:4px 0;color:#666}.invoice-details{display:flex;justify-content:space-between;margin-bottom:30px}table.items{width:100%;border-collapse:collapse;margin:30px 0}table.items th,table.items td{padding:12px;text-align:left;border-bottom:1px solid #eee}table.items th{background:#f8f9fa;font-weight:600}table.items tfoot tr{border-top:2px solid #eee}table.items tfoot tr.total{font-weight:bold;font-size:1.1em;color:#2c3e50}.footer{margin-top:40px;text-align:center;color:#666}.payment-info{margin-top:20px;font-size:14px}.payment-info p{margin:4px 0}"
}
Update the invoice details, company information, and styling to match your branding.
How it Works
- Clean, professional layout using flexbox and CSS Grid
- Responsive table design for item listing
- Subtle shadows and borders for visual hierarchy
- System fonts ensure consistent rendering across platforms
For invoices with many items, set fullpage to true so the rendered PNG matches the content height.
Code in other languages
PHP (Laravel)
$response = Http::withHeaders(['X-API-Key' => env('HTML2IMG_API_KEY')])
->post('https://app.html2img.com/api/html', [
'html' => view('invoices.show', compact('invoice'))->render(),
'css' => $invoiceCss,
'width' => 900,
'height' => 815,
]);
$url = $response->json('url');
Node.js
const response = await fetch('https://app.html2img.com/api/html', {
method: 'POST',
headers: { 'X-API-Key': process.env.HTML2IMG_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ html: invoiceHtml, css: invoiceCss, width: 900, height: 815 }),
});
const { url } = await response.json();
Python
import os, requests
response = requests.post(
'https://app.html2img.com/api/html',
headers={'X-API-Key': os.environ['HTML2IMG_API_KEY']},
json={'html': invoice_html, 'css': invoice_css, 'width': 900, 'height': 815},
)
url = response.json()['url']
Common pitfalls
- Currency formatting drifts. Pre-format every monetary string to the buyer’s locale before sending. The renderer does not localize.
- Long line item descriptions wrap awkwardly. Cap descriptions at 80 characters or split across two rows.
- Tax label localization. Use a per-customer string (“VAT (20%)”, “GST (10%)”, “Sales Tax”) so the buyer sees the right wording.