FlowKit

n8n Markdown node: converting Markdown to HTML (and back)

Published 25 August 2026 · 7 min read

An LLM answers in Markdown. An email, a WordPress page or a Webflow block expect HTML. A conversion is missing in between, and that is exactly the job of n8n's Markdown node (n8n-nodes-base.markdown), which travels in both directions. This guide covers its actual configuration, the options that really change the rendering, three complete pipelines and the traps that turn a neat AI-generated table into a pile of pipe characters.

The missing link between a model and its destination

Ask any model to write an article, a summary or a message: it will answer in Markdown. ## for headings, ** for bold, dashes for lists. That is the format these models were trained to answer in, and no instruction talks them out of it for long.

This is not just a cosmetic habit: the study by Jia He, Mukund Rungta, David Koleczek, Arshdeep Sekhon, Franklin X. Wang and Sadid Hasan, "Does Prompt Formatting Have Any Impact on LLM Performance?" (arXiv, 2024), compared the same content presented as plain text, Markdown, JSON and YAML. On GPT-3.5-turbo and a code translation task, the authors measure up to 40% performance variation depending on the template used, with larger models such as GPT-4 proving markedly more robust to those variations (see on Google Scholar). Markup is not neutral, neither on the way in nor on the way out.

The problem is the destination. The WordPress API's content field expects HTML. An HTML email body expects HTML. A Webflow Rich Text field expects HTML. Conversely, a scraped web page arrives as HTML and has to leave as clean text toward a model, a vector store or a Notion page. The Markdown node is the plumbing missing between the two.

Configuring the node: three fields, no more

The node is deliberately minimal:

  • Mode: Markdown to HTML or HTML to Markdown;
  • the source field, whose label changes with the mode — it is called Markdown one way, HTML the other. You drop an expression in there, typically {{ $json.output }} behind an AI node, or {{ $json.data }} behind an HTTP request;
  • Destination Key: the item field to write the result into, data by default.

That is a notable difference from the XML node, which replaces the value in the field you name. Here the source field stays intact: you keep the original Markdown next to the produced HTML, which is invaluable when debugging. Only give Destination Key the source field's name if you really mean to overwrite.

Under the hood, two distinct libraries do the work: Showdown for Markdown → HTML, node-html-markdown for HTML → Markdown. Knowing which one is active explains most of the node's behaviour — and in particular why the two option lists have nothing in common.

Markdown → HTML: the options that decide the rendering

Tables Support: the one everyone forgets

This is the number one support ticket. A model happily produces GitHub-style tables, with pipes and a row of dashes. But Tables Support is disabled by default: without it, Showdown leaves those lines as-is and your email displays a literal | Client | Amount |. Add the option, turn it on, and you get real <table> tags.

Same logic for Strikethrough (~~text~~) and Emoji Support, both off by default even though models use them regularly.

Line breaks, code blocks, heading level

Simple Line Breaks is disabled by default: in canonical Markdown, a single newline does not create a <br>, you need two trailing spaces. No LLM produces those. For an email or a short message, turn this option on or your paragraphs will glue back together.

GitHub Code Blocks, on the other hand, is enabled by default: blocks fenced with three backticks do become <pre><code>. Header Level Start defaults to 1; set it to 2 if your model starts its articles with a # and you don't want a second <h1> competing with the page title. Complete HTML Document is off by default, which produces a fragment — exactly what WordPress or Webflow expect. Only enable it when the destination requires a standalone document with <html> and <head>.

Finally, Encode Emails is enabled by default and turns addresses into decimal entities: decent anti-spam in a browser, unreadable if the downstream system re-escapes the HTML.

HTML → Markdown: cleaning up before the model

The reverse trip mostly serves one purpose: cutting noise. The HTML of a real page is 80% tags, utility classes and scripts that carry no information but are billed as tokens on every model call. Converting the page to Markdown first keeps the heading hierarchy, lists and links, and throws away the rest.

In practice you first isolate the useful area with the HTML node and a CSS selector (article, main), then convert. The fetching techniques are in our n8n scraping guide; if you go through Firecrawl, the service already returns Markdown and the node becomes redundant — worth knowing before stacking steps.

The options that matter in this direction:

  • Ignored Elements: the highest-return one. List the selectors to drop along with their children, typically nav, footer, aside, script, style, form. You remove menus and boilerplate before conversion even starts.
  • Place URLs At The Bottom: inline links become reference definitions at the end of the document. The body becomes readable again and long URLs stop cutting sentences in half.
  • Keep Images With Data: off by default, and thankfully so — enabled, it keeps data-URI images, meaning base64 that will blow up your token bill.
  • Bullet Marker (* by default), Emphasis Delimiter (_), Strong Delimiter (**) and Style For Code Block (Fence or Indented): cosmetic, unless the destination has a strict parser.
  • Text Replacement Pattern: a replacement regex, handy for stripping a recurring cookie banner that survived filtering.

The resulting Markdown has an extra advantage for a RAG pipeline: its ## headings are usable semantic boundaries for smarter chunking than a blind cut every 1,000 characters.

Three concrete pipelines

AI article to WordPress. An agent writes in Markdown → Markdown node in Markdown to HTML with Tables Support on and Header Level Start at 2 → WordPress node, Content field fed by {{ $json.data }}. The full setup, from topic to publication, is described in our guide to publishing on WordPress automatically with AI.

HTML newsletter from an LLM output. RSS feed → model summary in Markdown → Markdown node with Simple Line Breaks on → send node. Careful: the node produces semantic HTML, not email-client-proof HTML. Older clients need inline styles, to be added in a template after conversion. The editorial pipeline is detailed in generating an automatic newsletter, and the delivery settings in our SMTP with n8n guide.

Web page to vector store. HTTP Request → HTML node to isolate main → Markdown node in HTML to Markdown with Ignored Elements → chunking → embeddings. You store text rather than tags, and your chunks become readable again on inspection.

The traps

The HTML produced is not sanitized. Showdown lets raw HTML present in the source Markdown through: a <script> slipped into scraped content, then converted and republished, executes in your readers' browsers. And sanitizing is not a solved problem: David Klein and Martin Johns showed, in "Parse Me, Baby, One More Time: Bypassing HTML Sanitizer via Parsing Differentials" (IEEE Symposium on Security and Privacy, 2024), that the 11 server-side HTML sanitizers they tested all relied on deficient parsers, and that all but two could be bypassed by exploiting parsing divergences between the sanitizer and the browser (see on Google Scholar). So treat any externally sourced Markdown as hostile, and never give uncontrolled content a direct path to a published page.

Markdown is not standardized. Showdown covers the core format plus the GitHub extensions you enable. Footnotes, definition lists, maths between $$: none of that gets converted, and the text comes out raw. If your prompt allows those syntaxes, your rendering will be inconsistent — better to constrain the model, as you would with a structured output parser.

Backticks break expressions. A code block fenced with three backticks pasted into an n8n expression, or into a JavaScript template literal inside a Code node, closes the string in the wrong place. Don't re-inject Markdown content by interpolation: wire the field directly ({{ $json.output }}) and let the node read the value.

The round trip is not idempotent. Markdown → HTML → Markdown does not give back the original byte for byte: delimiters change, spacing gets normalized. Don't build any change detection on that assumption.

Summary

n8n's Markdown node comes down to three fields — Mode, source text, Destination Key — but its options decide the result. Going Markdown → HTML, enable Tables Support and Simple Line Breaks from the very first test, set Header Level Start, and sanitize before any republication. Going HTML → Markdown, Ignored Elements is the main lever for saving tokens without losing structure. The rest is cosmetic.

Going further

If your chain is about ingesting pages, documents and exports to make them queryable by an AI, converting to Markdown is the first step: the RAG Assistant Pack at €119 provides the ingestion, chunking and querying ready to plug in behind this node. And if your topic is rather inbound email processing — extracting, summarizing, replying in clean HTML — the AI Inbox Pack at €79 covers the whole loop.

FAQ

Frequently asked questions

Why doesn't my AI-generated table render after converting to HTML?

Because the Markdown node's Tables Support option is disabled by default. Without it, the Showdown library ignores GitHub-flavoured pipe table syntax and leaves the lines as plain text. Add the Tables Support option and turn it on: the pipes then become real table, thead and tbody tags. The same reflex applies to Strikethrough and Emoji Support, which are also off by default.

What is the difference between Property Name and Destination Key in the Markdown node?

The Markdown node has no Property Name: depending on the mode you pick, you fill in either a Markdown field or an HTML field that directly holds the text to convert, usually through an expression such as the output of an AI node. Destination Key then says which field of the item to write the result into, data by default. The source field is therefore not overwritten, unless you give Destination Key the same name.

Does the Markdown node sanitize the HTML it produces?

No. Markdown to HTML conversion relies on Showdown, which lets raw HTML present in the source Markdown pass through, including script tags or onerror attributes. If the Markdown comes from an LLM fed with external content, or from a public form, you must sanitize the HTML before republishing it, using a Code node with a dedicated library or a sanitizing service upstream of publication.

Why convert a web page to Markdown before sending it to a model?

Because the HTML of a real page is mostly tags, class attributes and scripts that carry no information for the model but are still billed as tokens. HTML to Markdown mode, combined with the Ignored Elements option to drop nav, footer, script and style, sharply reduces the volume you send while preserving the heading hierarchy, lists and links, which then feed your chunking strategy.

Bundle FlowKit Complet

€269