HTML to PDF in Go

Updated July 2026 · HTTP client: net/http — standard library only

The shortest reliable path from HTML to PDF in Go is not a rendering library — it’s an HTTP call to a rendering API. Your app sends HTML, a managed Chromium engine renders it exactly as Chrome would, and a PDF comes back. No browser binaries in your deploy, no native dependencies, no page-break surprises.

Complete example (main.go)

Set NIPPYPDF_API_KEY in your environment, then this is the whole program:

// main.go — run with: go run main.go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	payload, err := json.Marshal(map[string]any{
		"html":             "<h1>Invoice #1042</h1><p>Total: $2,508.00</p>",
		"format":           "A4",
		"margin":           "20mm",
		"print_background": true,
	})
	if err != nil {
		panic(err)
	}

	req, err := http.NewRequest(http.MethodPost,
		"https://api.nippypdf.com/v1/pdf", bytes.NewReader(payload))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("NIPPYPDF_API_KEY"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		panic(fmt.Sprintf("NippyPDF error %d: %s", resp.StatusCode, body))
	}

	pdf, err := io.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}
	if err := os.WriteFile("invoice.pdf", pdf, 0o644); err != nil {
		panic(err)
	}
	fmt.Println("Wrote invoice.pdf")
}

All request options

POST https://api.nippypdf.com/v1/pdf accepts JSON; the response body is the binary PDF. Options mirror Chromium’s print pipeline:

{
  "html": "<h1>…</h1>",              // or "url": "https://example.com/invoice/1042"
  "format": "A4",                     // "A4" | "Letter" | "Legal" | { "width": "210mm", "height": "297mm" }
  "margin": "20mm",                   // uniform, or { "top": "…", "right": "…", "bottom": "…", "left": "…" }
  "landscape": false,
  "scale": 1.0,                       // 0.1 – 2.0
  "print_background": true,
  "wait_until": "networkidle",        // "load" | "domcontentloaded" | "networkidle"
  "header_html": "<span></span>",     // running header (use sparingly)
  "footer_html": "<span class=\"pageNumber\"></span> / <span class=\"totalPages\"></span>"
}

For pagination control — keeping blocks together, repeating table headers, paper sizes — see the page-break CSS guide.

The self-hosted alternatives, honestly

If those trade-offs are fine for your workload, they are honest choices. The API exists for teams who want Chrome’s output without operating Chrome.

FAQ

Do I need a browser or PDF library installed in my Go app?

No. Rendering happens server-side on NippyPDF's Chromium fleet; your Go code only needs an HTTP client (this guide uses net/http — standard library only). No Chromium download, no native dependencies, nothing extra to deploy.

How do page breaks, fonts and CSS behave?

The API renders with a current Chromium engine, so anything that renders in Chrome renders in your PDF: flexbox, grid, webfonts, and the modern break-before/break-inside page-break properties. See our page-break CSS guide for controlling pagination precisely.

Can I convert a URL instead of an HTML string?

Yes — send { "url": "https://…" } instead of { "html": "…" } in the same request body. Use wait_until: "networkidle" for pages that load data client-side.

Is the API live?

NippyPDF is pre-launch: the schema shown here is the launch API, and early-access keys are going out in batches via the waitlist. Early signups lock in pay-as-you-go pricing around $0.003/document with 500 documents/month free.

Try your own markup in the live in-browser demo, or jump to another language: Node.js, Python, PHP, Ruby, C#.

Generate PDFs from Go without the infrastructure

Pre-launch. Join the waitlist and lock in early-access pricing — we email once, when your key is ready. No spam.