September 1, 2026 · 10 min read

Bluesky Scraper: 3 Practical Use Cases

By Crawlerbros Engineering Team

Direct answer

Bluesky Scraper extracts AT Protocol social network data via pure HTTP requests without requiring logins or proxies. It supports searching posts by keyword or hashtag, pulling user timelines, looking up profiles, searching account handles, and scraping custom feeds. To build a production workflow, match your business target to the correct Actor mode, set precise filter inputs like minLikes or language, and normalize the returned post or account records. The playbooks below outline real-world implementations for brand monitoring, creator discovery, and protocol research.

Blueprinting your Bluesky data extraction

Before launching any extraction, establish the exact AT Protocol identifiers your team needs. Bluesky identifies accounts using decentralized identifiers (DIDs) alongside mutable handles like bsky.app. Distinguishing between post text, embedded facets, and media attachments prevents pipeline failures downstream.

Define strict acceptance criteria based on record types. For instance, post records return metrics such as replyCount, repostCount, likeCount, quoteCount, and bookmarkCount, while account records contain followersCount, followsCount, and postsCount. Distinguishing between top-level posts, replies, and reposts using input flags like excludeReplies or excludeReposts keeps your data stream targeted.

Practical use cases

These use cases come from Bluesky Scraper's published documentation. Each is expanded into an operating pattern so the Bluesky Scraper output has a purpose beyond collection.

Use case 1: Social listening / brand monitoring

Outcome: Track mentions of your brand or product on Bluesky in real time.

Question to answer: Between this run and the last, what actually moved, and does the shift clear the bar for action?

Configure: Start with searchQuery (Keyword, hashtag (with #), or full-text query. Bluesky supports its standard search operators: from:user, since:YYYY-MM-DD, lang:en, etc.), actor (Bluesky handle (e.g. bsky.app, jay.bsky.team) or full DID (did:plc:...). Used by profile / follows / followers / actorLikes modes.), listUri (AT URI of a Bluesky list (at://did:plc:.../app.bsky.graph.list/).). Use the narrowest Bluesky Scraper values that represent the real task, keep the first result set small, and record why each selected input matters to the Bluesky Scraper outcome.

Working method: Keep a snapshot from every run and diff it against the previous one using a stable identifier. Bucket the differences into new, removed, and changed, then attach a plain-language reason to any change that crosses your action threshold.

Deliverable: Create a monitoring log that pairs every flagged change with the two runs it was confirmed across. Include the Bluesky Scraper source identifier and the collected fields behind every Bluesky Scraper decision.

Stop condition: Pause when a change is flagged from a single run with no second confirmation, or the matching key itself proves unstable. Fix the Bluesky Scraper question, comparison rule, or configuration before expanding the Bluesky Scraper run.

Use case 2: Influencer discovery

Outcome: Combine actorSearch + minLikes filters to surface high-impact accounts in any niche.

Question to answer: Which candidates satisfy the brief on paper, and what would a human reviewer still need to confirm?

Configure: Start with searchQuery (Keyword, hashtag (with #), or full-text query. Bluesky supports its standard search operators: from:user, since:YYYY-MM-DD, lang:en, etc.), postUrls (Public bsky.app post URLs to expand, e.g. https://bsky.app/profile/bsky.app/post/3kxxxx.), language (ISO 639-1 language code. Drops posts not in this language. Empty = no filter.). Use the narrowest Bluesky Scraper values that represent the real task, keep the first result set small, and record why each selected input matters to the Bluesky Scraper outcome.

Working method: Turn the brief into a short checklist of observable signals, then score reach and brand fit as two separate numbers instead of one blended score. Look at several recent posts per candidate rather than a single profile snapshot.

Deliverable: Create a shortlist with reach and fit reported separately, plus a documented reason for every candidate that was passed over. Include the Bluesky Scraper source identifier and the collected fields behind every Bluesky Scraper decision.

Stop condition: Pause when recent content is too sparse to judge fairly, or a candidate is being evaluated on outdated material. Fix the Bluesky Scraper question, comparison rule, or configuration before expanding the Bluesky Scraper run.

Use case 3: Academic research

Outcome: Snapshot public conversations on the AT Protocol, with full media + facet provenance.

Question to answer: After grouping fairly, which gaps are large enough to matter, and which are within normal variation?

Configure: Start with postUri (Full AT URI of the post (at://did:plc:.../app.bsky.feed.post/).), feedUri (Full AT URI of a feed generator (at://did:plc:.../app.bsky.feed.generator/). Use this for community feeds not in the preset list.), searchQuery (Keyword, hashtag (with #), or full-text query. Bluesky supports its standard search operators: from:user, since:YYYY-MM-DD, lang:en, etc.). Use the narrowest Bluesky Scraper values that represent the real task, keep the first result set small, and record why each selected input matters to the Bluesky Scraper outcome.

Working method: Decide the comparison axis first, then place every record into a cohort before looking at outcomes. Keep raw and normalized values side by side, and review the records that do not fit any cohort instead of dropping them.

Deliverable: Create a comparison worksheet showing cohort membership, the compared fields side by side, and any record that did not fit. Include the Bluesky Scraper source identifier and the collected fields behind every Bluesky Scraper decision.

Stop condition: Pause when cohorts overlap on the defining field, or the gap being reported depends on a field with heavy missing data. Fix the Bluesky Scraper question, comparison rule, or configuration before expanding the Bluesky Scraper run.

Execution workflow for AT Protocol datasets

  1. Select the extraction mode: Use mode=search for broad keyword matching, mode=profile for single-author timelines, mode=actorSearch for account discovery, or mode=feed for algorithmic streams.
  2. Formulate filter criteria: Input parameters like minLikes, minReposts, since, until, fromUser, language, excludeReplies, and excludeReposts must be set prior to running the scraper to narrow raw payloads at request time.
  3. Validate HTTP responses: Inspect initial runs for expected data structures. Verify that recordType accurately matches either post or account.
  4. Process facets and embeds: Parse arrays for tags, mentions, urls, and mediaAttachments to populate internal downstream databases.
  5. Export clean datasets: Convert canonical uri references into public bsky.app web links for human review and business reporting.

Technical capabilities and input parameters

The Actor accepts these documented configuration controls:

  • mode (string): What to fetch. Default: search. Options include search, profile, actorSearch, feed, postThread, urlFetch, getPosts, follows, followers, getLikes, getActorLikes, getList, getStarterPack, feedGeneratorsDiscovery.
  • searchQuery (string): Keyword, hashtag (with #), or full-text query. Bluesky supports its standard search operators: from:user, since:YYYY-MM-DD, lang:en, etc. Default: bluesky.
  • searchSort (string): Sort order for mode=search. top ranks by engagement; latest ranks by recency. Default: top.
  • actor (string): Bluesky handle (e.g. bsky.app, jay.bsky.team) or full DID (did:plc:...). Used by profile / follows / followers / actorLikes modes.
  • postUri (string): Full AT URI of the post (at://did:plc:.../app.bsky.feed.post/<rkey>).
  • postUris (array): Up to 25 AT URIs to batch-hydrate. Each must be at://did:plc:.../app.bsky.feed.post/<rkey>.
  • postUrls (array): Public bsky.app post URLs to expand, e.g. https://bsky.app/profile/bsky.app/post/3kxxxx.
  • listUri (string): AT URI of a Bluesky list (at://did:plc:.../app.bsky.graph.list/<rkey>).
  • starterPackUri (string): AT URI of a Bluesky starter pack (at://did:plc:.../app.bsky.graph.starterpack/<rkey>).
  • feedPreset (string): Built-in Bluesky feed preset. Overrides feedUri if both are set.
  • feedUri (string): Full AT URI of a feed generator (at://did:plc:.../app.bsky.feed.generator/<rkey>). Use this for community feeds not in the preset list.
  • language (string): ISO 639-1 language code. Drops posts not in this language. Empty = no filter.
  • excludeReplies (boolean): Drop posts that are replies to another post. Default: false.
  • excludeReposts (boolean): Drop posts that are reposts of someone else's post. Default: false.
  • mediaOnly (boolean): Only emit posts that have at least one image / video / external embed. Default: false.
  • minLikes (integer): Drop posts with fewer than this many likes.
  • minReposts (integer): Drop posts with fewer than this many reposts.
  • since (string): Earliest post date as YYYY-MM-DD. Bluesky search recency-weights its index; use the explicit since: filter for strict date bounds.
  • until (string): Latest post date as YYYY-MM-DD.
  • fromUser (string): Restrict search to posts authored by this handle (or DID).
  • maxItems (integer): Hard cap on emitted records. Default: 40.

Protocol constraints and API limits

Understanding AT Protocol AppView constraints prevents unexpected data gaps during execution:

  • mode=search is capped at ~100 posts per query. Bluesky's AppView blocks unauthenticated cursor pagination on searchPosts (HTTP 403 from page 2 onward). Each query returns one page of up to 100 posts. To get more results, run multiple queries with different keywords or use fromUser + date filters to narrow.
  • mode=profile, mode=actorSearch, and mode=feed paginate normally and can return thousands of records.
  • Bluesky search is recency-weighted and does not index every post: very old or low-engagement posts may not surface in searchPosts.
  • Custom feeds depend on third-party feed-generator services; if a generator is offline, the feed returns empty.
  • The actor only reads public data: it cannot access private follower lists or DMs.
  • Bluesky's AT Protocol is still evolving; field names and embed types may shift between major releases.

Quality assurance and verification controls

Maintain operational standards across automated Bluesky data pipelines with these controls:

  • Verify record schemas upon retrieval. Confirm whether recordType equals post or account before attempting downstream transformations.
  • Handle missing optional properties gracefully. Empty fields are dropped at extraction time, so treat absent properties as omitted rather than populated with default values.
  • Apply unique key constraints using uri or cid for posts, and did for account profiles to eliminate duplicate entries when merging multiple runs.
  • Monitor search query boundaries carefully. Because mode=search caps results at 100 posts, partition date windows using since and until parameters for complete historical coverage.
  • Isolate engagement metrics from static content metadata. Post counts like likeCount and repostCount change dynamically over time, whereas createdAt remains immutable.

Frequently asked questions

Do I need a Bluesky account or credentials to run this scraper?

No. Bluesky Scraper leverages public AppView XRPC endpoints. All read operations execute over pure HTTP without logins, session cookies, or proxy requirements.

Why does search mode return maximum 100 posts per query?

Bluesky's public AppView restricts unauthenticated cursor pagination on searchPosts, returning HTTP 403 on subsequent pages. To extract larger post volumes, combine distinct search terms or apply fromUser and date filters (since/until).

How do I target posts containing specific images or external links?

Set mediaOnly to true. This instructs the scraper to drop text-only posts and retain records containing image, video, or external link attachments inside the mediaAttachments array.

What is the difference between feedPreset and feedUri?

feedPreset allows selection of built-in feed shortnames such as whats-hot, discover, or news. If you need a custom community feed, leave feedPreset empty and provide the full feed generator AT URI in feedUri.

How are quote posts and replies structured in the output?

Replies contain parent identifiers in inReplyToUri and inReplyToCid. Quoted posts include nested details inside the quotedPost object containing the quoted post's URI, CID, author handle, DID, and text.

Resources

● Featured actors

Bluesky Scraper

Scrape Bluesky (AT Protocol) using search posts by keyword or hashtag, fetch user timelines, look up profiles, search for accounts, and pull custom feeds. Pure HTTP, no login required, no proxy needed.

Run on Apify ↗