Bluesky Historical Archive Scraper - Old Posts by Date & Author
Pricing
from $1.50 / 1,000 results
Bluesky Historical Archive Scraper - Old Posts by Date & Author
Scrape the full public post history of any Bluesky account by date, author, and thread via the keyless AT-Protocol API. Posts, replies, reposts, profiles, thread trees, and list feeds. No API key, no login, no cookies.
Pricing
from $1.50 / 1,000 results
Rating
0.0
(0)
Developer
Logiover
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 days ago
Last modified
Categories
Share
Bluesky Historical Archive Scraper — Old Posts by Date, Author & Thread
Scrape the full public post history of any Bluesky account — years of old posts, replies and reposts, by date and by author — content that Bluesky's own on-app search and search API can no longer reach. This Bluesky historical scraper walks each account's AT-Protocol author feed page by page, all the way back to the account's very first post, so you can pull a deep archive, expand entire thread and reply trees, dump curated list feeds and enrich every row with the author's follower, following and post counts. Point it at handles, DIDs, profile URLs, post URLs or Bluesky list URIs and get clean, flat rows. Fast, no browser, no Bluesky login, no app password, no API key, no OAuth.
🦋 Why this Bluesky historical scraper?
Full account history in flat rows · thousands of posts per run · reply-tree reconstruction · date-bounded windows back to an account's first post · author profile enrichment · export to JSON / CSV / Excel. The unofficial Bluesky / AT-Protocol API alternative for archival, research, AI training corpora, brand monitoring and lead-gen.
✨ What does the Bluesky Historical Archive Scraper do?
This Actor is a keyless historical harvester for Bluesky built directly on the public AT-Protocol XRPC API (public.api.bsky.app). Its backbone is app.bsky.feed.getAuthorFeed, which it paginates via the returned cursor until the cursor runs out — reaching an account's entire archive of original posts, replies and reposts, far past what Bluesky's app shows before it stops loading. Each post is flattened into a single tidy row with engagement counts (likes, reposts, replies, quotes), media detection, reply/thread references and ISO timestamps. Optional modes fetch full reply trees (getPostThread), pull curated list feeds (getListFeed) and enrich every author once via getProfile. Date filtering is applied client-side on createdAt, and because feeds are newest-first, pagination stops early on time-bounded windows. It runs with no app password, no OAuth, no session and no cookies — only public endpoints.
👥 Who is it for?
- Academic researchers & social scientists studying how a community, topic or account evolved over time on Bluesky.
- AI / NLP & ML teams building domain-specific training corpora from years of real, public conversational text.
- Brand, PR & reputation analysts archiving everything an account (or a curated list of accounts) has ever posted.
- Data journalists & OSINT analysts reconstructing timelines, threads and reply networks around an event or figure.
- Growth & lead-gen teams collecting active, follower-ranked authors and their posting cadence for outreach.
🎯 Use cases
- Full-account backfill — pull every post an account has ever made into a spreadsheet or warehouse in one run.
- Date-bounded historical windows — grab a news outlet's posts from a specific month or year with
afterDate/beforeDate. - Thread & conversation reconstruction — expand any post into its complete flat reply tree for discourse analysis.
- List-wide monitoring — scrape every post surfaced by a curated Bluesky list (a community, a beat, a competitor set).
- Influence & audience mapping — enrich each post with the author's follower/following/post counts to rank reach.
🏆 Why use the Bluesky Historical Archive Scraper?
- 🔑 Fully keyless — no app password, no OAuth token, no session, no cookies, no developer account. It reads only public AT-Protocol endpoints.
- 📚 Whole-archive depth — cursor pagination reaches an account's first-ever post, well beyond what the Bluesky app or search will surface.
- 🧾 24 clean fields per row — text, timestamps, engagement counts, author enrichment, media type, reply/thread links and a ready-to-open post URL.
- 🧵 Multi-mode targeting — mix author history, individual post threads and curated list feeds in a single run.
- 🗓️ Precise date filters + caps —
afterDate,beforeDate,maxPostsPerActorand a globalmaxItemsgive you exact control over volume and cost. - 📤 Export anywhere — download as JSON, CSV, Excel, HTML, XML or JSONL, or stream via the Apify API, webhooks and integrations. Simple pay-per-result pricing.
📊 What data can you extract?
Every post, reply and repost is returned as one flat row. The type field tells you whether it is an original post, a reply, or a repost. Here is the complete field reference:
| Field | Type | Description |
|---|---|---|
uri | string | The post's AT-URI (at://did:plc:.../app.bsky.feed.post/<rkey>) — the stable global identifier. |
cid | string | Content identifier (IPLD CID) of the post record. |
url | string | Ready-to-open web URL: https://bsky.app/profile/<handle>/post/<rkey>. |
type | string | post, reply, or repost. |
text | string | The full post text (plain UTF-8, emojis included). |
createdAt | date | ISO timestamp the author set when the post was created. |
indexedAt | date | ISO timestamp Bluesky's AppView indexed the post. |
lang | string | Primary declared language tag (e.g. en, ja), when present. |
authorDid | string | The author's decentralized identifier (DID). |
authorHandle | string | The author's handle (e.g. nytimes.com). |
authorDisplayName | string | The author's display name. |
authorFollowers | number | Author's follower count (when profile enrichment is on). |
authorFollowing | number | Number of accounts the author follows. |
authorPostsCount | number | Author's lifetime post count. |
replyCount | number | Replies to this post. |
repostCount | number | Reposts of this post. |
likeCount | number | Likes on this post. |
quoteCount | number | Quote-posts of this post. |
isReply | boolean | true if the post is a reply to another post. |
replyToUri | string | AT-URI of the immediate parent post (if a reply). |
rootUri | string | AT-URI of the thread root (if a reply). |
hasMedia | boolean | true if the post embeds images or video. |
mediaType | string | image, video, external (link card), quote, or empty. |
linkUrl | string | First media URL (image/video) or external link-card URL. |
threadRepliesFetched | number | How many replies were pulled for this post in thread mode. |
Example output row
{"uri": "at://did:plc:eclio37ymobqex2ncko63h4r/app.bsky.feed.post/3mr7upflb242n","cid": "bafyreib2r...","url": "https://bsky.app/profile/nytimes.com/post/3mr7upflb242n","type": "post","text": "Japan's Prime Minister Sanae Takaichi has ...","createdAt": "2026-07-22T08:10:04.551Z","indexedAt": "2026-07-22T08:10:05.012Z","lang": "en","authorDid": "did:plc:eclio37ymobqex2ncko63h4r","authorHandle": "nytimes.com","authorDisplayName": "The New York Times","authorFollowers": 1336639,"authorFollowing": 120,"authorPostsCount": 40057,"replyCount": 42,"repostCount": 68,"likeCount": 86,"quoteCount": 9,"isReply": false,"replyToUri": null,"rootUri": null,"hasMedia": false,"mediaType": "external","linkUrl": "https://www.nytimes.com/2026/07/22/world/asia/japan-takaichi.html","threadRepliesFetched": 0}
🚀 How to use
You can target Bluesky in three ways — combine them freely in one run.
Option A — Full account history (by handle, DID or profile URL)
The most common mode. List one or more accounts in actors. Each is paginated back to its first post. Add a date window and caps to control depth.
{"actors": ["nytimes.com", "did:plc:z72i7hdynmk6r22z27h6tvur"],"feedFilter": "posts_no_replies","afterDate": "2024-01-01","beforeDate": "2024-12-31","maxPostsPerActor": 2000,"includeProfiles": true}
- Paste handles (
nytimes.com), DIDs (did:plc:...) or profile URLs (https://bsky.app/profile/nytimes.com) intoactors— a leading@and any URL wrapper are stripped for you. - Optionally set
feedFilter, a date window andmaxPostsPerActor. - Click Start. Watch rows stream into the Output tab.
Option B — Individual posts with their reply trees
Pass post URLs or AT-URIs to postUrls and turn on expandThreads to pull each post's full conversation as flat rows.
{"postUrls": ["https://bsky.app/profile/bsky.app/post/3mqc36slinc2m"],"expandThreads": true,"threadDepth": 10}
Option C — A curated Bluesky list
Pass list AT-URIs to lists to harvest every post surfaced by that list.
{"lists": ["at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.graph.list/3abc..."],"maxPostsPerActor": 5000,"maxItems": 20000}
⚙️ Input parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
actors | array | ["nytimes.com","bsky.app"] | Handles, DIDs or profile URLs to pull full history for. |
lists | array | [] | Bluesky list AT-URIs (list-feed mode). |
postUrls | array | [] | Individual post URLs or AT-URIs to fetch with their thread. |
feedFilter | string | posts_with_replies | posts_with_replies, posts_no_replies, posts_with_media, or posts_and_author_threads. |
afterDate | string | null | Only posts created after this date (YYYY-MM-DD or ISO). Stops pagination early. |
beforeDate | string | null | Only posts created before this date. |
maxPostsPerActor | integer | 1000 | Hard cap on posts per account / list. |
expandThreads | boolean | false | Also fetch each post's reply tree and emit replies as rows. |
threadDepth | integer | 6 | Reply levels to walk when expandThreads is on (0–1000). |
includeProfiles | boolean | true | Enrich rows with author follower/following/post counts (cached per author). |
maxItems | integer | 0 | Global cap across everything. 0 = unlimited. |
proxyConfiguration | object | Apify Proxy on | Proxy settings; each retry rotates to a fresh IP. |
Full input example
{"actors": ["nytimes.com", "bsky.app"],"lists": [],"postUrls": [],"feedFilter": "posts_with_replies","afterDate": null,"beforeDate": null,"maxPostsPerActor": 1000,"expandThreads": false,"threadDepth": 6,"includeProfiles": true,"maxItems": 0,"proxyConfiguration": { "useApifyProxy": true }}
💡 Tips for best results
- Reach the full archive — set
maxPostsPerActorhigh (e.g.50000) and leavemaxItemsat0to pull an account's entire history. - Bound by time cheaply — set
afterDate; because feeds are newest-first, the scraper stops paging as soon as it crosses that date, saving results and time. - Drop the noise — use
feedFilter: "posts_no_replies"when you only want an account's original posts, not its replies to others. - Media-only slices —
feedFilter: "posts_with_media"returns just posts that carry images or video. - Reply trees cost more —
expandThreadsmultiplies volume; keepthreadDepthmodest (6–10) unless you truly need deep nesting. - Handles vs DIDs — both work; DIDs are permanent, so prefer them for long-running scheduled jobs (handles can change).
- Strip nothing — you can paste raw
@handleor a fullhttps://bsky.app/profile/...URL; the Actor normalizes it. - Cache is automatic — each author's profile is fetched only once per run, so enrichment adds little overhead even on big feeds.
- Reposts are included — in
posts_with_repliesan account's reposts appear astype: "repost"with the original author's handle. - Scale with the global cap — for multi-account jobs, set
maxItemsto bound total cost regardless of how big any one account is.
🔌 Integrations
Push your Bluesky archive anywhere. From the Apify platform you can:
- Google Sheets — sync the dataset straight into a spreadsheet for analysts.
- Slack / Discord — post run summaries or new-post alerts to a channel.
- Zapier / Make / n8n — trigger downstream workflows on each finished run.
- Webhooks — POST the dataset to your own endpoint the moment a run completes.
- Schedule — run daily or hourly to keep a rolling archive of an account, list or beat fresh.
🛠️ API usage
Run the Actor programmatically with the Apify API or clients.
cURL
curl -X POST "https://api.apify.com/v2/acts/logiover~bluesky-historical-archive-scraper/runs?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"actors":["nytimes.com"],"maxPostsPerActor":500,"afterDate":"2025-01-01"}'
Node.js (apify-client)
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_TOKEN' });const run = await client.actor('logiover/bluesky-historical-archive-scraper').call({actors: ['nytimes.com', 'bsky.app'],feedFilter: 'posts_no_replies',maxPostsPerActor: 1000,includeProfiles: true,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items);
Python (apify-client)
from apify_client import ApifyClientclient = ApifyClient("YOUR_TOKEN")run = client.actor("logiover/bluesky-historical-archive-scraper").call(run_input={"actors": ["nytimes.com"],"afterDate": "2025-01-01","maxPostsPerActor": 1000,})for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item["authorHandle"], item["likeCount"], item["text"][:80])
🤖 Use with AI agents (MCP)
This Actor works as a tool for AI agents through the Apify MCP Server, so an LLM agent can pull Bluesky history on demand. Connect the Apify MCP server to your agent, then prompt it naturally — for example: "Use the Bluesky Historical Archive Scraper to fetch the last 500 posts from nytimes.com created after 2025-01-01, then summarize the main themes." The agent calls the Actor, receives the flat dataset and reasons over it.
❓ Frequently Asked Questions
Do I need a Bluesky API key, app password or login?
No. The scraper reads only public AT-Protocol endpoints on public.api.bsky.app, so no app password, OAuth token, session or cookie is ever required to pull old posts, threads or author profiles.
How far back can it scrape a Bluesky account?
All the way to the account's first-ever post. The Actor paginates the author feed via its cursor until the cursor is exhausted, which reaches the entire public archive — far deeper than the Bluesky app loads before it stops.
How many posts can I get per run?
Thousands. A single account can yield tens of thousands of rows; multiple accounts or a big list scale further. Use maxPostsPerActor and the global maxItems to control volume and cost.
Can I scrape Bluesky posts by date?
Yes. Set afterDate and/or beforeDate (YYYY-MM-DD or full ISO). Because feeds are newest-first, pagination stops early once posts fall before afterDate, so time-bounded windows are fast and cheap.
Does it work by handle or by DID?
Both. Paste a handle (nytimes.com), a DID (did:plc:...) or a full profile URL. Handles are resolved automatically. DIDs are permanent, so they are the safer choice for scheduled jobs.
Can it fetch replies and full threads?
Yes. Turn on expandThreads and set threadDepth to walk each post's reply tree via getPostThread. Every reply is returned as its own flat row, so you can reconstruct entire conversations.
Why not use Bluesky's search endpoint?
Bluesky's searchPosts endpoint is edge-restricted and returns errors to server-side callers, so this Actor deliberately builds on the reliable, keyless author-feed, thread and list endpoints instead — which also reach far deeper history than search does.
The run returned zero results — what went wrong?
Check that the handle/DID/URL is correct and the account is public, and that any date window actually contains posts. A private, deactivated or misspelled account returns nothing; the run still exits cleanly with a warning in the log.
Why are some fields null?
Not every post has media, a language tag, or reply references, so linkUrl, lang, replyToUri and rootUri can be null. Author enrichment fields are null when includeProfiles is off or a profile can't be fetched.
How do I export old Bluesky posts to CSV or JSON?
Run the scraper, then download the dataset as CSV, JSON, Excel, HTML, XML or JSONL straight from the Apify Console, or pull it through the API. Every post is a flat row, so it imports cleanly into spreadsheets and databases.
How do I download a Bluesky account's entire post history?
Add the handle or DID to actors, set maxPostsPerActor high and leave maxItems at 0. The Actor paginates the full author feed and returns every post, reply and repost.
How often is the data updated?
It's live. Each run reads Bluesky's current public AppView, so newly published posts appear within moments of going live. Schedule the Actor to keep a rolling, always-fresh archive.
⚖️ Is it legal?
This Actor collects only publicly available Bluesky content served by the open AT-Protocol AppView. It requires no login and accesses nothing private. You are responsible for using the data in compliance with Bluesky's Terms of Service, the AT-Protocol usage norms, applicable privacy laws such as GDPR and CCPA, and any local regulations. Do not use scraped personal data for spam, harassment or unlawful profiling. Scrape responsibly and respect rate limits.
🔗 Related scrapers by logiover
Building a wider social dataset? Pair this with the rest of the logiover social-media suite:
- Reddit Historical Archive Scraper — old Reddit posts & comments by date.
- X Tweet Scraper — profiles, tweets and posts from X / Twitter.
- Threads Scraper — posts and profiles from Meta's Threads.
- Mastodon Scraper — posts from the wider fediverse.
👉 Browse all logiover scrapers on Apify Store — 180+ actors across social media, real estate, jobs, crypto & B2B data.
📝 Changelog
2026-07-22
- 🦋 Initial release. Full public Bluesky account history via the keyless AT-Protocol API: author-feed pagination to the first post, thread/reply-tree expansion, curated list feeds, author profile enrichment, and precise
afterDate/beforeDatewindows. 24 flat fields per row, deduplicated by URI, with fresh-proxy retry and exponential backoff.