Skip to main content
Glama
drsound

markdown-to-whatsapp

by drsound

Markdown to WhatsApp Converter

License: MIT tests npm

Wandle Standard-Markdown in die Syntax von WhatsApp um – als Webseite, npm-Bibliothek, Kommandozeilenwerkzeug oder MCP-Server für Agents.

➡️ Zum Live-Tool

npm i markdown-to-whatsapp · npx markdown-to-whatsapp mcp

Screenshot der App


Zweck dieses Tools

WhatsApp verwendet für die Textformatierung eine nicht standardisierte Syntax (z. B. *bold*, _italic_, ~strikethrough~). Sie ist Standard-Markdown ähnlich, aber nicht identisch.

Dieses Tool bietet eine einfache Möglichkeit, Text aus Markdown-Quellen (wie Texteditoren, Google Docs usw.) in das Format umzuwandeln, das WhatsApp erwartet – und erspart die manuelle Korrektur.

Der gesamte Konvertierungsprozess läuft lokal in deinem Browser ab, in JavaScript, und der Parser wird mit der Seite ausgeliefert. Es werden keine Daten an einen Server gesendet – die einzige Anfrage, die die Seite verlässt, ist die für die Schrift.

Unterstützte Konvertierungen

Das Skript nutzt die marked-Bibliothek für sauberes AST-basiertes Parsen und verarbeitet:

Textstile

  • Fett: **text***text*

  • Kursiv: *text* oder _text__text_

  • Durchgestrichen: ~~text~~~text~

  • Inline-Code: `code``code`

  • Fett+Kursiv: ***text***_*text*_ (erhält beide Stile)

Überschriften

Überschriften werden in fetten Text mit emoji-Präfixen pro Ebene umgewandelt:

  • # H1*📌 H1*

  • ## H2*🟠 H2*

  • ### H3*🟡 H3*

  • usw.

Das Emoji-Präfix kann in der Oberfläche deaktiviert werden (Überschriften · Emoji), sodass ein schlichtes *Title* bleibt.

Listen

  • Ungeordnete Listen: Verwenden das Präfix *; tiefere Ebenen werden mit markiert

    • Ebene 1: * Item

    • Ebene 2: * ◦ Item

    • Ebene 3: * ◦ ◦ Item

  • Geordnete Listen: Nummerierung bleibt erhalten, kennzeichnet tiefere Ebenen

    • 1. A / ◦ 1. A1 / ◦ ◦ 1. A1a / 2. B

  • Aufgabenlisten: - [x], - [ ], auch innerhalb geordneter Listen (1. ☑ done)

  • Lose Einträge: Mehrere Absätze eines Eintrags werden in einer einzigen Zeile zusammengefügt

  • Blockartikel in Einträge: Codeblöcke, Zitate und verschachtelte Listen werden in eigenen Zeilen unterhalb des Eintrags ausgegeben

Sprechblasenbreite

Eine WhatsApp-Sprechblase passt eine feste Anzahl von Monospace-Zeichen pro Zeile – auf einem 360-px-Gerät etwa 26, und das ist der Standard. Miss deine eigene, indem du dir selbst einen Codeblock schickst und auszählst, wo er umbricht, und setze dann Breite in der Leiste auf diesen Wert (das ? daneben sagt dasselbe). Das Feld akzeptiert 10 bis 80: Kein Telefon liegt außerhalb dieses Bereichs.

Diese Zahl ist eine Eigenschaft des Geräts, nicht irgendeiner einzelnen Tabelle, und gilt deshalb für alles Monospace: Tabellen werden abgestuft, bis sie darunter bleiben, und die Vorschau zeichnet jeden Codeblock exakt so breit, mit Umbruch an der Stelle, an der auch WhatsApp des Empfängers umbricht.

Tabellen

Eine Tabelle wird in einem von zwei Stilen dargestellt, wählbar in der Oberfläche für das ganze Dokument oder für einzelne Tabellen:

  1. Auto (Standard): eine gezeichnete Tabelle in einem Monospace-Block, so breit wie nötig und nie breiter als die Sprechblase – und die Aufzählungsliste, wenn gar keine Box gezeichnet werden kann.

    +--------+-------------+
    | Name   | Description |
    +========+=============+
    | Value  | Details     |
    +--------+-------------+
  2. Liste: Immer die Aufzählungsliste.

Wie die Liste aufgebaut wird

Eine Liste kann die Zellen auf drei Arten gruppieren. Der Konverter rät es aus den Kopfzeilen und den fetten Zellen, und die Wahl kann pro Tabelle überschrieben werden (Layout: Auto · Rows · Columns · Pairs):

  • Pairs – 2 Spalten, egal was in den Kopfzeilen steht: Jede Zeile wird zu einer key: value-Zeile. Die Kopfzeilen in jeder Zeile auszuschreiben liest sich bei fast jeder Tabelle schlechter als Italy: Rome.

    * *CPU:* Intel Xeon
    * *RAM:* 64 GB
    * *Storage:* 1 TB SSD
  • Columns – 3+ Spalten, deren erste Kopfzeile leer ist oder eine Eigenschaft benennt („Feature“, „Spec“, „Parameter“ …), oder deren erste Spalte fett ist: eine Vergleichsmatrix, in der die Spalten verglichen werden, also jede Spalte eine Gruppe ist.

    * *Proxmox*
    * ◦ _Kernel:_ KVM
    * ◦ _License:_ AGPL v3
    * *ESXi*
    * ◦ _Kernel:_ VMkernel
    * ◦ _License:_ Proprietary
  • Rows – alles andere: eine Gruppe pro Zeile, beschriftet mit ihrer ersten Zelle.

    * *Product:* Laptop
    * ◦ _Price:_ $999
    * ◦ _Stock:_ 50
    * *Product:* Smartphone
    * ◦ _Price:_ $599
    * ◦ _Stock:_ 100

Die Eigenschaftswörter werden wortweise abgeglichen („Species“ zählt nicht als „spec“) in 11 Sprachen: Englisch, Italienisch, Spanisch, Französisch, Portugiesisch, Deutsch, Russisch, Arabisch, Hindi, Bengali und Indonesisch. Pairs brauchen genau zwei Spalten; für eine breitere Tabelle angefragt, wird daraus Rows.

Wie die Box heruntergefahren wird

Die Box wird nicht in jeder Breite gezeichnet: Sie wird abgestuft, bis sie in monoWidth passt, und zu einer Liste, wenn nichts passt. Es gibt keine Möglichkeit, eine Tabelle breiter als die Sprechblase anzufordern.

  1. Volle Box, bei der Spalte für Spalte Innenabstand entfernt wird (zuerst rechts, dann links).

  2. Kompakter, rahmenloser Stil, der den Innenabstand wieder schrittweise entfernt:

     Head1|Head2       |Head-N
    ------+------------+------
     A    |BBBBBBBBBBBB|C
  3. Umgebrochene Box, zuerst mit vollen Rahmen, dann kompakt: Jede Spalte bekommt mindestens ihr längstes Wort, die restliche Breite wird proportional verteilt und Zellen werden umbrochen. Zeilen wachsen so hoch wie nötig – ohne Limit – und zwischen ihnen wird immer eine Trennlinie gezogen, denn zwei umgebrochene Zeilen ohne Trennlinie laufen ineinander. Zellen sind am Anfang der Zeile ausgerichtet.

    +---------+--------------+
    | Feature | Notes here   |
    +=========+==============+
    | Alpha   | short note   |
    +---------+--------------+
    | Beta    | a slightly   |
    |         | longer note  |
    +---------+--------------+
  4. Aufzählungsliste, wenn nicht einmal die längsten Wörter hineinpassen (eine lange URL, fünf Spalten bei 26 Zeichen …).

Ob eine hohe, umgebrochene Box besser zu lesen ist als die Liste, kannst du in der Vorschau selbst entscheiden: Das eigene Panel der Tabelle stellt sie zur Liste um. Eine Tabelle, die in keine Box passt, sagt das in ihrem Panel und bietet stattdessen das Listenlayout an – statt eines Stils, der nichts ändern könnte.

Weiteres Tabellenverhalten

  • Spaltenbreiten werden in Anzeigezellen gemessen, sodass Emoji- und CJK-Text ausgerichtet bleiben (, 日本語 zählen als zwei Spalten) – so weit das Gerät es zulässt: Diese Glyphen stammen ebenfalls aus einer Fallback-Schrift, daher ist die Ausrichtung „best effort“, anders als bei den ASCII-Rahmen.

  • Spaltenausrichtung (:---, :---:, ---:) wird bei Box- und Kompakt-Stil beachtet.

  • Nur-Kopfzeilen-Tabellen werden ohne leeren Body oder doppelte Trennlinie gerendert.

  • <br> in einer Zelle wird zu einem Leerzeichen, und ein escaped \| wird zu ¦, damit es keine zusätzliche Spalte vortäuschen kann.

  • Rahmen sind bewusst reines ASCII (+-|=). Dafür gibt es einen Grund: Die Monospace-Schrift von WhatsApp enthält keine Box-Zeichen. Ein Telefon nimmt und aus der jeweiligen Fallback-Schrift, in der Breite, die diese Schrift ihnen wählt; eine Zeile aus 26 solcher Zeichen bricht auf zwei Zeilen um, die Textzeilen daneben aber nicht. +-| sind die einzigen Zeichen, deren Breite eine Monospace-Font tatsächlich zusichert – deshalb wird der escaped Pipe-Strich auch zu ¦, einem Latin-1-Zeichen aus derselben Schrift wie à.

  • Zeilen-Trenner (standardmäßig aus) zeichnet eine Linie zwischen Body-Zeilen, in jedem Box- und Kompakstil; eine umgebrochene Tabelle zeichnet sie immer.

  • Der Stil, der Zeilen-Trenner und das Listen-Layout lassen sich pro Tabelle setzen: Wenn du in der Vorschau mit der Maus über eine Tabelle fährst, erscheinen ihre eigenen Steuerelemente, die vom Dokumentdefault ausgehen und nur diese Tabelle ändern, und zwar mit nur den noch passenden Optionen (Trenner bei der Box, Layout bei der Liste). Die Breite ist nicht dabei: Es gibt die eine Sprechblase, und die ist für jede Tabelle gleich. Eine Tabelle mit eigenen Einstellungen behält eine gestrichelte Markierung, denn die Steuerelemente am oberen Ende des Panels lassen sie bewusst in Ruhe – ihr „Reset“-Button gibt zurück zu den globalen Einstellungen. Überschreibungen folgen der Tabelle über ihre Kopfzeile, daher ziehen die Einstellungen nicht um, wenn zu- oder abbrechend eine Tabelle weiter oben sitzt. Eine Tabelle verschachtelt in Listen-Element oder Zitat folgt immer der Dokument-Einstellung.

Codeblöcke

Betongebene und eingerückte Blöcke kommen unverändert bei WhatsApp: Der Konverter bricht sie nie neu abzeilen noch neu einrücken – ein Zeilenumbruch innerhalb von Code ist Inhalt, kein Layout. Langzeitige Zeilen bricht WhatsApp selbst, mitten im Wort, und eine ChatBlase hat kein horizontales Scrollen – also reproduziert die Vorschau diesen Umbruch bei monoWidth, statt zu scrollen, und zeigt genau das, was der Empfänger als Umbruch sehen wird.

Andere Elemente

  • Links: [text](url)text (url); Autolinks, <https://x>, [url](url) und <me@x.com> werden als nackte/Adresse dargestellt (keine Duplikation, kein mailto:-Leak)

  • HTML-Entitäten: Dezimal- und Hex-Referenzen plus die üblichen benannten – Latin-1-Buchstaben, Zeichen und Symbole (caf&eacute;café, &copy;©, &#65;A). Seltenere Referenzen (Griechisch, mathematisch) bleiben unverändert.

  • Inline-HTML: <b>/<strong>*, <i>/<em>_, <s>/<del>~, <code>`, <br> macht Zeilenumbruch; mehr und andere

  • HTML-Blöcke: Tags entfernt, Blockumbrüche zu neue Zeilen, Entitäten dekodiert

  • Blockzitate: >-Präfix bleibt, Verschachtelung wird unterstützt und angezeigt: > > nested

  • Codeblöcke: Mit drei Backticks begehalten; ein Dreifach-Rückwing im Inhalt → ˋˋˋ, damit man den Block nicht vorzeitig schließen kann.

  • Horizontale Trennlinien: ---───────────────

  • Escaping von Zeichen: Nutzt Unicode-Kannibalen (, _, ), damit WhatsApp sie nicht als Formatierung interpretiert.

WhatsApp-spezifisches Verhalten

  • Teilwortformatierung wird ignoriert: super**bold**lysuperboldly (WhatsApp unterstützt keine Formatierung mitten im Wort)

  • Punctuation ist eine gültige Grenze: **Name**: value*Name*: value – genauso bei (**x**) und **end**.

Verwenden

  1. Öffne die Webseite: https://drsound.github.io/markdown-to-whatsapp/

  2. Füge ein, tippe oder ziehe eine .md-Datei in das linke Panel. „Try an example“ füllt es mit dem Beispieltext.

  3. Das rechte Panel zeigt die Nachricht in der WhatsApp-Sprechblase – genau wie viel der das scheint. „view raw syntax“ zeigt den Text, der jetzt kopiert wird. Die beiden Panels scrollen gemeinsam – die unterwegs ist, führt – und während du sie schreibst, folgt die Vorschau besser dem Cursor.

  4. „Copy for WhatsApp“, oder „Share on WhatsApp“ öffnet einen Chat via wa.me mit der Nachricht. Eine ganz lange Nachricht passt nicht in eine URL-Link – Browser schneiden Links von mehr als wenige tausend Zeichen speichern, so dass Share zurücktritt und stattdessen „Kopieren“ empfiehlt.

Die Oberfläche richtet sich nach dem Hell- oder Dunkeldesign des Betriebssystems – angepasst durch den Schalter oben; der Schalter gewinnt und die Wahl wird gespeichert. Die Optionsleiste, unterteilt nach Inhaltstyp, wird es bei vorhandenen Inhalt angezeigt für: Sprechblase (selber die Breite, auch vorhanden ist), Tabelle Trennlinie und Überschriften (änderungen Emoji-Präfix). Eine Einstellung kann eine andere überflüssig (z. B. der Trennstil bei List, die Breite ohne etwas Monospace) – sie wird grau ausgegraut und sonst unbeeinflusst, damit die Leiste ihre Form behält. Die Optionen werden in localStorage; die Optionen pro Tabelle werden nicht gespeichert – sie gehören zu dem Text, der gerade umgewandelt wird.

Aus Code, der Shell oder von Agents

Derselbe Konverter ist auf npm verfügbar als markdown-to-whatsapp (Node 20 oder neuer). Die Optionen sind identisch benannt und voreingestellt, sowie oben beschrieben – vollständige Liste dies Ende dieses Bereichs.

Bibliothek

npm install markdown-to-whatsapp
import { convertTextToWhatsapp, convertToBlocks } from 'markdown-to-whatsapp';

convertTextToWhatsapp('# Hi **there**');
// → '*📌 Hi there*'

convertTextToWhatsapp(markdown, { monoWidth: 30, tableFormat: 'auto', headingEmojis: false });

// The same conversion with the blocks kept apart: each has the source `line` it starts on,
// and each table its `key`, `columns`, `fitsBox`, `asList` and `listLayout`
const { text, blocks } = convertToBlocks(markdown, { monoWidth: 30 });

Kommandozeile

npx markdown-to-whatsapp notes.md                  # a file…
cat notes.md | npx markdown-to-whatsapp            # …or stdin
npx markdown-to-whatsapp notes.md --width 32 --tables list --no-emoji
npx markdown-to-whatsapp notes.md --json           # the blocks, for scripting
npx markdown-to-whatsapp --help

--width (10–80), --tables auto|list, --layout auto|rows|columns|pairs, --separator, --no-emoji, --json, sowie - h, --help und - v --version. Ausgabe geht aufstdout; bei falscher Option Option (Stderr) Exit-Code 2.

MCP-Server

Das Paket läuft als Model Context Protocol-Server über stdio, damit werfen Agenten den Text selbst konvertieren kann – entscheidend. Zähler from Spalte an 26-Zeichen-Sprechblase is exactly what ein Model nicht richtig macht, dieses Tool aber richtig richt. Es gibt

claude mcp add markdown-to-whatsapp -- npx -y markdown-to-whatsapp mcp

für Claude Desktop und weitere Kunden mit JSON-Konfig:

{
  "mcpServers": {
    "markdown-to-whatsapp": {
      "command": "npx",
      "args": ["-y", "markdown-to-whatsapp", "mcp"]
    }
  }
}

Es stellt ein einzelnes Werkzeug bereit, convert_markdown_to_whatsapp, das markdown zusammen mit den optionalen monoWidth, tableFormat, listLayout, rowSeparator und headingEmojis aufnimmt. Der Text kommt als Werkzeuginhalt zurück, und das strukturierte Ergebnis enthält ihn als text zusammen mit Tables: ein Eintrag pro Tabelle mit key, columns, fitsBox, asList und listLayout, sodass der Agent erkennen kann, welche Tabellen zu einer Box und welche zu einer Liste wurden. Das Werkzeug ist schreibgeschützt und idempotent.

Optionen

Die Optionen sind tableFormat (auto | list), monoWidth, rowSeparator, headingEmojis und listLayout (auto | rows | columns | pairs) sind die Optionen; außerdem gibt es tableOverrides – entweder ein Array, das über die Position der Tabelle im Dokument indiziert wird, oder ein Objekt, das über den key der Tabelle (die mit | verbundenen Kopftexte, bei wiederhoften Kopfzeilen zusätzlich #2, #3 …) indiziert wird; jeder Eintrag überschreibt für diese Tabelle alle anderen Optionen. Die Seite macht listLayout nur pro Tabelle verfügbar.

Die älteren Namen werden weiterhin als Eingabe akzeptiert: tableThreshold für monoWidth und ascii / always für tableFormat (ascii hat nie eine Box breiter als die Silenblatt gezeichnet, daher wird es auf auto abgebildet). Wenn sowohl der alte als auch der neue Name angegeben werden, gewinnt der neue und ein Alte wird verworfen. borderStyle, das früher für Unicode-Boxzeichen zuständig war, wird akzeptiert und ignoriert.

Entwicklung

Tests ausführen

Node 20 oder neuer, im Wurzelverzeichnis des Repository:

npm install
npm test

Die Test-Suite verwendet dateibasierte Tests:

  • tests/inputs/*.md – Markdown-Eingabedateien

  • tests/inputs/*.json – optionale Konverter-Optionen pro Test (z. B. { "monoWidth": 40 })

  • tests/expected/*.txt – erwartete WhatsApp-Ausgabe

Dazu kommen einige Invarianten: der mitgelieferte Parser stimmt mit dem installierten überein, convertToBlocks liefert die richtige Quelle Benutzerzeilen und die Paket-Einstiegspunkt ist das Seiten-Skript.

Tests laufen auch in CI bei jedem Push und jedem Pull-Request (.github/workflows/test.yml).

Projektstruktur

  • docs/converter.js – der Konverter selbst: ein reines ES-Modul, ohne DOM, Optionen als Parameter übergeben. Er ist zugleich die Skript, das die Seite importiert, und der Einstiegspunkt des npm‑Pakets (exports["."]), sodass es eine Kopie und keinen Build-Schritt gibt. Er bietet convertTextToWhatsapp(markdown, options) und convertToBlocks(markdown, options) an – dieselbe Umwandlung, wobei die obersten Blöcke getrennt bleiben und jede Block mit der Ursprungstabelle markiert ist, worauf die Tabellen-Optionen liegen – sowie die von der UI genutzten Zuordnungen mdContainsTable, mdContainsHeading und mdContainsCode, um eine Option nur dann einzublenden, wenn sie zutrifft. Jeder Block von convertToBlocks meldet die Quelline line, an der er beginnt – das hält die beiden Panee beim Synchronrolle synchron – und jeder Tabellenblock zudem key, columns, fitsBox (ob eine Box möglich ist), asList (was geschrieben wurde) und listLayout, sodass die Schnittstelle genau die verbleibenden Optionen anbieten kann.

  • docs/ui.js – Seitenverdrahtung: Theme, kontextabhängige Optionen, WhatsApp-Vorschau, Scroll-Sync-Zwischen den Panelen, Kopieren und Teil/am.

  • docs/index.html, docs/style.css – Markup und handgeschriebenes Stylesheet (ohne CSS-Framework).

  • docs/vendor/ – die ES-ktion von marked.com/markedjs/marked), von node_modules via npm run vertor kopiert; die Import-Map der Seite löst marked darauf auf.

  • bin/markdown-to-Whatsapp.js – das Befehlszeug; bin/mcp.js – der MCP-Server, den es bei mcp startet und nur dann lädt, so dass das Konvertieren einer Datei niemals das Protokoll-SDK inspiziert.

  • scripts/vendor.js – kopiert die marked‑E– in docs/vendor/ (npm run vendor).

  • tests/ – die Fixtures und der Runner.

Die marked-Abhängigkeit

Die Version von marked ist in package.json auf 18.19.1 fixiert, und die von docs/vendor/ von der Seite geladene Kopie wird daher durch die Teststraße gegen diese Version geprüft, sodass Seite, Paket und Tests Markdown immer gleich parsen. Zum Aktualisieren: Version erhöhen, npm install, npm run vendor, npm test.

Teilung

npm test
npm pack --dry-run   # docs/converter.js, bin/, README, LICENSE — nothing else
npm publish

Lokale Entwicklung

cd docs
python3 -m http.server 8080
# Open http://localhost:8080

Firma

Firm.

MIT, see the LICENSE file.
-
license - not tested
Not graded
quality - not tested
A
maintenance

Maintenance

Maintainers
Response time
Release cycle
1Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Use your own Word templates to convert Markdown → DOCX/PDF/HTML from any MCP-compatible AI.

  • Web scraping for AI agents. Converts URLs to clean, LLM-ready Markdown with anti-bot bypass.

  • Fonto (FontoXML) documentation for AI tools. Converts DITA XML to Markdown on demand.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/drsound/markdown-to-whatsapp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server