A lightweight microservice that converts HTML to PDF using FastAPI and Playwright.
It’s designed to run on Heroku’s container stack with Docker, producing Chrome-quality PDFs (page numbers, headers/footers, @page CSS) consistently across all browsers.
-
FastAPI service exposing a single
/renderendpoint. -
Playwright + Chromium backend → same PDF output as Chrome’s print dialog.
-
Supports:
- Custom HTML headers & footers per request.
- Page numbers (
<span class="pageNumber">/<span class="totalPages">). - Standard CSS
@pagesizing and margins.
-
Secured with a Bearer token (
RENDERER_TOKEN).
Headers:
Authorization: Bearer <RENDERER_TOKEN>
Content-Type: application/json
Body JSON:
{
"html": "<html><body><h1>Hello</h1></body></html>",
"header": "<div>Optional header HTML</div>",
"footer": "<div>Page <span class='pageNumber'></span> / <span class='totalPages'></span></div>",
"format": "A4"
}Response:
{
"pdf_base64": "<base64-encoded-pdf>"
}import requests, base64
RENDER_URL = "https://your-app.herokuapp.com/render"
TOKEN = "your-secret-token"
payload = {
"html": "<html><body><h1>Hello PDF</h1></body></html>",
"footer": "<div style='font-size:10px;text-align:right;'>Page <span class='pageNumber'></span> / <span class='totalPages'></span></div>",
"format": "A4"
}
headers = {"Authorization": f"Bearer {TOKEN}"}
r = requests.post(RENDER_URL, json=payload, headers=headers)
pdf_bytes = base64.b64decode(r.json()["pdf_base64"])
with open("test.pdf", "wb") as f:
f.write(pdf_bytes)-
Set the app stack to container:
heroku stack:set container -a <app-name>
-
Add config var:
heroku config:set RENDERER_TOKEN=<your-secret-token> -a <app-name>
-
Connect repo to Heroku and deploy via GitHub (or push manually).
.
├── app.py # FastAPI service
├── requirements.txt
├── Dockerfile # Container build (installs Chromium + Python deps)
├── heroku.yml # Heroku container config
└── README.md
Build & run locally with Docker:
docker build -t htmltopdf .
docker run -p 8080:8080 -e RENDERER_TOKEN=local-secret htmltopdfThen call:
POST http://localhost:8080/render
Authorization: Bearer local-secret
MIT