User Rating 0.0
Total Usage 0 times
Drop your .md file here or click to browse Supports Q:: / A:: delimiter format • Max 10 MB
Is this tool helpful?

Your feedback helps us improve.

About

Converting structured Markdown notes into Anki flashcards by hand is error-prone and slow. A misplaced delimiter or inconsistent header hierarchy silently drops cards from your import. This tool parses Markdown files that use Q:: and A:: delimiters within header-based sections (#, ##, ###), normalizes line endings across Windows (\r\n), macOS (\r), and Linux (\n), and outputs either the Pseudonium/Obsidian_to_Anki plugin format or tab-separated values for direct Anki import. It handles multi-line answers, nested code blocks, inline formatting, and generates hierarchical tags from your header structure automatically.

The original shell-script approach breaks on Windows due to carriage return handling and requires Node.js plus a specific folder structure. This browser-based converter eliminates those dependencies. It approximates the Obsidian_to_Anki plugin's START/END block syntax assuming Basic note type. Limitation: it does not process Obsidian-specific wiki-links ([[...]]) or embedded transclusions. Pro tip: keep your Q:: on a single line and let A:: span multiple lines. The parser treats everything after A:: until the next Q:: or header as the answer body.

markdown to anki flashcard converter obsidian to anki spaced repetition anki import Q&A parser markdown flashcards

Formulas

The parser operates in two passes. Pass 1 builds a section tree from Markdown headers. Pass 2 extracts Q&A pairs within each section.

normalize(input) input.replace(/\r\n|\r/g, "\n")

Line ending normalization replaces all Windows (\r\n) and legacy macOS (\r) line breaks with Unix (\n) before any parsing occurs.

headerPattern = /^(#{1,6})\s+(.+)$/gm

Headers are matched by leading # characters. The count of # determines depth d where 1 d 6. Each header creates a tag segment.

tag(card) = deck :: join(ancestors, ::)

Tags are built hierarchically. A card under ## Chapter 1 ### Section A generates tag deck::Chapter_1::Section_A.

questionPattern = /^Q::\s*(.+)/

answerPattern = /^A::\s*([\s\S]+?)(?=^Q::|^#{1,6}\s|\Z)/gm

Where Q:: marks the question (single line) and A:: captures everything until the next question, header, or end of file. The lazy quantifier +? prevents overmatching across sections.

Variable legend: input = raw file text. d = header depth level. deck = user-specified deck name. ancestors = array of parent header names from root to current section. card = a single Q&A pair object containing question text, answer text, tags, and source section.

Reference Data

FeatureThis ToolManual Copy-PasteNode.js ScriptObsidian_to_Anki Plugin
Cross-platform line endings✓ Auto-normalizedN/A✗ Linux only
No installation required✓ Browser-based✗ Node.js required✗ Obsidian + Plugin
Folder structure dependency✗ None✗ None✓ Specific nesting✗ Vault structure
Multi-line answersProne to errorPartial
Code block preservation✓ Fenced blocks keptFormatting lostPartial
Auto-tagging from headers✓ Hierarchical
Export: Obsidian_to_Anki formatNative
Export: Anki TSV importManual
Inline Markdown rendering✓ Bold, italic, code, linksN/APartial
Live card preview
Max file size10 MBN/AOS-dependentVault-dependent
Supported delimitersQ:: / A::AnyQ:: / A::Configurable
Header depth supported# through ###### (6 levels)N/A# onlyConfigurable
Wiki-link support✗ Plain text passthroughN/A
Batch processingSingle file per conversionN/ASingle fileEntire vault
Offline capable✓ Fully client-side

Frequently Asked Questions

Fenced code blocks (delimited by triple backticks ```) are detected before header parsing. The parser tracks a boolean state for "inside code block". Any line starting with # inside a fenced block is treated as literal text, not a header. The answer capture continues across the code block until a genuine Q:: or header outside a code block is found.
The card is still created with an empty answer field. A warning badge appears on that card in the preview, colored amber, indicating a missing answer. The export includes the card with a blank answer - Anki will import it, but you should review flagged cards before studying.
No. Any header-level line (starting with one or more # followed by a space) terminates the current answer block and begins a new section. If you need header-like formatting inside an answer, use bold (**text**) or uppercase text instead. This is a deliberate design constraint matching the Obsidian_to_Anki plugin's behavior.
Tags use Anki's :: separator for hierarchy. A card under # Topic > ## Chapter > ### Section produces the tag Topic::Chapter::Section (spaces replaced with underscores). Anki's tag browser renders these as a collapsible tree. Maximum depth is 6 levels matching Markdown's header limit. Empty or whitespace-only header names are replaced with "Untitled".
The Obsidian_to_Anki format produces a .md file with START/END blocks, note type declarations, and tag metadata - designed to be placed in your Obsidian vault and synced via the Pseudonium plugin. The TSV format produces a tab-separated .txt file (questionanswertags) that you import directly into Anki via File > Import. TSV converts Markdown formatting to basic HTML (bold, italic, code). Choose TSV if you don't use Obsidian.
Parsing runs on the main browser thread. A 10 MB Markdown file could contain over 100,000 Q&A pairs. DOM manipulation for the live preview at that scale would freeze the UI. The 10 MB limit keeps parsing under 2 seconds on mid-range hardware. Typical flashcard files (500-2000 cards) are under 500 KB. If you have larger files, split them by top-level header before converting.