Bluesky Scraper | $0.50/1K | Posts & Engagement
Pricing
from $0.40 / 1,000 useful bluesky posts
Bluesky Scraper | $0.50/1K | Posts & Engagement
Collect public Bluesky author feeds and keyword searches with text, dates, engagement and media metadata. Latest search uses overlapping time windows, URI deduplication and bound continuation. No complete archive guarantee.
Pricing
from $0.40 / 1,000 useful bluesky posts
Rating
0.0
(0)
Developer
Apivault Labs
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 days ago
Last modified
Categories
Share
Bluesky Scraper — Public Search, Author Posts & Engagement

Concept illustration, not actual post content or live product UI.
Turn public Bluesky posts into structured JSON or a CSV table: original text, author identity, source dates, observed engagement and available media links. Use it for a small brand-mention sample, an author's public posting history, or research datasets that retain the original post URI.
Private development candidate. Initial pricing has owner approval; publication requires exact-build review. Private QA is not a public Store release. Public source access can change. The Actor does not log in, solve challenges, rotate proxies or retrieve private content.
Start with an author feed
{"mode": "author","actor": "bsky.app","maxPosts": 5,"maxPages": 2,"pageSize": 10}
Supply a Bluesky handle or DID. This mode reads the public author feed, rather than searching for mentions of that person. Replies are included by default; repost entries are excluded. A two-page local source probe returned ten distinct posts, but that is not proof of unlimited archive access.
Search public posts
{"mode": "search","query": "python","sort": "latest","maxPosts": 5,"pageSize": 10}
Search uses Bluesky's public AppView search endpoint. Latest search now defaults to overlapping time windows using the supported until filter. Each following window overlaps the oldest source creation timestamp by one second; URI deduplication prevents a repeated result event. A local proof covered three windows each for two keywords. This is a bounded sample of a live search index, not a complete historical export. Native cursor requests returned403; they remain an explicit optional mode, without automatic retries or a silent fallback after an error. A source error retains useful rows and diagnostics. top uses native cursor mode and may therefore return403 on continuation. Time windows require latest. The Actor does not calculate a popularity score.
Useful recipes
| Goal | Settings |
|---|---|
| Public author sample | mode=author, actor=bsky.app |
| Original standalone posts | includeReplies=false, includeReposts=false |
| Include repost entries | includeReposts=true; still deduplicates original URI |
| Brand/keyword mention sample | mode=search with your query |
| Only posts with an observed reaction threshold | minLikes=10; unknown counts fail a positive threshold |
| Resume a bounded collection | Copy CONTINUATION.resumeInput unchanged |
These are input recipes, not claims of five published Tasks. Saved Tasks, if created during QA, remain private until separately published and read back. The source index is live: cursor pagination cannot guarantee a stable historical snapshot or completeness.
What each row means
| Fields | Meaning |
|---|---|
| uri, cid, postId, postUrl | Original at:// post identity, content ID when present and public link |
| text | Source post text; an image/video-only post may have empty text |
| author | Original author's DID, handle and display name; not the person who reposted |
| createdAt | Author-supplied creation timestamp, if present |
| indexedAt | AppView indexing timestamp, separately named |
| observedAt | Time our collector observed the row |
| likeCount, repostCount, replyCount, quoteCount | Exposed nonnegative counters; unavailable values remain null |
| languages, hashtags, links | Declared record languages and rich-text facet metadata |
| images, video, external | Available embed metadata and source links; no media files downloaded |
| parentUri, rootUri, quotedUri | Exposed references; no thread tree or quoted-post enrichment |
| isRepost, repostedBy | Feed repost context; original URI remains the deduplication key |
Counts and links are observations, not guarantees of current engagement, availability or ownership. The Actor does not infer sentiment, author location, contact information, follower lists or demographic attributes. It does not fetch the external links contained in posts. The same original post returned more than once becomes one Dataset row per run.
Inputs and bounds
| Input | Default | Behavior |
|---|---|---|
| mode | search | search or author |
| query | Required in search | Up to500characters; source search syntax |
| actor | Required in author | Handle or DID, not an arbitrary URL |
| sort | latest | latest or top; search route only |
| searchPagination | time_windows for latest search | Overlapping until windows; cursor for top/author. No complete archive guarantee |
| since / until | Unset | ISO timestamps with timezone; search only, not a full archive guarantee |
| lang | Unset | Language code forwarded to search; author mode rejects this filter |
| maxPosts | 20 | 1–10,000 delivered posts; synthetic bound, not a bulk benchmark |
| maxPages | 5 | 1–1,000 requests; errors stop rather than retry |
| pageSize | 25 | 1–100 source entries per request |
| maxRunSeconds | 120 | 30–1,800seconds; allowance for an in-flight request |
| requestDelayMs | 500 | 250–10,000ms between sequential pages |
| includeReplies | true | Filter reply posts; does not collect replies to a post |
| includeReposts | false | Filter author-feed repost entries |
| minLikes | 0 | Minimum known like count; unknown passes only0 |
| startCursor | Unset | Source cursor; use full continuation input |
| excludeUris | Empty | Up to20,000 known post URIs; affects delivery, not source page fetching |
Unsupported fields and invalid combinations fail before source requests. This protects against silently ignoring a date/language filter in author mode.
Continuation, errors and coverage
After a result, time or page limit, open the CONTINUATION record and copy resumeInput into the next run. It contains the mode, query/author, source cursor, filters and already delivered URIs. If the run stops midway through a page, the next run intentionally replays that page and excludes previously delivered posts, so an unprocessed tail is not silently skipped. Keep the same query and ordering. Time-window continuation also binds the original date filters, language, page size and pagination mode; changing these fields is rejected before source requests. You can change result/page/time limits. A saturated timestamp boundary stops with SEARCH_WINDOW_STALLED rather than jumping over a tied group. If the source has more posts at that boundary than a page can expose, coverage remains incomplete. Source creation timestamps are author-supplied and can differ from source indexing/sort timestamps, another reason that time windows cannot establish complete coverage.
A source-exhausted response has resumeInput: null. This only means no next cursor was returned; it does not prove a complete public or historical archive. A429/403 response, invalid API shape, repeated cursor or stalled time-window boundary is a diagnostic rather than a successful empty collection. Errors after useful posts retain those rows and report partial coverage. Errors with no useful posts fail visibly. A legitimately empty search or filter result can succeed with zero rows.
SUMMARY distinguishes fetched entries, useful delivered posts, filtered entries, duplicates, invalid entries, pages and stop reason. ERRORS contains sanitized failure codes. No API credentials are accepted or required by this MVP. After a crash, reconcile the actual Dataset before continuation because a recent successful write may precede the latest saved checkpoint. Do not interpret missing posts as deletions or an incomplete query as a complete monitoring baseline.
Cost and integrations
The owner-approved initial result tariff is $0.50 per1,000 useful posts on the Free tier and $0.40 per1,000 on paid plans, with no Actor startup fee. Apify compute, storage and transfer are paid separately by the user. Failed source requests can consume platform resources even when no post result is charged. A maximum Actor charge caps event fees, not all separate platform usage. Use page and time limits too. The code distinguishes an accepted free Dataset write from a rejected positive-price PPE event; live billing and budget checks must pass on the exact candidate before release.
Export the Dataset as JSON, CSV or Excel through Apify. JSON preserves nested author/embed fields; the overview table offers common columns. An authorized API client can start the Actor and read its defaultDatasetId using Apify's Python client or JavaScript client. A generic n8n HTTP/Apify workflow can use the same input recipes. A dedicated Bluesky npm node, PyPI package or custom MCP server is not verified or advertised.
FAQ
Does it include private posts or require a session cookie? No. The MVP only requests public AppView endpoints and accepts no session secrets.
Will it collect every matching post or all of an author's history? No completeness guarantee is made. Source indexing, cursor behavior, filters and errors limit coverage. The supported numeric cap does not establish live access to that many posts.
Are replies a full discussion tree? No. includeReplies controls whether reply posts already in the search/feed are retained. Parent/root fields are references, not fetched thread data.
Will a repost create duplicate charges for the same original post? The original URI deduplicates output within a run and across a continuation exclusion list. Separate independent runs are separate observations. Duplicates and filtered entries do not become result events.
Can I monitor deletions or engagement growth? You can collect timestamped observations, but the Actor does not implement lifecycle classification, deletion detection or notifications. A missing post in a limited response cannot establish deletion.