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:

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

  1. Open the Markdown to PDF tool.
  2. Paste your Markdown into the left pane. The preview on the right updates as you type.
  3. Pick a page size — A4, Letter, A5 or Legal.
  4. 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.

Open Markdown to PDF

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):

FeatureResult in the PDF
Headings, bold, italic, linksRendered 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 blocksSyntax-highlighted per language tag (```python, ```sql, …) via Pygments.
ImagesRemote (https://…) and inline base64 images are both fetched and embedded, scaled to the text column.
Footnotes, definition lists, abbreviationsSupported — part of the extra extension.
Task lists, nested listsNesting is preserved at any depth.
Admonitions (!!! note)Rendered as callout blocks.
Raw HTML in MarkdownAllowed, 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:

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 ![](./diagram.png) 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:

  1. Create an accountsign up free. The free tier includes API access; no card.
  2. Open your cabinet — after signing in you land in the app; the token manager lives at cabinet → API tokens.
  3. 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.

Convert Markdown now Try the editor demo

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.