Bluesky Scraper — Posts, Profiles, Threads & Followers avatar

Bluesky Scraper — Posts, Profiles, Threads & Followers

Pricing

from $2.00 / 1,000 bluesky records

Go to Apify Store
Bluesky Scraper — Posts, Profiles, Threads & Followers

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

Nomad.Dev

Maintained by Community

Actor 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:

FieldMeaning
uri / cidStable AT Protocol identifiers of the post
urlDirect bsky.app link to the post
authorHandle / authorDid / authorDisplayNameWho posted it
textFull post text
createdAt / indexedAtWhen it was posted / indexed
likeCount / repostCount / replyCount / quoteCount / bookmarkCountEngagement counts
langsDeclared post languages
tags / mentions / linksHashtags, @-mention DIDs and hyperlinks parsed from the post's richtext facets
embedType / mediaUrls / mediaAlt / externalUrl / externalTitle / quotedUriMedia & embeds: images/video/gallery URLs and alt text, external link cards, and quoted-post URIs
replyParentUri / replyRootUriThe post this replies to, and the thread root (null if not a reply)
isRepost / feedOfRepost flag and source handle/feed (authorFeed, feed modes)
depth / parentUri / rootUri / isRoot / threadUriThread structure (thread mode)
aiSentiment / aiTopics / aiSummaryOptional LLM analysis (only when the aiAnalysis add-on is on)
modeWhich 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

ModeWhat it returnsKey inputs
searchPosts matching a keyword/hashtag, with date, author, mention, language, domain/url/tag and engagement filtersquery, since, until, fromAuthor, mentionsAuthor, language, domain, url, tag, sort, minLikes, minReposts
authorFeedPosts by one or more accountshandles, includeReplies, minLikes, minReposts
threadA post plus its full reply thread (and optional ancestors)threadUris, threadDepth, parentHeight
feedPosts from a custom/algorithmic feed generatorfeedUris
profileProfile details (bio, counts) per accounthandles
followersAccounts following the given handleshandles
followingAccounts the given handles followhandles

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 as from:). Uses searchPosts' own author filter param, not just a query-string trick.
  • mentionsAuthor — only posts that mention this handle (same as mentions:). Uses the mentions filter param.
  • language — only posts declared in this ISO 639-1 language code (same as lang:). Uses the lang filter 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

  1. Click Try for free / Run — no Bluesky account needed, only public data is read.
  2. Pick a mode, set a query or handles, adjust maxItems or keep the defaults.
  3. 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 ApifyClient
client = 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):

FieldTypeDefaultNotes
modestringsearchOne of search, authorFeed, thread, feed, profile, followers, following.
handlesarrayHandles or DIDs for authorFeed/profile/followers/following. Leading @ optional.
includeRepliesbooleanfalseInclude the author's replies in authorFeed mode.
maxItemsinteger100Maximum records for the whole run. Set 0 for no limit.
onlyNewSinceLastRunbooleanfalseDelta mode: skip records seen in the previous run (search/authorFeed/feed).

Thread & feed fields:

FieldTypeDefaultNotes
threadUrisarrayPost URLs / at:// URIs whose reply thread to scrape (thread mode).
threadDepthinteger6Levels of replies to fetch below the post (thread mode).
parentHeightinteger0Ancestor posts above the requested one to include (thread mode).
feedUrisarrayFeed URLs / at:// generator URIs to read (feed mode).

Search fields (search mode; minLikes/minReposts also apply to authorFeed/thread/feed):

FieldTypeDefaultNotes
querystringKeyword/hashtag for search mode. Supports Bluesky search operators.
sincestringOnly posts created at or after this date/time. Datepicker (YYYY-MM-DD) or a precise ISO 8601 timestamp.
untilstringOnly posts created before this date/time. Datepicker (YYYY-MM-DD) or a precise ISO 8601 timestamp.
fromAuthorstringOnly posts written by this handle (from: operator / author param).
mentionsAuthorstringOnly posts that mention this handle (mentions: operator / mentions param).
languagestringOnly posts in this ISO 639-1 language code (lang: operator / lang param).
domainstringOnly posts linking to this domain (domain param).
urlstringOnly posts linking to this exact URL (url param).
tagarrayOnly posts carrying these hashtags, entered without # (tag param).
sortstringlatestlatest (newest first) or top (by relevance) for search mode.
minLikesinteger0Drop posts with fewer likes than this (compares likeCount). 0 = no filter.
minRepostsinteger0Drop posts with fewer reposts than this (compares repostCount). 0 = no filter.

AI analysis fields (optional, bring your own key):

FieldTypeDefaultNotes
aiAnalysisbooleanfalseAdd aiSentiment/aiTopics/aiSummary to posts (post modes only).
aiProviderstringautoAuto-detected from whichever key you supply; set anthropic or mistral only to override.
aiModelstringOverride the model (default: claude-haiku-4-5 / mistral-small-latest).
anthropicApiKeystring (secret)Your Anthropic key; billed by Anthropic. Not required.
mistralApiKeystring (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.

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.