Bluesky Scraper — Posts, Profiles, Threads & Followers
Pricing
from $2.00 / 1,000 bluesky records
Bluesky Scraper — Posts, Profiles, Threads & Followers
All-in-one Bluesky extractor on the official AT Protocol public API. Search posts (keyword, hashtag, author, domain, date), pull an account feed, scrape a post's reply thread, read custom feeds, or list profiles and followers. Clean JSON with engagement & media — no login, no proxies.
Pricing
from $2.00 / 1,000 bluesky records
Rating
0.0
(0)
Developer
Nomad.Dev
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
10 days ago
Last modified
Categories
Share
Extract Bluesky data in one Actor: search posts by keyword or hashtag, pull any account's post feed, scrape a post's full reply thread, read a custom/algorithmic feed, fetch profile details, or list followers and following — all through the official AT Protocol public API. No login, no cookies, no proxies.
What Bluesky data does this scraper extract?
Post records (search, authorFeed, thread and feed modes) — one flat JSON record per post:
| Field | Meaning |
|---|---|
uri / cid | Stable AT Protocol identifiers of the post |
url | Direct bsky.app link to the post |
authorHandle / authorDid / authorDisplayName | Who posted it |
text | Full post text |
createdAt / indexedAt | When it was posted / indexed |
likeCount / repostCount / replyCount / quoteCount / bookmarkCount | Engagement counts |
langs | Declared post languages |
tags / mentions / links | Hashtags, @-mention DIDs and hyperlinks parsed from the post's richtext facets |
embedType / mediaUrls / mediaAlt / externalUrl / externalTitle / quotedUri | Media & embeds: images/video/gallery URLs and alt text, external link cards, and quoted-post URIs |
replyParentUri / replyRootUri | The post this replies to, and the thread root (null if not a reply) |
isRepost / feedOf | Repost flag and source handle/feed (authorFeed, feed modes) |
depth / parentUri / rootUri / isRoot / threadUri | Thread structure (thread mode) |
aiSentiment / aiTopics / aiSummary | Optional LLM analysis (only when the aiAnalysis add-on is on) |
mode | Which mode produced the record |
Profile records (profile, followers, following modes): did, handle, url, displayName, description, avatar, createdAt, plus followersCount / followsCount / postsCount in profile mode and subjectHandle in follower/following modes.
Modes
| Mode | What it returns | Key inputs |
|---|---|---|
search | Posts matching a keyword/hashtag, with date, author, mention, language, domain/url/tag and engagement filters | query, since, until, fromAuthor, mentionsAuthor, language, domain, url, tag, sort, minLikes, minReposts |
authorFeed | Posts by one or more accounts | handles, includeReplies, minLikes, minReposts |
thread | A post plus its full reply thread (and optional ancestors) | threadUris, threadDepth, parentHeight |
feed | Posts from a custom/algorithmic feed generator | feedUris |
profile | Profile details (bio, counts) per account | handles |
followers | Accounts following the given handles | handles |
following | Accounts the given handles follow | handles |
Add onlyNewSinceLastRun: true to any streaming mode (search, authorFeed, feed) to skip records already seen in the Actor's previous run — handy for scheduled/incremental scraping. The first run returns everything.
Search supports Bluesky query operators typed straight into query — #hashtag, "exact phrase", from:user.bsky.social, mentions:user.bsky.social, lang:en, and more. The most common ones also have dedicated inputs so you don't have to remember the operator syntax:
fromAuthor— only posts written by this handle (same asfrom:). UsessearchPosts' ownauthorfilter param, not just a query-string trick.mentionsAuthor— only posts that mention this handle (same asmentions:). Uses thementionsfilter param.language— only posts declared in this ISO 639-1 language code (same aslang:). Uses thelangfilter param.
These compose safely with query, since, until and sort in the same request. The searchPosts endpoint's dedicated domain/url/tag filters are also wired up as first-class inputs:
domain— only posts linking to this domain (e.g.nytimes.com).url— only posts linking to this exact URL.tag— only posts carrying these hashtags (enter each without the leading#).
Bluesky's unauthenticated search API does not allow cursor paging, so the Actor transparently paginates latest searches by walking the time window backwards — you still just set maxItems. top sort is not time-ordered and returns up to 100 posts per run.
minLikes / minReposts filter posts client-side, after they're fetched from the API — set either to skip low-engagement noise in the search, authorFeed, thread and feed post modes. Filtered-out posts are never pushed to the dataset, so you aren't billed for them.
Thread & custom-feed modes
thread mode returns a post and its whole reply tree via the AT Protocol getPostThread endpoint. Put post links or at:// URIs in threadUris, set threadDepth for how many reply levels to fetch, and parentHeight to also pull ancestor posts above the requested one. Every record carries depth (0 = the requested post, 1+ = replies, negative = ancestors), parentUri, rootUri and isRoot, so you can rebuild the conversation tree.
feed mode reads a custom/algorithmic feed generator via getFeed. Put feed links (https://bsky.app/profile/<handle>/feed/<rkey>) or at://.../app.bsky.feed.generator/... URIs in feedUris; handles are resolved to DIDs automatically. Records include feedOf (the feed) and isRepost.
Optional AI analysis (bring your own key)
Turn on aiAnalysis to add aiSentiment (positive / negative / neutral / mixed), aiTopics (grounded topic tags) and aiSummary (one-sentence summary) to each post in the post modes. Supply your own anthropicApiKey or mistralApiKey (pick with aiProvider, override the model with aiModel) — that provider bills you directly, and this Actor's per-record price is unchanged. When off, the three fields are simply absent. If a post can't be analyzed, its AI fields are set to null rather than guessed.
How to scrape Bluesky with this Actor
- Click Try for free / Run — no Bluesky account needed, only public data is read.
- Pick a
mode, set aqueryorhandles, adjustmaxItemsor keep the defaults. - Run it and export the dataset as JSON, CSV or Excel, or read it over the API.
Run it from your own code:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("nomad-agent/bluesky-scraper").call(run_input={"mode": "search","query": "#ai","since": "2026-06-01T00:00:00Z","maxItems": 200,})for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item["authorHandle"], "—", item["text"][:80], item["url"])
Or a single HTTP call that runs the Actor and returns items in one response:
curl -X POST \"https://api.apify.com/v2/acts/nomad-agent~bluesky-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \-H "Content-Type: application/json" \-d '{"mode": "authorFeed", "handles": ["bsky.app"], "maxItems": 50}'
Input
General fields (apply across modes):
| Field | Type | Default | Notes |
|---|---|---|---|
mode | string | search | One of search, authorFeed, thread, feed, profile, followers, following. |
handles | array | — | Handles or DIDs for authorFeed/profile/followers/following. Leading @ optional. |
includeReplies | boolean | false | Include the author's replies in authorFeed mode. |
maxItems | integer | 100 | Maximum records for the whole run. Set 0 for no limit. |
onlyNewSinceLastRun | boolean | false | Delta mode: skip records seen in the previous run (search/authorFeed/feed). |
Thread & feed fields:
| Field | Type | Default | Notes |
|---|---|---|---|
threadUris | array | — | Post URLs / at:// URIs whose reply thread to scrape (thread mode). |
threadDepth | integer | 6 | Levels of replies to fetch below the post (thread mode). |
parentHeight | integer | 0 | Ancestor posts above the requested one to include (thread mode). |
feedUris | array | — | Feed URLs / at:// generator URIs to read (feed mode). |
Search fields (search mode; minLikes/minReposts also apply to authorFeed/thread/feed):
| Field | Type | Default | Notes |
|---|---|---|---|
query | string | — | Keyword/hashtag for search mode. Supports Bluesky search operators. |
since | string | — | Only posts created at or after this date/time. Datepicker (YYYY-MM-DD) or a precise ISO 8601 timestamp. |
until | string | — | Only posts created before this date/time. Datepicker (YYYY-MM-DD) or a precise ISO 8601 timestamp. |
fromAuthor | string | — | Only posts written by this handle (from: operator / author param). |
mentionsAuthor | string | — | Only posts that mention this handle (mentions: operator / mentions param). |
language | string | — | Only posts in this ISO 639-1 language code (lang: operator / lang param). |
domain | string | — | Only posts linking to this domain (domain param). |
url | string | — | Only posts linking to this exact URL (url param). |
tag | array | — | Only posts carrying these hashtags, entered without # (tag param). |
sort | string | latest | latest (newest first) or top (by relevance) for search mode. |
minLikes | integer | 0 | Drop posts with fewer likes than this (compares likeCount). 0 = no filter. |
minReposts | integer | 0 | Drop posts with fewer reposts than this (compares repostCount). 0 = no filter. |
AI analysis fields (optional, bring your own key):
| Field | Type | Default | Notes |
|---|---|---|---|
aiAnalysis | boolean | false | Add aiSentiment/aiTopics/aiSummary to posts (post modes only). |
aiProvider | string | auto | Auto-detected from whichever key you supply; set anthropic or mistral only to override. |
aiModel | string | — | Override the model (default: claude-haiku-4-5 / mistral-small-latest). |
anthropicApiKey | string (secret) | — | Your Anthropic key; billed by Anthropic. Not required. |
mistralApiKey | string (secret) | — | Your Mistral key; billed by Mistral. Not required. |
Output example
{"mode": "search","uri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3lb2abcxyz","cid": "bafyreib2rxk3rw6...","url": "https://bsky.app/profile/bsky.app/post/3lb2abcxyz","authorHandle": "bsky.app","authorDid": "did:plc:z72i7hdynmk6r22z27h6tvur","authorDisplayName": "Bluesky","text": "Introducing new moderation tools...","createdAt": "2026-06-15T18:02:11.000Z","indexedAt": "2026-06-15T18:02:12.345Z","langs": ["en"],"replyCount": 412,"repostCount": 1287,"likeCount": 9034,"quoteCount": 187,"bookmarkCount": 54,"replyParentUri": null,"replyRootUri": null,"tags": ["moderation"],"mentions": [],"links": ["https://bsky.social/about/blog"],"embedType": "external","mediaUrls": [],"mediaAlt": [],"externalUrl": "https://bsky.social/about/blog","externalTitle": "Bluesky Blog","quotedUri": null}
Pricing
Pay per event: $0.05 per Actor start and $0.004 per record returned.
100 records ≈ $0.45. No subscription, no rental — you pay only for what you fetch.
minLikes/minReposts and onlyNewSinceLastRun are applied before records are pushed, so filtered-out and already-seen posts are never billed. The optional aiAnalysis add-on uses your own Anthropic/Mistral key and is billed by that provider — it does not change this Actor's per-record price.
Integrations
Export the dataset as JSON, CSV, Excel or HTML, pull it over the Apify API (including run-sync-get-dataset-items for a single blocking call), wire it into Make, Zapier or n8n, or call it as a tool from an AI agent via the Apify MCP server.
Use cases
- Brand, keyword and hashtag monitoring on Bluesky
- Social listening and sentiment datasets for AI/LLM pipelines
- Influencer discovery via follower/following graphs and engagement counts
- Archiving an account's full posting history
- Trend and virality analysis with like/repost/reply counts
FAQ
Is it legal to scrape Bluesky?
This Actor reads only publicly available data through Bluesky's own public AT Protocol API (public.api.bsky.app) — the same data any logged-out visitor can see. No authentication is used and no private data is touched. Review Bluesky's terms and your local regulations for your specific use case.
Do I need a Bluesky account? No. All seven modes use unauthenticated public endpoints.
How fresh is the data?
Every run hits the live API. search with sort: latest returns posts within seconds of being indexed.
How many records can I get?
maxItems caps the run; set 0 to paginate until the source is exhausted (full author feeds and follower lists). The Actor follows API cursors and respects Bluesky's rate limits automatically.
What about deleted or blocked accounts? Handles that cannot be resolved (typos, deactivated accounts) are logged and skipped — one bad handle never fails the whole run.
Which search operators are supported as dedicated inputs?
fromAuthor, mentionsAuthor, language, domain, url and tag map to searchPosts' own author, mentions, lang, domain, url and tag filter params (verified against the live API) — equivalent to from:, mentions:, lang:, domain: and #tag in query, but composable with it via proper params instead of string-building.
Something broken or missing? Open an issue on the Actor's Issues tab — it is monitored and reliability fixes ship fast.
Related Actors
- Hacker News Who Is Hiring Scraper — HN Jobs
- Web Search Scraper
- AI & ML Engineer Jobs Scraper — 8 Boards in One
Credits
Independent implementation on the official AT Protocol public API. Design informed by the MIT-licensed deepfates/bsky-scraper firehose archiver — see LICENSE for the attribution note.