HTML to PDF in Go
Go's local options are chromedp (you now operate a browser
fleet) or PDF-drawing libraries like gofpdf (you now position every element by hand).
The API route keeps your binary static and your Dockerfile boring — standard library
only:
1. Convert HTML to PDF
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"time"
)
func main() {
body, _ := json.Marshal(map[string]any{
"html": "<h1>Hello from Go</h1><p>Rendered by real Chromium.</p>",
"options": map[string]any{"format": "A4"},
})
req, _ := http.NewRequest("POST", "https://inkpdf.dev/v1/pdf", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INKPDF_KEY"))
req.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: 60 * time.Second}
res, err := client.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
msg, _ := io.ReadAll(res.Body)
panic(fmt.Sprintf("render failed: %s", msg))
}
pdf, _ := io.ReadAll(res.Body)
os.WriteFile("hello.pdf", pdf, 0o644)
}2. Invoice from a struct (no HTML)
type LineItem struct {
Description string `json:"description"`
Quantity int `json:"quantity"`
UnitPrice float64 `json:"unitPrice"`
}
payload := map[string]any{
"template": "invoice",
"data": map[string]any{
"brand": map[string]any{"name": "Acme Studio", "color": "#0f766e"},
"invoiceNumber": "INV-2043",
"issueDate": "2026-07-01",
"dueDate": "2026-07-31",
"currency": "USD",
"to": map[string]any{"name": "Northwind Traders"},
"items": []LineItem{
{Description: "Design work", Quantity: 10, UnitPrice: 95},
},
"taxRate": 8.5,
},
}Subtotal, tax, and grand total are computed server-side from
quantity × unitPrice.
3. Serve the PDF from an http.Handler
func invoiceHandler(w http.ResponseWriter, r *http.Request) {
pdf, err := renderInvoice(r.Context(), r.PathValue("id")) // wraps the call above
if err != nil {
http.Error(w, "could not generate PDF", http.StatusBadGateway)
return
}
w.Header().Set("Content-Type", "application/pdf")
w.Header().Set("Content-Disposition", `attachment; filename="invoice.pdf"`)
w.Write(pdf)
}Also speaks Markdown and URLs
Swap the html field for
markdown (with an optional theme)
or url to render any public page. One endpoint, four input
modes — details in the API docs.
Try it without writing code
The playground renders live against the real pipeline — 20 free renders a day, no signup.