Generate Invoice Preview Images from HTML in an Indian Billing App
Render invoice data as HTML for an in-app preview, then capture an image when needed. Keep visual previews separate from GST e-invoice registration.
To generate an invoice preview image from HTML, build the invoice from structured data, render it in a browser or app web view, wait for fonts and images to load, then capture the rendered page or invoice element as PNG, JPEG, or WebP. Keep the image capture step separate from invoice creation and from GST e-invoice registration: an HTML preview does not submit invoice particulars to an Invoice Registration Portal (IRP), produce an Invoice Reference Number (IRN), or create the IRP-signed JSON and QR code.
A reliable architecture is invoice record → HTML template → browser/web view → optional raster image. Reuse the checked invoice record for display and any required registration workflow. Treat the preview as a presentation artifact, not as proof of tax compliance.
1. Separate the invoice record, preview, and registration flow
Store invoice fields in a structured model and render that model into HTML. This keeps the displayed values tied to the underlying record and allows the same data to feed separate output or registration steps. This is an implementation recommendation based on the fact that rendering and IRP registration are distinct workflows.
For applicable transactions, the CGST Act and Rules describe invoice particulars such as supplier identity and GSTIN, a consecutive invoice serial number and date, recipient particulars as applicable, description, quantity, value, and tax charged. A template can display fields, but its appearance alone does not establish that every requirement is met; applicability depends on the transaction and rules in force. See CGST Act section 31 and CGST Rules Rule 46.
For a notified class of registered persons, Rule 48(4) describes preparing an invoice with specified FORM GST INV-01 particulars and obtaining an IRN through the common portal. Rule 48(5) addresses invoices issued by persons subject to that sub-rule in another manner. Do not assume every billing-app user is subject to this e-invoice process; check current official requirements for the supplier and transaction. Read Rule 48.
2. Render a responsive HTML invoice
The following minimal example creates a preview from data. In a real app, populate the model from your validated invoice record, escape untrusted values, and apply your own print and screen styles.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Invoice preview</title>
<style>
* { box-sizing: border-box; }
body { margin: 0; padding: 24px; background: #f2f4f7; color: #17202a;
font: 14px/1.5 system-ui, sans-serif; }
.invoice { max-width: 780px; margin: auto; padding: 32px; background: white; }
.row { display: flex; justify-content: space-between; gap: 24px; }
table { width: 100%; margin-top: 24px; border-collapse: collapse; }
th, td { padding: 10px 8px; border-bottom: 1px solid #dfe3e8; text-align: left; }
.number { text-align: right; }
@media print { body { padding: 0; background: white; } .invoice { max-width: none; } }
</style>
</head>
<body>
<main class="invoice">
<div class="row">
<section><strong>Example Supplier Pvt Ltd</strong><br>
Supplier address<br>GSTIN: 29ABCDE1234F1Z5</section>
<section>Invoice: INV-2026-0042<br>Date: 2026-10-04<br>
Bill to: Example Customer</section>
</div>
<table>
<thead><tr><th>Description</th><th>Qty</th>
<th class="number">Taxable value</th><th class="number">Tax</th></tr></thead>
<tbody><tr><td>Consulting service</td><td>2</td>
<td class="number">₹10,000.00</td><td class="number">₹1,800.00</td></tr></tbody>
</table>
<p class="number"><strong>Total: ₹11,800.00</strong></p>
</main>
</body>
</html>
The values above are illustrative. Avoid constructing markup by concatenating raw user input: escape text and validate any URLs or styles that can enter the template. Keep calculations and tax decisions in application logic; the template should present prepared values.
3. Display it in a browser or app web view
For an interactive preview, show the HTML in the app’s browser surface or embedded web view. If the invoice is long, let the document scroll and provide a separate capture action. If your app needs a single image, decide whether the artifact should represent the whole invoice or only the visible viewport.
- Responsive preview: use a fluid layout for the on-screen view, and a fixed page width or print stylesheet for document-like output.
- Long invoices: test tables that span pages, repeated headers, and totals that might otherwise be separated from their items.
- Fonts and assets: wait until custom fonts and images are ready before capture. Provide a fallback font and handle failed asset loads.
- Small screens: distinguish the readable mobile preview from the print or export layout. A wide invoice may be better viewed at document width with horizontal scrolling or as paginated output.
- Security: render trusted templates, escape invoice values, and avoid injecting arbitrary invoice HTML or scripts.
Browser and web-view behavior can differ by platform and version. The research sources do not establish a particular browser engine, capture library, fidelity guarantee, or best mobile framework, so evaluate the options in the target app rather than assuming identical rendering.
4. Capture the rendered invoice as an image
Use the capture mechanism available in your app’s browser or web-view stack. A sound capture sequence is:
- Load the invoice HTML and its styles.
- Wait for document readiness, then explicitly wait for fonts and required images.
- Choose full-document capture or capture a specific invoice element.
- Set output format, viewport or page dimensions, and pixel scale.
- Capture and inspect the resulting image for clipped content, missing assets, and unreadable text.
- Store the image only if the product needs a raster artifact; otherwise keep the HTML preview or produce a document output appropriate to the workflow.
Capture APIs vary, so adapt the pseudocode below to the chosen browser or web-view library:
await page.goto(invoicePreviewUrl, { waitUntil: "networkidle" });
await page.evaluate(() => document.fonts.ready);
await page.locator(".invoice img").evaluateAll(images =>
Promise.all(images.map(img => img.decode().catch(() => undefined)))
);
await page.locator(".invoice").screenshot({ path: "invoice-preview.png" });
This is an illustrative browser-automation pattern, not a claim that a specific library is required or that every platform supports the same methods. If your HTML is generated in memory rather than hosted at a URL, use the target library’s HTML/content loading method and apply the same readiness checks.
Choose the output deliberately
| Need | Suitable output | Check |
|---|---|---|
| Interactive in-app display | HTML in browser/web view | Responsive layout, navigation, and accessibility |
| Thumbnail, messaging attachment, or image artifact | PNG, JPEG, or WebP snapshot | Full content, readable scale, file size, and crop |
| Print-oriented invoice document | PDF or the applicable official output | Pagination, paper size, margins, and required data |
A vendor documents an API pattern with an HTML invoice preview endpoint and a separate PDF output. That is an example of separating preview and document outputs, not a benchmark or endorsement. See the OptoSoft API catalog.
5. Keep GST e-invoice registration separate
For a person and transaction subject to the e-invoice rules, the registration path includes reporting specified invoice particulars to an IRP. GSTN says a successful IRP registration returns signed e-invoice JSON containing the IRN and QR code. GSTN also describes converting the signed JSON to PDF for printing. See GSTN’s e-invoicing FAQs.
Do not create a decorative or locally generated QR code and label it the official signed e-invoice QR. IRIS IRP describes the standard B2B QR code as digitally signed and carrying selected invoice information, the IRN, and generation date. Confirm current applicability and operational guidance against official sources; thresholds, exclusions, notifications, and portal instructions can change. IRIS IRP portal information.
6. Or skip the browser setup
If the HTML preview is available at a URL, ScreenshotNeo can return a screenshot in one GET request. The API supports PNG, JPEG, WebP, or PDF output; see the ScreenshotNeo API docs for parameters and configuration.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://your-app.example/invoices/INV-2026-0042/preview -o invoice-preview.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={
"access_key": "YOUR_API_KEY",
"url": "https://your-app.example/invoices/INV-2026-0042/preview",
},
timeout=90,
)
r.raise_for_status()
open("invoice-preview.webp", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://your-app.example/invoices/INV-2026-0042/preview'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('invoice-preview.webp', res);
Use an authenticated, shareable preview URL only if your access model permits it; never put a customer’s private invoice behind a public URL merely to capture it. ScreenshotNeo can accept custom headers and cookies, and signed links are available for public image tags. Its consent handling accepts cookie banners like a visitor and removes 60+ known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. An MCP server provides take_screenshot, get_page_info, and capture_pdf for AI agents. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000. These are general service facts; review the docs and protect sensitive invoice access in your own application.
Sign up for 1,000 free screenshots a month, with no card required.
7. Performance, reliability, and cost considerations
- Capture only when needed: generating an image for every view can add work and storage. Create or refresh a raster preview when a downstream feature needs one.
- Control image dimensions: high pixel scale improves detail but increases output size and processing. Pick dimensions based on the display or export use.
- Cache with a clear key: if invoice data or template changes, an old image must not be shown as current. Key cached output to the invoice version and rendering options, and define invalidation behavior.
- Make retries safe: distinguish transient page-load failures from invalid invoice data. Retry capture where appropriate without duplicating invoice issuance or registration actions.
- Handle partial readiness: external fonts, logos, or remote assets may fail or load slowly. Set bounded waits and show a useful failure state rather than silently storing a misleading image.
- Measure in your app: compare HTML display, raster capture, and PDF generation against your actual devices, templates, and data. The available sources provide no comparative rendering benchmarks or capture-cost figures.
- Protect financial data: use access controls, avoid logging full invoice payloads unnecessarily, and apply suitable retention and deletion rules to image artifacts.
8. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Image is blank or mostly empty | Capture ran before the document or route finished rendering | Wait for the invoice element and required data, then wait for fonts and images before capture. |
| Logo or custom font is missing | Asset URL is inaccessible, blocked, or not ready | Check network access and asset permissions; wait for font readiness and image decode; provide fallbacks. |
| Bottom rows or totals are clipped | Only the viewport was captured, or the capture height was constrained | Use full-page capture or capture the invoice element; inspect long-content behavior. |
| Text is tiny or blurry | Capture dimensions or scale do not match the intended display | Set a suitable viewport and pixel scale, then verify at the actual rendered size. |
| Layout differs between preview and export | Responsive, print, and capture viewports apply different CSS | Define the intended capture viewport and explicit print/export styles; inspect each output separately. |
| Table rows split awkwardly in PDF or print | Pagination rules are missing or unsupported in the renderer | Use print-specific CSS and verify page breaks with representative long invoices. |
| Special characters or rupee symbol render incorrectly | Font lacks the glyph or encoding is wrong | Serve UTF-8 HTML and use a font with the needed glyphs; verify fallback behavior. |
| Stale invoice image appears | Cached output was not invalidated after invoice/template edits | Include record and template versions in the cache key and invalidate on changes. |
| IRN or signed QR is absent from preview | The app only rendered a local invoice model | Keep the preview distinct from registration output; where applicable, consume the IRP-returned signed data. |
9. Frequently asked questions
Can I print an e-invoice?
GSTN says that once the IRP returns the signed JSON, it can be converted to PDF and printed if required. Follow the applicable official workflow for the invoice.
Do I need to print the IRN on the invoice?
GSTN’s FAQ says the IRN is optional to print because it is embedded in the QR code. Confirm the current official guidance for your case.
Does an invoice preview image count as an e-invoice?
No. A rendered image is a visual output; it does not itself submit particulars to the IRP or return signed invoice data.
Should the app store HTML, an image, or both?
Keep the invoice record as the source data. Store HTML or a raster image only when the product needs that artifact, and choose PDF or official signed output for the relevant document workflow.
Implementation checklist
- Keep invoice data and HTML presentation separate.
- Escape values and render amounts prepared by trusted application logic.
- Choose whether the preview is responsive, document-width, or print-oriented.
- Wait for fonts and required assets before capturing.
- Test long invoices, narrow screens, missing assets, and updated records.
- Keep IRP registration and returned signed data in its own applicable workflow.
- Use official, current guidance to determine e-invoice applicability and required particulars.


