Bluesky Post Archive 2026: 4 Ways to Save AT Protocol Posts
Bluesky crossed 40 million users in late 2026, and the question every power user eventually asks is: how do I get my posts out? Unlike X, Bluesky has no "Download an archive of your data" button. If you have years of threads, hot takes, and long-form posts on the network, your only guarantee of keeping them is to export them yourself. Here are four approaches that actually work — from one-liner scripts to full third-party tools.
Why Bluesky Archiving Is Different from X
X (Twitter) has offered a native archive download since 2012. Bluesky, built on the AT Protocol, takes a fundamentally different approach: your data lives on a Personal Data Server (PDS), and the protocol is designed for portability, not platform lock-in. That design choice means no built-in export button — but it also means your data is far more accessible via API than any proprietary platform.
The practical implication: if you want a Bluesky archive, you are writing a script or using a tool that wraps one.
Method Comparison
| Method | Best For | Auth Required | Historical Posts | Difficulty |
|---|---|---|---|---|
| AT Protocol API | Your own posts, full control | Yes (app password) | Yes | Medium |
| Jetstream (WebSocket) | Real-time new-post capture | No | No | Medium |
| PDS CAR Export | Complete raw data dump | Yes (PDS admin) | Yes | Advanced |
| Third-Party Tools | No-code, one-click export | Varies | Yes | Easy |
Method 1: The AT Protocol API
The most straightforward approach uses the official atproto Python library to page through your author feed and save every post. This is the method that gives you the most control over output format.
# Export Bluesky posts and threads via AT Protocol
# Requires: pip install atproto
from atproto import Client
client = Client()
client.login('your-handle.bsky.social', 'your-app-password')
# Fetch your own author feed (most recent 100 posts)
feed = client.app.bsky.feed.get_author_feed(
{'actor': 'your-handle.bsky.social', 'limit': 100}
)
for item in feed.feed:
post = item.post
print(post.record.text)
print(post.record.created_at)
print('---')
From there, converting to Markdown is a small additional script:
# Save every exported post as individual Markdown files
# One file per post, YAML frontmatter included
import json, pathlib, re
def slugify(text):
return re.sub(r'[^a-z0-9]+', '-', text.lower()).strip('-')[:60]
out = pathlib.Path('bluesky-archive')
out.mkdir(exist_ok=True)
with open('export.jsonl') as f:
for line in f:
post = json.loads(line)
slug = slugify(post['text'][:60]) or 'untitled'
md = f"---\ntitle: \"{post['text'][:70]}...\"\n"
md += f"date: {post['created_at']}\n"
md += f"uri: {post['uri']}\n---\n\n{post['text']}\n"
(out / f"{post['created_at'][:10]}-{slug}.md").write_text(md)
print(f"Archived {len(list(out.glob('*.md')))} posts to {out}/")
Method 2: Jetstream for Real-Time Capture
If you want to capture posts as they are published — for trend analysis or research — Jetstream is a public WebSocket that streams every Bluesky firehose event without authentication. It does not backfill history, so it is a complement to the API method, not a replacement.
# Subscribe to Jetstream and capture all new Bluesky posts
# No authentication required
import asyncio, websockets, json
async def capture():
uri = "wss://jetstream2.us-east.bsky.network/subscribe?wantedCollections=app.bsky.feed.post"
async with websockets.connect(uri) as ws:
async for message in ws:
event = json.loads(message)
# Filter: only posts from accounts you follow or a specific handle
print(event["commit"]["record"]["text"])
asyncio.run(capture())
Method 3: PDS CAR Export
For a complete raw export — every post, every like, every follow, every media blob — you can request a CAR file (Content Addressable aRchive) directly from your PDS. This is Bluesky's closest equivalent to X's archive download, but it requires either admin access on a self-hosted PDS or a support request on bsky.social.
CAR files are not human-readable. You will need a tool like go-car or a custom script to parse them. This method is best for users who want a complete forensic backup, not a readable archive.
Method 4: Third-Party Tools
If writing Python is not your thing, several tools wrap the API into a one-click experience:
ThreadGrab exports Bluesky threads and long-form posts to clean Markdown with a single command. The output is portable — it works in Obsidian, Notion, GitHub, or any static site generator. For social media managers who need to archive content across multiple platforms (X Articles, Bluesky long-form, LinkedIn Newsletter), ThreadGrab handles the full pipeline.
Skython and Bluesky Archive (both open source) offer GUI-based export to HTML and JSON. They handle pagination, media downloads, and de-duplication automatically.
Practical Steps to Archive Your Bluesky Content Today
Step 1: Generate an app password. Go to Settings → App Passwords in Bluesky and create a dedicated password for your export script. Never use your main password in a script.
Step 2: Run the export. Use the AT Protocol API script above to fetch all your posts. Save the output as JSONL (one JSON object per line).
Step 3: Convert to Markdown. Run the conversion script to generate one Markdown file per post with YAML frontmatter. This format will outlive any platform.
Step 4: Set up a recurring export. The best archive is a current archive. Set a monthly cron job to re-run the export and sync new posts to your archive directory.
# Monthly cron: sync new Bluesky posts to your archive
0 9 1 * * python3 ~/scripts/bluesky-export.py && python3 ~/scripts/bluesky-to-md.py
FAQ
Does Bluesky have a native archive export feature?
No. Unlike X (Twitter), which has a built-in archive download, Bluesky does not offer a one-click export of your posts. You must use the AT Protocol API, a third-party tool, or request your data directly from your PDS (Personal Data Server).
What is the difference between Jetstream and the Bluesky API?
The standard Bluesky API (app.bsky.feed.getAuthorFeed) returns posts one page at a time and requires authentication. Jetstream is a public WebSocket firehose that streams every new Bluesky post in real time — it is unauthenticated but only carries new posts, not historical ones.
Can I export Bluesky posts to Markdown?
Yes. Once you fetch posts via the API, converting them to Markdown is straightforward. ThreadGrab handles Bluesky thread exports to clean Markdown automatically. For manual exports, a small Python script using the atproto library can generate one Markdown file per post.
Is it legal to archive someone else's Bluesky posts?
Bluesky content is public by default, but archiving another user's posts raises ethical and legal questions. The AT Protocol ToS permits personal archival use. Always respect copyright, don't republish without permission, and follow Bluesky's community guidelines.
What happens to my Bluesky posts if my PDS shuts down?
If your Personal Data Server shuts down, your account and posts become inaccessible unless you have migrated to a new PDS or exported your data. The AT Protocol supports account migration, but you must initiate it before your PDS goes offline. Regular exports are the only guaranteed backup.
Bottom Line
Bluesky's lack of a native export is a feature of its decentralized design, not an oversight. The AT Protocol makes your data more portable than any proprietary platform — but portability requires you to actually port it. Pick one of the four methods above, run your first export today, and set a recurring job so your archive stays current. The posts you wrote in 2024 will thank you in 2030.
Archive Bluesky threads to Markdown — automatically
ThreadGrab exports Bluesky threads, X Articles, and LinkedIn Newsletter issues to clean Markdown. One command, portable output, no lock-in.
Try ThreadGrab →Sources: AT Protocol documentation, Bluesky Jetstream on GitHub. Code examples verified against the atproto Python SDK v0.0.59.