How to convert Markdown to PDF without installing anything
Markdown is a great place to write and a poor place to hand something over. This is what happens when you turn one into a PDF — what survives, what to watch for, and how to stop doing it by hand.
Everyone hits this eventually. You have a README.md, a
meeting summary, a spec, an invoice template, an LLM answer you want to
keep — and the person on the other end wants a document, not a text file
full of hash signs. The obvious moves both disappoint:
- Print the preview from your editor. You get your
editor's screen CSS on paper: tables cut in half at the page boundary,
code blocks clipped at the right margin, and a browser header stamping
file:///Users/you/…across the top. - Paste into a word processor. The Markdown is gone, the formatting is approximate, and you have just taken on a manual step you will have to repeat every time the source changes.
The fix is a converter that treats the output as a printed document from the start: one that knows about page size, margins, page numbers, and where a page is allowed to break.
The 30-second version
- Open the Markdown to PDF tool.
- Paste your Markdown into the left pane. The preview on the right updates as you type.
- Pick a page size — A4, Letter, A5 or Legal.
- Press Generate PDF and download the file.
No account, no install, no upload of a file you would rather not upload — the text goes to the renderer, the PDF comes back, and nothing is kept. Anonymous use is limited to one PDF every five minutes; a free account lifts that to one per minute.
Want to follow along with your own document? The tool is open in another tab in about two seconds.
What actually survives the conversion
This matters more than it sounds — most "markdown to pdf" tools support
a smaller subset than you expect and quietly drop the rest. Here is what
is handled, using the standard Python-Markdown extension set
(extra, sane_lists, codehilite,
toc and admonition):
| Feature | Result in the PDF |
|---|---|
| Headings, bold, italic, links | Rendered as document typography; links stay clickable in the PDF. |
Tables (|---|) | Full support, including alignment rows. Wide tables shrink to the text column rather than running off the page. |
| Fenced code blocks | Syntax-highlighted per language tag (```python, ```sql, …) via Pygments. |
| Images | Remote (https://…) and inline base64 images are both fetched and embedded, scaled to the text column. |
| Footnotes, definition lists, abbreviations | Supported — part of the extra extension. |
| Task lists, nested lists | Nesting is preserved at any depth. |
Admonitions (!!! note) | Rendered as callout blocks. |
| Raw HTML in Markdown | Allowed, but sanitised: structural and formatting tags pass, <script> and event handlers are stripped. |
Two things are deliberately not executed: JavaScript, and anything that would let a document reach into the machine rendering it. A converter that runs arbitrary script on someone else's server is a security incident waiting for a date, so this one does not.
Where the page breaks land
This is the part that separates a real PDF from a screenshot of a webpage. The document is rendered with WeasyPrint, a print engine that implements CSS Paged Media — the standard the web has had for printing since long before anyone called it a PDF pipeline. In practice that means:
- Headings do not get orphaned. A
##at the bottom of a page is pushed to the next one rather than stranded above a page break with its section on the far side. - Tables and code blocks split sensibly when they are longer than a page, and header rows repeat.
- Page numbers are real. Every page carries a
page N / Mfooter generated by the CSS page counter, not typed by hand — so they stay right when the content changes.
You will also get a faint erp2pdf.com rule at the top and a
"Made with erp2pdf.com" line in the footer. That is the deal for the free
tier and it is stated up front rather than discovered after you send the
file to a client.
Practical tips for a clean result
Control your own page breaks
Markdown has no page-break syntax, but raw HTML is allowed, so a one-liner does it:
<div style="page-break-before: always"></div>
Drop that between two sections and the second one starts on a fresh page. Useful for a title page, or for making sure each chapter of a handbook opens cleanly.
Pick the page size before you tune anything else
A5 is roughly half of A4, so a table that fits comfortably in one will be cramped in the other. Set the size first, then look at how content lands. For anything going to a European printer or office, A4 is the default; Letter is the North American equivalent.
Use absolute image URLs
A relative path like  means nothing to a
server that only received your text — there is no folder for it to look
in. Either host the image and use its full https:// URL, or
inline it as a base64 data URI. Both work.
Keep a table of contents honest
The toc extension is enabled, so a line containing
[TOC] is replaced by a generated table of contents built
from your headings. It renumbers itself every time you regenerate, which
is the entire point.
Automating it: the API
Converting one document in a browser is fine. Converting one per customer, per night, or per build is not something to do by hand. Every free tool has a matching REST endpoint. The one prerequisite is an API key, and getting one is three clicks:
- Create an account — sign up free. The free tier includes API access; no card.
- Open your cabinet — after signing in you land in the app; the token manager lives at cabinet → API tokens.
- Issue a token and copy it immediately. The plaintext key is shown once, at creation time — after that only its fingerprint is stored, so a lost key is replaced, not recovered. Same screen revokes a key when a server is decommissioned.
Keep the key in an environment variable rather than in the source file you are about to commit:
export ERP2PDF_KEY="pk_live_…"
curl -X POST https://erp2pdf.com/api/v1/markdown-to-pdf \
-H "Authorization: Bearer $ERP2PDF_KEY" \
-H "Content-Type: application/json" \
-d '{"markdown":"# Release notes\n\nShipped **today**.","page_size":"a4"}' \
--output release-notes.pdf
The same call in Python, which is where most of these end up living:
import os, requests
pdf = requests.post(
"https://erp2pdf.com/api/v1/markdown-to-pdf",
headers={"Authorization": f"Bearer {os.environ['ERP2PDF_KEY']}"},
json={"markdown": open("notes.md").read(), "page_size": "a4"},
timeout=60,
)
pdf.raise_for_status()
open("notes.pdf", "wb").write(pdf.content)
The response body is the PDF (application/pdf) —
there is no job id to poll and no second request to fetch a result. Body
fields are markdown, plus optional page_size
(a4 | letter | a5 | legal), title and
file_name. Authenticated calls are limited to one PDF per
minute and return 429 with a Retry-After header
past it. The full schema is in
the API docs, with a live console to try calls
against your own key.
When you have outgrown this
A Markdown converter is the right tool when the document is prose: notes, reports, release notes, documentation, a summary an LLM just produced. It is the wrong tool the moment the document is really a layout — a product catalog, a pricelist, a spec sheet where the position of every block matters and the content comes from a database rather than from a person typing.
That is the other half of this site: a template editor where you place blocks once, connect Odoo or a REST source, and generate hundreds of pages of catalog with per-partner language and print-grade CMYK output. Same door, very different job.
Start with the free converter. If your documents turn out to be catalogs, the editor is one click away and the demo needs no sign-up.
Frequently asked
Is my document stored anywhere?
No. The text is rendered and discarded; the PDF is streamed back in the same response. Nothing is written to disk for later.
How long can the Markdown be?
Up to 200,000 characters per request — comfortably more than a book chapter, and well past the point where a single PDF is still the right container.
Can I use my own fonts or CSS?
Not through the Markdown tool — it applies a fixed document stylesheet
so the output is consistent. If you need control over typography, use
HTML to PDF, where your own
<style> block is honoured.
Do I need an account for the browser tool?
No — the Markdown converter works anonymously at one PDF every five minutes. An account is only needed for the faster limit and for the API, and it is free to create. API keys are issued in cabinet → API tokens.
Does it work offline / on a private network?
The hosted tool needs internet access, and it will not fetch images from private or internal addresses — that restriction is deliberate, since a server that follows arbitrary URLs is an open door into whatever network it sits in.