Markdown-to-Image-API: PNG mit cURL, Node.js, Python und n8n erzeugen
Für ein einzelnes Bild reicht ein manueller Export. Wenn ein Produkt jedoch jeden KI-Bericht, Changelog, Support-Text oder Social-Post in eine einheitliche Grafik verwandeln soll, wird Handarbeit zum Engpass. Eine Markdown-to-Image-API verlagert das Rendering in den Code: Markdown senden, Format und Theme wählen, eine URL oder Binärdatei erhalten und das Ergebnis am gewünschten Ort speichern.
Dieser Leitfaden baut eine echte Integration mit der MarkdownToImage-API auf. Zuerst prüfen wir den Aufruf mit cURL, danach setzen wir denselben Ablauf in Node.js, Python und n8n um. Zum Schluss ergänzen wir die Schutzmaßnahmen, die in kurzen Quickstarts oft fehlen.
Endpoint und Limits wurden am 2. August 2026 anhand der offiziellen API-Dokumentation geprüft. Kontingente und Tarife können sich ändern; vor einer Kostenplanung solltest du die aktuelle Preisseite kontrollieren.
Eine API ist sinnvoll, wenn die Bilderzeugung Teil eines wiederholbaren Workflows und keine gelegentliche Designaufgabe ist. Typische Beispiele sind:
- eine LLM-Antwort als herunterladbares Berichtsbild ausgeben;
- nach einem Deployment automatisch Release-Karten erzeugen;
- Open-Graph- oder Social-Karten aus CMS-Feldern erstellen;
- Code, Tabellen, Mermaid-Diagramme oder KaTeX-Formeln einheitlich rendern;
- visuelle Artefakte in n8n, Dify, Make, CI oder internen Tools erzeugen.
Für einen einmaligen Export bleibt ein Browser-Konverter oft schneller. Die API spielt ihre Stärke aus, wenn die Eingabe bereits in einem anderen System liegt, derselbe Stil häufig wiederholt werden muss oder das Ergebnis automatisch in Speicherung, Veröffentlichung oder Messaging weiterläuft.
Melde dich bei MarkdownToImage an und erstelle im Bereich API Tokens einen Token. Behandle ihn wie ein Passwort: Er gehört weder in Quellcode und Markdown-Dateien noch in Screenshots, Browser-JavaScript oder exportierte Workflow-Dateien.
Für lokale Tests legst du ihn als Umgebungsvariable ab:
export MARKDOWN_TO_IMAGE_API_TOKEN="mti_your_token_here"
In Produktion solltest du den verschlüsselten Secret-Speicher deiner Hosting-Plattform verwenden. Taucht ein Token in einem öffentlichen Repository oder Log auf, widerrufe ihn und erstelle einen neuen, statt nur den alten Commit zu verstecken.
Die API bietet derzeit ein monatliches Freikontingent mit Wasserzeichen. Wasserzeichenfreie und höhere Nutzung hängt von Credits oder dem aktuellen Tarif ab. Prüfe API- und Preisseite bei der Implementierung und hinterlege die heutige Quote nicht als dauerhafte Produktannahme.
Der Generierungs-Endpoint akzeptiert JSON und verwendet Bearer-Authentifizierung. Dieser Request erzeugt ein 1200 Pixel breites PNG im dunklen GitHub-Theme:
curl -X POST https://markdowntoimage.com/api/v1/images/generate \
-H "Authorization: Bearer $MARKDOWN_TO_IMAGE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"markdown": "# Weekly release\n\n- Faster exports\n- Clearer reports\n- One automated workflow",
"format": "png",
"width": 1200,
"quality": 2,
"theme": "github-dark",
"mode": "url"
}'
Eine erfolgreiche Antwort im URL-Modus enthält data.imageUrl. Die Adresse ist temporär: Sie im Browser zu öffnen bestätigt nur das Rendering, ersetzt aber keine dauerhafte Speicherung. Lade die Datei zeitnah herunter und übertrage sie in deinen eigenen Objektspeicher, dein CMS oder deine Mediathek.
Nur markdown ist verpflichtend. Für automatisierte Ausgaben solltest du die Einstellungen dennoch explizit setzen, damit das Ergebnis reproduzierbar bleibt.
| Parameter | Steuerung | Praktische Wahl |
|---|---|---|
markdown | Quellinhalt | Länge und Pflichtabschnitte vor dem Senden prüfen |
format | png, jpeg, webp oder pdf | PNG für Code und UI, WebP für kleine Webdateien, PDF für Dokumente |
width | Renderbreite von 200 bis 2560 Pixel | Für Social- und Berichtskarten bei 1200 beginnen und echte Inhalte testen |
quality | Geräteskalierung von 1 bis 3 | Mit 2 starten; höhere Werte erhöhen meist Dateigröße und Renderaufwand |
theme | Gesamtes Erscheinungsbild | Ein benanntes Theme festlegen, damit Releases den Stil nicht unerwartet ändern |
codeStyle | Farbpalette der Syntaxhervorhebung | Auf ausreichenden Kontrast zum Seitentheme achten |
fontFamily | Schrift-Voreinstellung | Alle Sprachen des Produkts testen |
mode | Antwort als url oder binary | URL für Orchestrierung, Binary für direkte Dateipipelines |
JPEG passt zu fotografischem Material, wenn verlustbehaftete Kompression akzeptabel ist. PNG eignet sich für Code, Diagramme und scharfe UI-Elemente. WebP spart Bandbreite, sofern alle Empfänger es unterstützen. PDF wird zwar über denselben Endpoint erzeugt, ist aber eine Dokumentausgabe und keine normale Social-Grafik.
Das folgende Node.js-Skript ruft die API auf, prüft die HTTP-Antwort, lädt das temporäre Ergebnis herunter und schreibt eine echte Datei. Es nutzt das globale fetch aktueller Node.js-Versionen.
import { writeFile } from "node:fs/promises";
const token = process.env.MARKDOWN_TO_IMAGE_API_TOKEN;
if (!token) throw new Error("MARKDOWN_TO_IMAGE_API_TOKEN is required");
const response = await fetch("https://markdowntoimage.com/api/v1/images/generate", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
markdown: "# Build report\n\n- Tests: **passed**\n- Deploy: **ready**",
format: "png",
width: 1200,
quality: 2,
theme: "github-dark",
mode: "url",
}),
signal: AbortSignal.timeout(30_000),
});
if (!response.ok) {
throw new Error(`Generation failed: ${response.status} ${await response.text()}`);
}
const result = await response.json();
const imageResponse = await fetch(result.data.imageUrl, {
signal: AbortSignal.timeout(30_000),
});
if (!imageResponse.ok) {
throw new Error(`Download failed: ${imageResponse.status}`);
}
await writeFile("build-report.png", Buffer.from(await imageResponse.arrayBuffer()));
console.log("Saved build-report.png");
In einem Webdienst sollte der Auftrag erst nach dem permanenten Upload als erfolgreich gelten. Nur die temporäre API-URL zu speichern, ohne die Datei zu kopieren, führt nach Ablauf der URL zu einem verzögerten Ausfall.
Im URL-Modus folgt Python demselben Muster mit zwei Requests: zuerst rendern, dann herunterladen. Explizite Timeouts verhindern, dass ein Worker unbegrenzt wartet.
import os
from pathlib import Path
import requests
token = os.environ["MARKDOWN_TO_IMAGE_API_TOKEN"]
payload = {
"markdown": "# Build report\n\n- Tests: **passed**\n- Deploy: **ready**",
"format": "png",
"width": 1200,
"quality": 2,
"theme": "github-dark",
"mode": "url",
}
response = requests.post(
"https://markdowntoimage.com/api/v1/images/generate",
headers={"Authorization": f"Bearer {token}"},
json=payload,
timeout=30,
)
response.raise_for_status()
image_url = response.json()["data"]["imageUrl"]
image_response = requests.get(image_url, timeout=30)
image_response.raise_for_status()
Path("build-report.png").write_bytes(image_response.content)
print("Saved build-report.png")
Bei wachsendem Volumen gehört diese Funktion in eine Job Queue statt in einen langen, nutzerseitigen Request. Die Queue begrenzt Parallelität und Wiederholungen und bietet einen Ort für die endgültige Speicher-URL.
Setze in n8n einen HTTP-Request-Node hinter den Node, der Markdown erzeugt oder lädt. Speichere den Token in n8n Credentials, nicht direkt im Workflow-JSON.
Method: POST
URL: https://markdowntoimage.com/api/v1/images/generate
Authentication: Header Auth
Header name: Authorization
Header value: Bearer {{$credentials.markdownToImageToken}}
Send Body: JSON
Body:
{
"markdown": "{{$json.content}}",
"format": "png",
"width": 1200,
"quality": 2,
"theme": "github-dark",
"mode": "url"
}
Verbinde einen zweiten HTTP-Request-Node, der {{$json.data.imageUrl}} herunterlädt und Dateiausgabe aktiviert. Danach sendest du die Binärdatei an S3, Google Drive, Directus, WordPress, Slack oder das nächste Ziel. Definiere den Fehlerzweig ausdrücklich, damit Authentifizierungs- oder Quotenfehler keinen leeren Datensatz veröffentlichen.
Wähle den URL-Modus, wenn deine Automatisierungsplattform JSON gut verarbeitet und einen zweiten Download ausführen kann. Das ist bequem für Queues, Webhooks und No-Code-Workflows. Die zurückgegebene URL bleibt jedoch nur vorübergehend erhalten, laut aktueller Dokumentation 24 Stunden.
Wähle Binary, wenn eine Antwort direkt in den Speicher gestreamt werden soll. Damit entfällt der zweite HTTP-Aufruf, aber der Client muss Binärinhalt, Content-Type, Dateiendung, Speichergrenzen und die Bereinigung unvollständiger Uploads korrekt behandeln.
Speichere das endgültige Asset unabhängig vom Modus in einem Speicher unter deiner Kontrolle. Halte zusätzlich Format, Breite, Theme, Quell-ID, Erzeugungszeit und einen Hash des Markdowns fest. Das erleichtert Deduplizierung und Fehleranalyse.
Die API dokumentiert diese wichtigen Ergebnisse:
| HTTP-Status | Bedeutung | Empfohlene Aktion |
|---|---|---|
400 | Markdown fehlt oder Parameter sind ungültig | Unveränderte Eingabe nicht wiederholen; Payload validieren |
401 | Token fehlt, ist ungültig oder widerrufen | Stoppen und alarmieren; Secret korrigieren oder rotieren |
429 | Freikontingent oder Credits sind nicht verfügbar | Job verschieben, Verantwortliche informieren oder Kapazität erhöhen |
500 | Generierungs- oder interner Fehler | Begrenzte Wiederholungen mit Backoff verwenden |
Automatische Wiederholungen sollten nur vorübergehende Fehler betreffen, nicht jede Antwort außerhalb 200. Für 500 und Netzwerk-Timeouts eignet sich exponentielles Backoff mit Jitter. Prüfe vor einem Retry nach unklarem Verbindungsabbruch, ob bereits ein Ergebnis für denselben Inhalts-Hash gespeichert wurde. So erzeugt ein logischer Job nicht mehrere kostenpflichtige Renderings.
Protokolliere Statuscode, Provider-Fehlercode, Job-ID, Versuch und Latenz, aber niemals den vollständigen Authorization-Header.
Vor echtem Traffic sollten folgende Punkte erfüllt sein:
- API-Token liegt in einem verschlüsselten serverseitigen Secret-Speicher;
- Verbindungs- und Gesamt-Timeouts sind gesetzt;
- Wiederholungen sind begrenzt und nutzen exponentielles Backoff mit Jitter;
- Worker-Parallelität passt zu Quote und nachgelagertem Speicher;
- Markdown-Größe und Pflichtfelder werden vor dem API-Aufruf validiert;
- Format, Breite, Theme, Code-Stil und Schrift sind festgelegt;
- Ergebnisse im URL-Modus werden sofort dauerhaft gespeichert;
- Dateinamen sind sicher und deterministisch, nicht direkt aus Nutzereingaben übernommen;
- veröffentlichte Bilder erhalten Alt-Text und sinnvollen Kontext;
- Nutzung wird gemessen und vor Quotenende alarmiert;
- mehrsprachige Schriften, lange Codezeilen, Tabellen, Mermaid und KaTeX werden mit echten Inhalten getestet;
- geschäftskritische Veröffentlichungen haben einen manuellen Fallback.
Beginne mit einem kleinen, repräsentativen Testset. Zehn echte Markdown-Beispiele decken mehr Layoutprobleme auf als Hunderte „Hello World“-Aufrufe.
Ja. Sende format: "png" an den Generierungs-Endpoint. JPEG, WebP und PDF sind ebenfalls möglich. Für Code, Text, Diagramme und UI-Screenshots ist PNG meist die sicherste Wahl.
Ein geheimer API-Token darf nicht im Client-Code stehen. Rufe die API über Server, Serverless Function oder einen geschützten Automatisierungs-Workflow auf und gib dem Browser anschließend nur das dauerhaft gespeicherte Ergebnis.
Übertrage die Markdown-Ausgabe nach eigenen Längen-, Inhalts- und Sicherheitsprüfungen in das Feld markdown. Eine stabile Prompt-Vorlage und festgelegte Renderparameter liefern konsistentere Karten, als wenn jede Antwort ihr Layout selbst bestimmt.
Für lineare Abläufe aus Erzeugen, Herunterladen und Hochladen reicht n8n. Anwendungscode ist sinnvoll bei hoher Parallelität, eigener Idempotenz, detaillierter Beobachtbarkeit oder enger Verzahnung mit Berechtigungen und Abrechnung.
Nimm ein Markdown-Dokument, das dein Produkt bereits erzeugt, und führe das cURL-Beispiel damit aus. Prüfe Zeilenumbrüche in Code, Tabellen, Schriften und Bildgröße, bevor du den Workflow ausweitest.
Wenn das erste Rendering passt, öffne den MarkdownToImage-API-Leitfaden, erstelle einen serverseitigen Token und überführe das Node.js-, Python- oder n8n-Rezept in einen kleinen Produktionstest. Sicher startest du mit einem realen Inhaltstyp, einem festen visuellen Preset, dauerhaftem Speicher und beobachtbarer Fehlerbehandlung und skalierst erst danach anhand der Ergebnisse.