HTML to PDF Conversion for Indian Tax Invoices with Rupee Symbols
Create readable invoice PDFs with ₹ by separating GST content checks from HTML rendering, font setup, pagination and output validation.
To convert an Indian tax invoice from HTML to PDF with a readable rupee symbol, validate the invoice particulars required for the transaction, then render the HTML with a PDF engine whose production environment has a font containing the ₹ glyph (Unicode U+20B9). Set paper size, margins and print styles deliberately, and inspect the resulting PDF. A correct-looking PDF does not by itself establish GST compliance: the legal content and the rendering are separate checks.
There is no GST-mandated HTML template, PDF library or special technique for drawing ₹. CBIC Rule 46 sets out invoice particulars and conditions; check the current rule and applicable exceptions for your taxpayer and transaction. [CBIC CGST Rules, Rule 46]
1. Separate invoice content from PDF rendering
Build and validate the invoice data first. Treat the following as a practical checklist, not a substitute for checking the rule’s conditions and exceptions:
- Supplier name, address and GSTIN.
- A consecutive serial number unique for the financial year, and the invoice issue date.
- Recipient details required for the recipient and transaction, including GSTIN or other applicable identifiers.
- HSN code for goods or Accounting Code for services, as applicable; description; and quantity and unit where relevant.
- Total value, taxable value, tax rate and tax charged, with line-level figures and totals that reconcile.
- Place of supply and delivery address where applicable, reverse-charge status where applicable, and the supplier’s signature or digital signature where required.
Only include fields applicable to the specific supply, but do not omit a required particular because it is inconvenient to render. The GST Council’s explanatory flyer says no format is prescribed and only applicable fields need to be filled; because it is older, rely on current CBIC rule text for legal specifics. [GST Council explanatory flyer]
Keep amounts as numeric values in your application model and format them for display at the presentation layer. Use decimal arithmetic appropriate for currency calculations; do not calculate tax by parsing formatted strings containing commas or ₹. Apply the rounding policy required by your accounting workflow consistently, and ensure the displayed line values and totals agree with the stored invoice data.
2. Choose a rendering approach
Two common approaches are Chromium-based browser printing and WeasyPrint. Pick based on your stack, CSS needs, deployment fonts and ability to validate repeatable output. The available documentation does not establish a universal performance winner or prove rupee-glyph behavior in every environment.
| Approach | Useful when | Validate |
|---|---|---|
| Chromium printing, such as through Gotenberg | Your invoice is already HTML/CSS and you want browser print layout behavior. | Print media styles, backgrounds, page breaks, font loading and final output in your deployed Chromium version. |
| WeasyPrint | A Python service fits your stack and its supported CSS and document behavior meet your needs. | Fonts discoverable through Pango, CSS compatibility, pagination and the actual U+20B9 glyph in the generated PDF. |
Gotenberg’s documented Chromium conversion uses print media by default. Configure intended page dimensions and margins; set printBackground when backgrounds matter because print output may omit them otherwise. [Gotenberg HTML to PDF documentation]
WeasyPrint uses fonts available to Pango and embeds fonts in generated PDFs. That is useful, but does not prove a particular font will render U+20B9 correctly in your deployment. Confirm the glyph in the exact environment and inspect the output. [WeasyPrint font documentation]
3. Prepare HTML and print CSS
Use semantic HTML for the invoice, with a real text rupee character or the HTML numeric character reference ₹. Both represent U+20B9. Select a font that includes the glyph and make that font available to the converter; for web fonts, ensure the capture process waits for them to load. Add a fallback stack, but do not assume the fallback selected on a developer laptop exists on the server.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
@page { size: A4; margin: 16mm; }
* { box-sizing: border-box; }
body {
font-family: "Noto Sans", "DejaVu Sans", sans-serif;
color: #17202a;
font-size: 10pt;
}
h1 { font-size: 18pt; margin: 0 0 12mm; }
table { width: 100%; border-collapse: collapse; }
th, td { border-bottom: 1px solid #ccd2d8; padding: 5px; text-align: left; }
.amount { text-align: right; white-space: nowrap; }
.totals { margin-top: 8mm; break-inside: avoid; }
thead { display: table-header-group; }
tr { break-inside: avoid; }
@media print {
body { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
}
</style>
</head>
<body>
<h1>Tax invoice</h1>
<table>
<thead><tr><th>Description</th><th class="amount">Amount</th></tr></thead>
<tbody>
<tr><td>Example service</td><td class="amount">₹ 1,250.00</td></tr>
</tbody>
</table>
<section class="totals">Total: ₹ 1,250.00</section>
</body>
</html>
The sample is a rendering skeleton, not a compliant invoice template. Populate all applicable particulars from your validated invoice record. If you use local fonts, install them in the runtime image and rebuild the font cache where required by that environment. If you use remote font assets, make asset loading deterministic; a network failure or premature print can produce fallback glyphs or layout shifts.
4. Convert with Chromium using Gotenberg
Run a Gotenberg service using its official deployment instructions, then submit an HTML document and any required assets to its Chromium HTML-to-PDF endpoint. This example assumes the service is reachable on localhost and the source file is named index.html. Consult the API docs for the exact multipart fields supported by the Gotenberg version you deploy.
curl --fail --silent --show-error \
-F 'files=@index.html' \
-F 'paperWidth=8.27' \
-F 'paperHeight=11.69' \
-F 'marginTop=0.63' \
-F 'marginBottom=0.63' \
-F 'marginLeft=0.63' \
-F 'marginRight=0.63' \
-F 'printBackground=true' \
http://localhost:3000/forms/chromium/convert/html \
-o invoice.pdf
The dimensions and margins above are expressed in inches for an A4-sized page and are example values. Choose the settings that match the invoice design and confirm them against the deployed API version. Include linked stylesheets, images and fonts as needed using the documented multipart conventions. Do not depend on a browser’s interactive state: conversion should receive all content and assets it needs.
5. Convert with WeasyPrint in Python
Install WeasyPrint following its current installation guide for your operating system, including its system dependencies. The Python API can write PDF bytes directly. This runnable example converts an existing file:
from pathlib import Path
from weasyprint import HTML
source = Path("invoice.html")
output = Path("invoice.pdf")
HTML(filename=str(source), base_url=str(source.resolve().parent)).write_pdf(output)
print(f"Wrote {output}")
The base_url lets relative stylesheet and image references resolve from the HTML file’s directory. If the document is generated as a string, pass an appropriate base URL or use absolute asset URLs. Specify page dimensions and margins in CSS with @page. Confirm that the production host has the fonts your CSS names and that the actual rupee glyph appears in the output.
6. Validate the resulting PDF
- Check content: compare supplier, recipient, invoice identifier, dates, item details, tax rates and amounts, and applicable transaction particulars against the source record and current Rule 46 requirements.
- Check glyphs: view ₹ in line items, tax breakdowns and totals. Extract or select the PDF text as a second check; a glyph can look right while text extraction is wrong, or vice versa.
- Check layout: confirm no clipped totals, overlapping columns, unexpectedly blank pages or split rows that make an amount ambiguous. Test long descriptions and multi-page tables.
- Check print output: verify page size, margins, page breaks and backgrounds in the PDF viewers and printers relevant to your workflow.
- Check repeatability: convert the same input in the deployed environment more than once and compare content and layout when stable output matters to recordkeeping.
Use representative cases: large amounts, decimal values, long line descriptions, multiple line items, multi-page invoices, absent optional fields and the rupee symbol in several positions. These are validation recommendations based on documented font and print dependencies; they are not reported test results.
7. E-invoice workflow is separate
If the issuer is covered by e-invoicing requirements, reporting invoice details and receiving an IRN is an upstream step distinct from PDF rendering. Official portal guidance describes creating the recipient-facing document and further ERP or billing-software customization after IRN receipt. Check current official notifications for applicability; do not hard-code a threshold from a general rendering guide. [Official e-invoice portal guidance]
8. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| ₹ appears as a box, blank, or unrelated character | The selected font lacks U+20B9, the font is absent in the runtime, or it had not loaded when conversion started. | Use a font with the glyph, install or load it in the converter environment, wait for assets, then inspect the PDF visually and through text extraction. |
| Amounts or totals are clipped | Columns are too narrow, a long value is unbreakable, or print margins and page width do not match the layout. | Use right-aligned non-wrapping amount cells, widen the amount column, allow descriptions to wrap, and recheck page dimensions and margins. |
| Background colors or shading disappear | Print rendering omits backgrounds by default or the conversion request did not enable them. | Enable the renderer’s background-print option (Gotenberg documents printBackground) and retain print CSS color adjustment; verify the final PDF. |
| Rows split across pages or headers vanish on later pages | Pagination rules are missing or unsupported in the chosen engine. | Apply table header grouping and break-avoidance rules where appropriate, then test long tables in the actual renderer. Do not force an entire long table to stay on one page. |
| Stylesheets, images or fonts are missing | Relative URLs resolve from the wrong base, the converter cannot access remote resources, or required files were not submitted. | Set a correct base URL, package local assets with the request, and ensure remote asset access is intentional and available to the conversion service. |
| PDF is blank or incomplete | HTML generation failed, scripts or assets were not ready, or the conversion request did not include the intended input. | Check the generated HTML and service response, make asset readiness deterministic, and retry only after fixing the failed dependency. |
| Invoice is visually correct but particulars are missing | Rendering was treated as the compliance check. | Validate invoice data against current Rule 46 and transaction-specific conditions before rendering; visual quality alone does not establish compliance. |
9. Performance, reliability and cost
For a self-hosted workflow, conversion cost depends on your infrastructure, renderer deployment and operational work; the research sources provide no comparative benchmark. Reuse a warmed service where appropriate, avoid unnecessary remote asset fetches, and keep fonts and styles local when that improves determinism. Measure conversion time and resource use on your own representative invoices before setting capacity limits.
For reliability, pin and document the renderer version, package fonts and assets, validate the response as a PDF, and retain enough source data to reproduce an invoice. Handle timeouts and failed conversions explicitly; do not silently issue an empty or partial file. A conversion retry should not create a second invoice identity or alter validated invoice amounts.
10. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. It can also return a PDF from one GET request, which is useful when you already have a public invoice-rendering page. It is not a replacement for validating GST particulars or an e-invoice workflow. See the ScreenshotNeo API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
These examples use the supplied sample URL; replace it with the public URL of your invoice page. Configure the API for PDF output using the documented options when you need a PDF, and review the returned content type and response headers. Keep access keys out of browser code and public repositories.
- Cookie banners, newsletter popups and chat widgets are removed before the shot; each cleanup step can be turned off.
- Bot checks, blank pages and failed loads are never billed; response headers report the page verdict and billing status. Cache hits also cost nothing.
- An MCP server lets AI agents, including Claude and Cursor, take screenshots with tools for screenshots, page information and PDF capture.
- 1,000 screenshots a month are free with no card; paid plans start at $5 for 3,000. Every feature is on every plan.
Sign up for 1,000 free screenshots a month, with no card required.
11. FAQ
Does GST require a specific PDF generator?
The cited GST rule specifies invoice particulars and conditions, not a particular HTML-to-PDF library. Your invoice still needs the applicable particulars.
Does using the ₹ character guarantee it will print?
No. U+20B9 must be supported by a font available to the renderer, and the generated PDF needs to be checked in your actual environment.
Can I use a screenshot API to decide whether an invoice is compliant?
No. ScreenshotNeo can capture or return a PDF for a page, but invoice data and applicable GST requirements must be validated separately.


