# Markdown to PDF API Markdown to PDF API: convert with marked, markdown-it, Python-Markdown or goldmark, add a print stylesheet and code highlighting, and get a PDF. Markdown is the easiest way to write a document, and it's what most AI agents produce by default. Getting from Markdown to a good-looking PDF takes two steps. First turn the Markdown into HTML, then print that HTML with a browser engine. This guide covers the conversion in JavaScript, Python and Go, a minimal print stylesheet, code highlighting, and the API call that produces the PDF. **Quick answer.** Convert your Markdown to HTML with any parser, then POST the HTML to `https://html-pdf.com/v1/pdf` and save the response as a PDF. ```bash curl https://html-pdf.com/v1/pdf -H "Authorization: Bearer $HTML_PDF_KEY" \ -d '{"html":"
Rendered from Markdown.
"}' -o report.pdf ``` ## Step 1: Markdown to HTML This step turns your Markdown into HTML with the parser for your language. All of these support GitHub-style tables and fenced code blocks. **JavaScript with [marked](https://marked.js.org):** ```js import { marked } from "marked"; // npm install marked const body = marked.parse("# Report\n\n| Item | Qty |\n|---|---|\n| Widget | 3 |"); ``` **JavaScript with [markdown-it](https://github.com/markdown-it/markdown-it):** ```js import markdownit from "markdown-it"; // npm install markdown-it const body = markdownit({ html: false, linkify: true }).render(source); ``` **Python with [Python-Markdown](https://python-markdown.github.io):** ```python import markdown # pip install markdown body = markdown.markdown(source, extensions=["tables", "fenced_code", "toc"]) ``` **Go with [goldmark](https://github.com/yuin/goldmark):** ```go import ( "bytes" "github.com/yuin/goldmark" "github.com/yuin/goldmark/extension" ) var buf bytes.Buffer md := goldmark.New(goldmark.WithExtensions(extension.GFM)) if err := md.Convert(source, &buf); err != nil { panic(err) } body := buf.String() ``` If the Markdown comes from users or an LLM, keep raw HTML disabled (the markdown-it default) or sanitize the output. DOMPurify and `bleach` both work well for this. ## Step 2: Add a print stylesheet This section gives you a stylesheet that makes the output look like a real document. Raw parser output prints in Times New Roman with no margins, so wrap it in a full HTML document with a small stylesheet. This one is a good default for reports, docs and READMEs. ```css @page { size: A4; margin: 20mm 18mm; } html { font: 11pt/1.55 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; color: #1f2328; } body { margin: 0; } h1, h2, h3 { line-height: 1.25; margin: 1.4em 0 0.5em; break-after: avoid; } h1 { font-size: 22pt; margin-top: 0; } h2 { font-size: 15pt; border-bottom: 1px solid #d0d7de; padding-bottom: 0.2em; } h3 { font-size: 12.5pt; } p, ul, ol, table, pre, blockquote { margin: 0 0 0.9em; } a { color: #0969da; text-decoration: none; } code { font: 9.5pt ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; background: #f3f4f6; padding: 0.1em 0.3em; border-radius: 3px; } pre { background: #f6f8fa; padding: 10px 12px; border-radius: 6px; white-space: pre-wrap; word-break: break-word; break-inside: avoid; } pre code { background: none; padding: 0; } table { border-collapse: collapse; width: 100%; font-size: 10pt; } th, td { border: 1px solid #d0d7de; padding: 5px 8px; text-align: left; } th { background: #f6f8fa; } tr, img { break-inside: avoid; } img { max-width: 100%; } blockquote { border-left: 3px solid #d0d7de; padding-left: 12px; color: #57606a; } hr { border: 0; border-top: 1px solid #d0d7de; margin: 1.5em 0; } ``` `white-space: pre-wrap` stops long code lines from running off the page. The `break-*` rules keep headings with their content and table rows in one piece. More on that in [HTML to PDF page breaks](https://html-pdf.com/html-to-pdf-page-breaks). ## Code highlighting This section shows how to get colored code blocks in the PDF. Highlight at conversion time so the HTML already contains colored spans, and inline the theme CSS. Nothing has to load or run in the browser. In Node.js, use [highlight.js](https://highlightjs.org) with `marked-highlight`. ```js // npm install marked marked-highlight highlight.js import fs from "node:fs"; import { Marked } from "marked"; import { markedHighlight } from "marked-highlight"; import hljs from "highlight.js"; const marked = new Marked(markedHighlight({ emptyLangClass: "hljs", langPrefix: "hljs language-", highlight(code, lang) { const language = hljs.getLanguage(lang) ? lang : "plaintext"; return hljs.highlight(code, { language }).value; }, })); const hljsCss = fs.readFileSync("node_modules/highlight.js/styles/github.css", "utf8"); ``` In Python, the `codehilite` extension does the same with Pygments. ## Step 3: HTML to PDF This step prints your HTML to a PDF. The DIY route is a headless browser, either Puppeteer or Playwright with `page.setContent(html)` then `page.pdf()`, or `chrome --headless --print-to-pdf`. It works, but you have to run and maintain Chromium yourself. See the [Puppeteer guide](https://html-pdf.com/puppeteer-html-to-pdf). ## Or skip the server This section shows how to get the PDF without running a browser. Send the HTML to html-pdf.com and get the PDF back. Here is a complete Node.js script that continues from the highlighting snippet above. ```js const docCss = fs.readFileSync("print.css", "utf8"); // the stylesheet above const source = fs.readFileSync("report.md", "utf8"); const html = `