Xtracticle - Save X Articles and threads as PDF, Markdown or EPUB

Xtracticle turns X (Twitter) Articles, threads and posts into files you own: PDF, Markdown (optional YAML front-matter), EPUB for Kindle, or a ZIP with every image. New since v1: threads unrolled from any post, batch mode (20 links to one ZIP), an iPhone Shortcut, 7 languages, and a free MCP server so Claude, ChatGPT and Cursor can read X posts as Markdown. Tip: swap x.com for xtracticle.com in any post URL. Free, open source, no login.

Add a comment

Replies

Best
Hi Product Hunt! I'm Ahmet, the maker of Xtracticle. It first launched here in April; this is a relaunch because a lot has changed. Why I built it: X Articles can run to 100,000 characters, and they're hard to keep. There's no export button, print-to-PDF breaks the layout, and posts can disappear. I wanted a clean file I own. What's new since v1: - Threads from any post (first, middle or last); other people's replies are left out - EPUB 3 for Kindle, Kobo and Apple Books, plus a ZIP with every image - Batch mode: up to 20 links into one ZIP - PDFs built page by page, so long articles work on phones too - An iPhone/iPad Shortcut and an Android share target - 7 languages: English, Español, Português, 日本語, 简体中文, العربية, Türkçe - A free MCP server: add to Claude, ChatGPT or Cursor and they can read X posts as Markdown Free for good: every format, no login, no ads. The code is MIT: Honest limits: videos become linked thumbnails, private and deleted posts can't be fetched, and post data comes from the open FxTwitter API. If an article converts badly, or a format you need is missing, drop the link below and I'll look at it.

the MCP server is the part that caught my eye, I've got a daily claude code loop that already has to deal with X links showing up in research tasks and right now it just can't read them at all. the "swap for xtracticle.com" trick is clever for a human doing it manually, but does the MCP server handle that translation itself, or does the agent still need to know to rewrite the URL before it can call the tool

 Thanks Gal, that's exactly the use case I built it for. No rewriting needed: the tool takes the X link as-is. and links work, mirror links (fxtwitter, nitter, xcancel) and bare post IDs too. So your loop can pass whatever URL it finds straight to read_x_post.

For Claude Code it's one line:

claude mcp add --transport http xtracticle

A few things that help in a research loop:

- Paste any post of a thread and you get the author's whole thread in order

- Long Articles come back in pages (max_chars / offset), so they don't blow up your context

- Every result includes the title, author, date and source link, so citations are easy

The only link it can't take is the ... reader URL; it needs the post link (...). Also, it's a free server with a per-IP rate limit, so it's fine for a daily loop but not for bulk scraping.

If you try it, I'd love to hear how it behaves in your loop!

 that one line setup is exactly what I needed, thanks. going to wire it in this week. one more question before I do - when the per-IP rate limit hits, does the MCP call fail loud (clean error the agent can catch and retry later) or does it degrade quietly, like returning a partial/truncated result that looks valid? for a daily unattended loop the second one is way scarier than the first, since nothing would flag it as broken

 Great question, and it fails loud. There's no silent degradation by design:

- Rate limit: over 40 requests in 10 seconds from one IP gets an HTTP 429 at the edge for 10 seconds, so the MCP call errors out and your agent can back off and retry. A daily loop won't come close to that.

- Long articles: never silently cut. If a document is split, the result has truncated: true, end and totalChars in the structured output, plus a visible note at the end of the text telling the agent which offset to continue from.

- Deleted/private posts or bad links: the tool returns isError: true with a plain explanation, not an empty or partial result.

The one thing to know: if the upstream data source (FxTwitter) is down, I serve the last copy fetched within the past 7 days instead of failing, and mark it with stale: true in the metadata. If freshness matters for your loop, check that flag.

So for an unattended loop, check isError, truncated and stale, and you'll never get a partial result that looks valid.

 Glad it helped! If anything looks off once it's running in your loop (a post that converts badly, a weird error, a missing field), open an issue at or reply here and I'll take a look. Good luck with the setup!