Bluesky Scraper API - posts, followers, likers, starter packs
Pricing
from $0.80 / 1,000 posts
Bluesky Scraper API - posts, followers, likers, starter packs
Search Bluesky posts, export timelines, threads, quote posts, profiles, followers, likers, reposters and starter-pack members via the official public AT Protocol API. No login. Engagement filters, only-new-posts monitoring. $1 / 1,000 posts.
Pricing
from $0.80 / 1,000 posts
Rating
0.0
(0)
Developer
WEIGUO HAN
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
14 days ago
Last modified
Categories
Security
Limited permissionsShare
Bluesky Scraper API - posts, profiles, followers, likers, starter packs & threads (no login)
Extract public Bluesky data through the official AT Protocol API - no account, no API key, no browser. One Actor covers every read use case:
| Mode | What you get | Input |
|---|---|---|
search | Posts matching a keyword, phrase, hashtag, domain, mention or author, newest first, with full time-window paging | queries (+ filters) |
authorFeed | Every post / reply / repost of an account (filterable: no replies, media only, video only) | actors |
thread | A post with all parents and the full reply tree | postUrls |
profile | Detailed profiles: bio, follower / following / post counts, labels, pinned post | actors |
followers / follows | The follower or following list of an account (bounded) | actors |
customFeed | Posts from any custom feed generator (Discover, What's Hot, niche community feeds) | feedUrls |
likers / reposters | Who liked or reposted a post (profiles, with the like time) - find the most engaged audience of any post | postUrls |
quotes | Every quote post of a post (what people said when they shared it) | postUrls |
listMembers | Members of a starter pack or curated / moderation list - ready-made niche audiences | listUrls |
Engagement filters (minLikes, minReposts, minReplies) work in every post mode: keep only the posts that took off, pay only for those.
Every post comes back normalized: uri, cid, url, author (DID / handle / display name), text, langs, createdAt, reply / quote / repost relations, like / repost / reply / quote counts, images with alt text, video, external link card, the quoted post, hashtags, mentions, links and moderation labels - plus the raw record on request.
Turn on "Only new items since last run" and schedule the Actor: it keeps a checkpoint per query and only outputs (and charges) posts it has not seen before - a ready-made Bluesky monitoring / social listening feed for brand mentions, keywords, competitors or creators.
Pricing: $1 per 1,000 posts, $0.50 per 1,000 profiles (pay per event, no extra start fee, details below).
Why this Actor
- Official, public API only. All data comes from Bluesky's public AppView (
public.api.bsky.app/api.bsky.app) - the same endpoints the Bluesky web app uses for logged-out visitors. No scraping of HTML, no bypassing of anything. - Search that keeps paging. Since mid-2026 the public API rejects
cursorpagination for logged-out search (HTTP 403 on page 2). This Actor pages by time instead (sort=latest+until=<oldest post of the previous page>, deduplicated onuri), so you still get thousands of results per keyword without logging in. - Eleven modes, one schema. Search results, timelines, threads, quote posts and custom feeds all produce the same post object; profiles, followers, likers, reposters and list / starter-pack members share one profile object. Build once, reuse everywhere.
- Simple per-record pricing. Profile, follower, following, liker, reposter and list-member records cost $0.50 per 1,000; posts cost $1 per 1,000; there is no extra start fee beyond Apify's platform default (prices checked 2026-10-16). Items skipped by deduplication, engagement filters or incremental monitoring are free.
- Monitoring built in. Named key-value-store checkpoints per query, "only new since last run", no duplicates across runs, no double charging.
- Respects user choices. Accounts that opted out of logged-out visibility (
!no-unauthenticated) are skipped by default; labels are included in the output. - Bring your own App Password (optional). Log in with your own Bluesky account through the official session endpoint to unlock cursor pagination (including
sort=top), see opted-out accounts and use your own rate limits. Stored encrypted, never logged. - Polite and fast. Small JSON requests, max 8 requests/second, exponential backoff on 429 / 5xx; a 1,000-post run finishes in well under a minute.
Tutorial: how to scrape Bluesky posts
- Open the Actor and pick a Mode.
- Fill in the matching input:
search-> Search queries:apify,"web scraping",#opensource,from:bsky.appstyle filters go into the dedicated fields (author, mentions, domain, URL, language, hashtags, since / until).authorFeed,profile,followers,follows-> Accounts:bsky.app,@name.bsky.social,did:plc:...orhttps://bsky.app/profile/....thread-> Post URLs:https://bsky.app/profile/bsky.app/post/3mx5e63uvns2dor anat://URI.customFeed-> Feed URLs:https://bsky.app/profile/bsky.app/feed/whats-hotor anat://.../app.bsky.feed.generator/...URI.
- Set Max items per query (default 100, up to 20,000).
- For a monitor, switch on Only new items since last run and create a schedule (hourly / daily). Connect a webhook, Zapier, Make, n8n or Google Sheets integration to get notified.
- Click Start. Results land in the dataset (table / JSON / CSV / Excel / API); a per-query summary with request counts and warnings is stored under the
SUMMARYkey of the run's key-value store.
Input example: brand monitoring
{"mode": "search","queries": ["apify", "crawlee"],"mentions": "apify.com","lang": "en","sort": "latest","maxItemsPerQuery": 500,"sinceLastRun": true,"stateStoreName": "my-bluesky-monitor"}
Input example: viral posts for a keyword (engagement filter)
{ "mode": "search", "queries": ["#buildinpublic"], "lang": "en", "minLikes": 50, "maxItemsPerQuery": 200 }
Input example: everyone who liked a post / members of a starter pack
{ "mode": "likers", "postUrls": ["https://bsky.app/profile/bsky.app/post/3mx5e63uvns2d"], "maxItemsPerQuery": 5000 }
{ "mode": "listMembers", "listUrls": ["https://bsky.app/starter-pack/bsky.app/3mv3qhvnmkd2l"] }
Liker records carry edgeType: "liker", subjectUri (the post) and likedAt; list members carry edgeType: "listMember", listName and starterPackName.
Input example: export an account and its audience
{ "mode": "authorFeed", "actors": ["https://bsky.app/profile/bsky.app"], "authorFeedFilter": "posts_no_replies", "includeReposts": false, "maxItemsPerQuery": 2000 }
{ "mode": "followers", "actors": ["bsky.app"], "maxItemsPerQuery": 5000 }
Output example: one post
{"uri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3mx5e63uvns2d","cid": "bafyreicnhzopqetyqko7bcc2gul2dkgtyxgnl3creeklgugdagxp7anaxe","rkey": "3mx5e63uvns2d","url": "https://bsky.app/profile/bsky.app/post/3mx5e63uvns2d","authorDid": "did:plc:z72i7hdynmk6r22z27h6tvur","authorHandle": "bsky.app","authorDisplayName": "Bluesky","authorAvatar": "https://cdn.bsky.app/img/avatar/plain/did:plc:z72i7hdynmk6r22z27h6tvur/...","authorLabels": [],"text": "We just shipped ...","langs": ["en"],"createdAt": "2026-10-04T18:02:11.513Z","indexedAt": "2026-10-04T18:02:12.020Z","isReply": false,"replyParentUri": null,"replyRootUri": null,"isQuote": false,"quotedPostUri": null,"isRepost": false,"repostedByDid": null,"repostedByHandle": null,"repostIndexedAt": null,"isPinned": false,"likeCount": 1843,"repostCount": 212,"replyCount": 32,"quoteCount": 41,"bookmarkCount": 57,"embedType": "images","images": [{ "url": "https://cdn.bsky.app/img/feed_fullsize/plain/...", "thumb": "https://cdn.bsky.app/img/feed_thumbnail/plain/...", "alt": "Screenshot of the new feature", "width": 1600, "height": 900 }],"video": null,"externalLink": null,"quotedPost": null,"hashtags": ["bluesky"],"mentions": [],"links": ["https://bsky.social/about/blog/..."],"labels": [],"threadgate": false,"source": "authorFeed","feedActor": "bsky.app","scrapedAt": "2026-10-07T09:12:30Z"}
A search result additionally carries "source": "search", "query": "apify"; a thread post carries threadPosition (parent / focus / reply), threadDepth and threadRootUri; a custom-feed post carries feedUri. With sinceLastRun every item has "isNew": true. Set includeRaw: true to get the untouched app.bsky.feed.defs#postView under raw.
Output example: one profile / graph edge
{"did": "did:plc:vu5ic5ygdeyunpefgmlamsmw","handle": "apify.com","displayName": "Apify","description": "The full-stack web scraping and automation platform.","avatar": "https://cdn.bsky.app/img/avatar/plain/...","banner": "https://cdn.bsky.app/img/banner/plain/...","url": "https://bsky.app/profile/apify.com","followersCount": 2410,"followsCount": 118,"postsCount": 356,"createdAt": "2024-11-12T10:21:44.000Z","indexedAt": "2026-10-06T22:14:01.000Z","labels": [],"pinnedPostUri": null,"listsCount": 0,"feedgensCount": 0,"starterPacksCount": 1,"bioLinks": ["https://example.com"],"isLabeler": false,"verificationStatus": null,"source": "followers","edgeType": "follower","subjectDid": "did:plc:z72i7hdynmk6r22z27h6tvur","subjectHandle": "bsky.app","scrapedAt": "2026-10-07T09:12:30Z"}
edgeType is profile (profile mode), follower (X follows the subject) or following (the subject follows X). Graph entries are basic profile views: counts are included when the API returns them.
Pricing (pay per event)
| Event | What it means | Price |
|---|---|---|
post | One normalized post written to the dataset (search, authorFeed, thread, customFeed, quotes) | $0.001 ($1 / 1,000 posts) |
profile | One profile written to the dataset (profile lookup, or one follower / following / liker / reposter / list-member entry) | $0.0005 ($0.50 / 1,000 profiles) |
| Actor start | Apify's standard synthetic start event at the platform default | platform default |
Posts skipped by deduplication, by the engagement filters, by the !no-unauthenticated filter, by includeReposts: false or by incremental monitoring are never charged. Failed queries cost nothing. Proposed volume discounts for higher Apify plans: post $0.0008 (Silver) / $0.0006 (Gold); profile $0.0004 / $0.0003.
Cost examples
- Hourly brand monitor on 3 keywords with
sinceLastRun, ~150 new posts a day -> about $0.15 per day. - One-off export of an account's last 5,000 posts -> $5.00.
- Follower list of a 20,000-follower account -> $10.00.
- Everyone who liked 10 viral posts (~3,000 likers each) -> 30,000 profiles -> $15.00.
- Research dataset: 50 keywords x 2,000 posts -> $100 for 100,000 posts.
Use cases
- Social listening & brand monitoring - track mentions of your brand, product or domain; push new posts to Slack, HubSpot or a Google Sheet via Apify integrations.
- Creator / competitor analytics - export timelines with engagement counts, compute best posting times, top formats, growth of follower counts over time (schedule the
profilemode). - Audience research - followers / following graphs for influencer mapping and community detection.
- Academic & journalism research - keyword corpora with language filters and exact time windows (
since/until), full conversation threads for discourse analysis. - AI agents, RAG and MCP - "what are people on Bluesky saying about X today?" becomes one Actor call with clean JSON.
- Migration from X/Twitter data pipelines - same concepts (posts, reposts, quotes, threads, followers) in a stable schema.
How it works and which endpoints are used
| Mode | Endpoint (public AppView) | Paging |
|---|---|---|
search | app.bsky.feed.searchPosts on api.bsky.app | logged-out: sort=latest + until time window (the API forbids cursor for logged-out calls); logged-in: cursor |
authorFeed | app.bsky.feed.getAuthorFeed | cursor, 100 per page |
thread | app.bsky.feed.getPostThread (depth up to 1000, parentHeight up to 1000) | single request |
profile | app.bsky.actor.getProfiles | 25 accounts per request |
followers / follows | app.bsky.graph.getFollowers / getFollows | cursor, 100 per page |
customFeed | app.bsky.feed.getFeed | cursor, 100 per page |
| handle -> DID | com.atproto.identity.resolveHandle | cached per run |
The endpoints are defined by the public AT Protocol lexicons (app.bsky.*) and served by Bluesky's public AppView for logged-out reads. Bluesky documents no fixed read quota for the AppView ("generous rate limits"); the Actor defaults to 3 requests/second, never exceeds 8, honours Retry-After / RateLimit-Reset and stops a query on persistent 429 or 403 instead of hammering the service.
Incremental monitoring (only new posts since last run)
With sinceLastRun: true the Actor stores, per query / account / thread / feed, the newest timestamp and the most recent 5,000 item ids in the named key-value store stateStoreName (default bluesky-public-data-state). On the next run:
- items already seen are skipped (not charged);
- chronological modes (
searchwithsort=latest,authorFeed,customFeed) stop paging as soon as they reach the previous watermark, so a monitor costs only what is new; threadand graph modes output only new replies / new followers;- the checkpoint is only advanced after a successful run - if a run stops because your charge limit was reached, the next run catches up instead of silently skipping.
Different filters (language, author, sort ...) produce different checkpoints; use different stateStoreName values for independent monitors. The first run seeds the checkpoint and returns the items currently visible (up to maxItemsPerQuery).
Optional: use your own Bluesky App Password
Without login everything in this Actor works, with two limitations imposed by Bluesky for logged-out traffic: search cannot use cursor pagination (the Actor pages by time instead, which only works with sort=latest), and accounts that opted out of logged-out visibility are hidden.
If you need sort=top beyond the first 100 results, want to see opted-out accounts you are allowed to see, or prefer your own account's rate limits, create an App Password in Bluesky (Settings -> Privacy and security -> App Passwords) and fill in identifier + appPassword. The Actor calls the official com.atproto.server.createSession endpoint on your PDS (pdsHost, default https://bsky.social), routes all requests through it with a bearer token and refreshes the session automatically. The password is a secret input: encrypted by Apify, hidden in the UI, never logged, never written to the dataset. Never use your main account password.
Limitations and good-to-know
- Logged-out search: only
sort=latestcan page beyond the first 100 results;sort=topreturns the first page only.hitsTotalfrom the API is approximate. Very busy keywords with many posts sharing the same second can lose a handful of posts at page boundaries. - Search freshness: Bluesky's search index lags the firehose by seconds to minutes;
getAuthorFeedis the most complete source for a single account. - Threads are returned as the AppView renders them: replies hidden by the author (threadgates), blocked or deleted posts appear as warnings in
SUMMARY, not as items. Extremely large threads may be truncated by the AppView regardless ofthreadDepth. - Follower lists of huge accounts (millions) are expensive and slow to walk;
maxItemsPerQueryis capped at 20,000 per run. - Deleted content: the Actor reads live data; it does not keep posts that were deleted after your run. Please honour deletions in your own storage (Bluesky developer guidelines).
- Notifications, private lists and direct messages are not covered (they are never public). Likers, reposters, quote posts, lists and starter packs are covered since 1.1.
- Media files are returned as CDN URLs, not downloaded.
FAQ
Do I need a Bluesky account or API key? No. Every mode works logged-out through Bluesky's public API. An App Password is optional.
Is this allowed? Bluesky states that posts on Bluesky are public and readable through its open API, and operates public.api.bsky.app precisely for logged-out reads. The Actor only reads public data, respects the !no-unauthenticated opt-out by default, surfaces moderation labels, and never performs writes, likes, follows or messages. You are responsible for complying with Bluesky's Terms of Service, the Developer Guidelines and applicable privacy laws for the data you store.
How do I get only new posts? Set sinceLastRun: true and run on a schedule. The first run seeds the checkpoint.
How do I search for mentions of my account? Mode search, put your handle (e.g. apify.com) in Only posts mentioning and * or your brand name in Search queries.
Can I search posts in a date range? Yes: since / until accept ISO datetimes (2026-10-01T00:00:00Z).
Why are there fewer posts than hitsTotal? hitsTotal is an estimate from the search index; filtered accounts, deleted posts and maxItemsPerQuery reduce the count. Check SUMMARY in the run's key-value store for fetched vs pushed per query.
How do I find the most engaged accounts in a niche? Use search with minLikes to find the posts that took off, then run likers / reposters on their URLs - or export a niche starter pack with listMembers.
Do engagement filters apply to monitoring? Yes. With sinceLastRun each post is evaluated once, when it is first seen; a post that gains likes later is not re-checked.
Can I pass a Bluesky URL instead of a handle? Yes - profile, post and feed URLs from bsky.app are all accepted and converted to AT URIs.
Can it run locally? Yes: apify run with the Apify CLI, or python -m src inside a venv. Unit tests: pytest (recorded fixtures, no network).
Changelog
- 1.1.0 (2026-10-16) - new modes
likers,reposters,quotesandlistMembers(curated lists and starter packs); engagement filtersminLikes/minReposts/minRepliesfor every post mode (filtered posts are free). Profiles gainbioLinks(website / link-in-bio URLs found in the bio; e-mail addresses are deliberately not extracted). - 1.0.0 - initial release: search (time-window paging), authorFeed, thread, profile, followers, follows, customFeed; incremental monitoring; optional App Password; pay-per-event charging.