Export · Markdown

Your X bookmarks as plain Markdown

Markdown is the destination with no importer to learn and no vendor to trust, and the only question that really matters is how to wrap a post so that Markdown renders what the author wrote rather than reinterpreting it.

Where the Markdown comes from

Sift itself hands you a CSV — nine columns, one row per saved post. Markdown is one step away: the browser-side converter reads that file in the browser tab and writes Markdown back out, either as one file per bookmark or as a single document with a heading per bookmark. Nothing is uploaded, which is worth saying because a file full of things you found interesting is a reasonably intimate document.

What follows is about the output format rather than about any one application. If your destination is specifically an Obsidian vault, the vault-shaped version of this covers frontmatter keys, filename safety and tag rules; if you want a queryable table rather than files, the Notion database route is the other direction.

The escaping problem, which is the whole page

Post text is verbatim by design and by obligation: X’s display rules permit formatting changes and nothing else. Markdown makes that harder than it sounds, because a post is a plain string that Markdown is entitled to read as syntax. A post beginning ## thoughts on the release becomes a second-level heading. A post that starts a line with - becomes a bullet. Underscores in a handle become italics and disappear. None of that throws an error; the document just no longer says what the author said.

WrappingFaithful?Cost
Blockquote — > on every lineHeadings, lists and rules are neutralised. Emphasis and link syntax are not.Blank lines inside the post need their own > or the quote breaks in two.
Fenced block — ```Byte-faithful. Nothing inside is interpreted.Monospace, no clickable links, and a post that itself contains a fence breaks yours — use four backticks or a ~~~ fence.
Backslash escaping per CommonMarkFaithful, and still renders as prose.You have to escape the full punctuation set, not just the characters you thought of. Easy to half-do.
Raw paragraphNo.Nothing. This is the option that quietly rewrites posts.
A blockquote with emphasis characters escaped is the usual right answer: it reads like a quotation, which is what it is, and survives everything except a post that is itself Markdown.

A file per post, or one long file

For a single-file export, use ## per bookmark and reserve # for the document title. Plenty of tools — static site generators especially — assume exactly one first-level heading per document and will do something you did not ask for with a file containing four hundred of them. For a file per bookmark, the post ID makes the only safe filename; post text contains characters that are illegal in paths on at least one operating system you might sync through.

single-file shape
# Saved posts — exported 2026-09-07

## @rauchg · 14 Aug 2026

> the only two hard problems in caching

**Sift summary** — a one-line note on cache invalidation.
**Category** Engineering · **Tags** caching, infra, performance
[Original on x.com](https://x.com/rauchg/status/1795432198765432198)

---

Frontmatter travels less well than people assume

App or toolYAML frontmatterNote
ObsidianRead as PropertiesRenders as fields, and is queryable from Bases or Dataview.
Hugo, Jekyll, EleventyRead as page metadataThe reason frontmatter exists. Category and tags become taxonomy terms.
Zettlr, VS Code + extensionsReadDisplayed or folded depending on the extension.
Bear, iA Writer, UlyssesShown as literal textThree dashes and a block of key-value lines at the top of every note.
Logseq, RoamPartiallyBoth are block-based: each line becomes a block, and indentation is structure. A flat single-file import lands as one long list.
If the destination is in the bottom two rows, put the metadata in the body as a short line of bold labels instead. It reads better and cannot be misparsed.

Column to Markdown mapping

CSV columnMarkdown construct
post_idFilename, or a frontmatter value. Quote it if it goes in YAML.
post_urlA named link at the end of the entry. Never omitted — attribution is a display requirement, not a style choice.
author_handlePart of the entry heading, linked to the author page if you want it clickable.
posted_atHeading suffix, or frontmatter. Reformat freely; formatting is the one alteration that is allowed.
saved_atFrontmatter, or the sort key of a single-file export.
post_textThe wrapped block. See above.
ai_categoryA bold label, or a taxonomy term in a static site.
ai_tagsA comma-joined list, or #hashtags if the app supports them.
ai_summaryIts own labelled line, outside the quoted post.

Nothing to integrate with, and that is the point

There is no Markdown service to connect to. Files land in your downloads folder and you move them wherever you keep things, which also means this destination has no lock-in and no dependency on us continuing to exist. It is the format to choose if what you want is an archive rather than a workflow.

It is also the reason the boundary is a file rather than an API call. X’s developer policy restricts passing post content to third parties and carves out an exception for non-automated downloads; a folder of Markdown files is about as non-automated as software gets. The underlying data is read once, from a single bookmarks endpoint, and never re-fetched.

Two things that are true of every export

Sort them first, then export

An export is only worth having if the categories are. Connect X read-only, let Sift import and sort your newest bookmarks, and the file you download inherits that structure — category, tags and a one-line summary already attached to every row.

Connect X