Bluesky Scraper avatar

Bluesky Scraper

Pricing

from $3.00 / 1,000 results

Go to Apify Store
Bluesky Scraper

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.

Pricing

from $3.00 / 1,000 results

Rating

5.0

(22)

Developer

Crawler Bros

Crawler Bros

Maintained by Community

Actor stats

22

Bookmarked

2

Total users

0

Monthly active users

10 days ago

Last modified

Share

Scrape Bluesky (the AT Protocol social network) — full-text search by keyword or hashtag, fetch user timelines, look up profiles, search for accounts, and pull custom feeds. Pure HTTP, no login, no cookies, no proxy required.

Bluesky's public XRPC endpoints serve every read operation without authentication, so the actor runs straight from datacenter IPs.

What you get

Post records (recordType=post)

FieldDescription
uriCanonical AT URI (at://did:plc:.../app.bsky.feed.post/...)
cidContent ID
urlPublic bsky.app URL (derived from uri + author handle)
textPost text
createdAtISO 8601 timestamp
indexedAtWhen Bluesky indexed the post
languageISO 639-1 language code
replyCountReply count
repostCountRepost count
likeCountLike count
quoteCountQuote-post count
bookmarkCountBookmark count
inReplyToUriAT URI of parent post (when reply)
inReplyToCidCID of parent post (when reply)
isReposttrue if surfaced via repost reason
repostedByHandle that reposted (when isRepost=true)
mentionsArray of mentioned DIDs (extracted from facets)
tagsArray of hashtags used (lowercase, extracted from facets)
urlsArray of external URLs in the post (extracted from facets)
mediaAttachmentsArray of {type, url, previewUrl, description} for images/videos/external
quotedPostEmbedded quoted post {uri, cid, text, authorHandle, authorDid}
authorAuthor summary {did, handle, displayName, avatar}
authorHandleAuthor handle (top-level convenience field)
scrapedAtISO 8601 UTC timestamp of extraction

Account records (recordType=account)

FieldDescription
didDID (decentralised identifier)
handleBluesky handle (e.g. bsky.app)
displayNameDisplay name
descriptionBio
avatarAvatar URL
bannerBanner URL
followersCount, followsCount, postsCountStats
createdAtAccount creation timestamp
indexedAtWhen Bluesky last reindexed the profile
urlPublic profile URL

Empty fields are dropped from every record at every depth — the dataset never contains nulls.

Input

ParameterTypeDefaultDescription
modeEnumsearchsearch / profile / actorSearch / feed / postThread / urlFetch / getPosts / follows / followers / getLikes / getActorLikes / getList / getStarterPack / feedGeneratorsDiscovery
searchQueryStringblueskyFree-text query (used by search and actorSearch); also acts as a query keyword for feedGeneratorsDiscovery
searchSortEnumtoptop (engagement) or latest (recency) — applies to mode=search
actorStringbsky.appHandle (bsky.app) or DID. Used by profile / follows / followers / getActorLikes
postUriStringFull AT URI of a post — used by mode=postThread and mode=getLikes
postUrisArrayUp to 25 AT URIs to batch-hydrate — used by mode=getPosts
postUrlsArrayPublic bsky.app post URLs to expand — used by mode=urlFetch
listUriStringAT URI of a Bluesky list — used by mode=getList
starterPackUriStringAT URI of a starter pack — used by mode=getStarterPack
feedPresetEnumBuilt-in feed preset — whats-hot, discover, mutuals, bsky-team, hot-classic, popular-with-friends, for-you, news, trending-videos, quiet-posters. Overrides feedUri when set.
feedUriStringCustom AT feed URI for mode=feed (used when no preset is selected)
languageEnumISO 639-1 dropdown (top 30 codes) — drops posts not in this language
excludeRepliesBooleanfalseDrop reply posts
excludeRepostsBooleanfalseDrop reposts
mediaOnlyBooleanfalseOnly emit posts with at least one media attachment
minLikesIntegerDrop posts with fewer likes
minRepostsIntegerDrop posts with fewer reposts
sinceStringYYYY-MM-DD — earliest post date (search mode)
untilStringYYYY-MM-DD — latest post date (search mode)
fromUserStringRestrict search to a specific author handle / DID
maxItemsInteger40Hard cap on emitted records (1-5000)
{
"mode": "search",
"searchQuery": "AI",
"language": "en",
"minLikes": 50,
"maxItems": 100
}
{
"mode": "search",
"searchQuery": "#python",
"since": "2026-01-01",
"maxItems": 200
}

Example input — user profile

{
"mode": "profile",
"actor": "bsky.app",
"maxItems": 50,
"excludeReplies": true
}
{
"mode": "actorSearch",
"searchQuery": "rust",
"maxItems": 25
}

Example input — custom feed

{
"mode": "feed",
"feedPreset": "whats-hot",
"maxItems": 100
}

Example input — post thread (post + replies)

{
"mode": "postThread",
"postUri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3kxxxx",
"maxItems": 200
}

Example input — expand post URLs

{
"mode": "urlFetch",
"postUrls": [
"https://bsky.app/profile/bsky.app/post/3kxxxx",
"https://bsky.app/profile/jay.bsky.team/post/3kyyyy"
]
}

Example input — followers / follows

{
"mode": "followers",
"actor": "bsky.app",
"maxItems": 200
}

Example input — likes on a post

{
"mode": "getLikes",
"postUri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3kxxxx",
"maxItems": 100
}
{
"mode": "feedGeneratorsDiscovery",
"searchQuery": "news",
"maxItems": 50
}

Example input — author + keyword

{
"mode": "search",
"searchQuery": "release",
"fromUser": "bsky.app",
"maxItems": 50
}

Example output

{
"recordType": "post",
"uri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3ml54ry2iwc2x",
"cid": "bafyreidwzz...",
"url": "https://bsky.app/profile/bsky.app/post/3ml54ry2iwc2x",
"text": "Keep it private! We're adding more ways to connect…",
"createdAt": "2026-04-23T17:06:32.796Z",
"language": "en",
"replyCount": 123,
"repostCount": 255,
"likeCount": 1509,
"quoteCount": 47,
"tags": ["bluesky"],
"mentions": [],
"urls": [],
"mediaAttachments": [
{ "type": "image", "url": "https://cdn.bsky.app/img/feed_fullsize/.../photo.jpg", "previewUrl": "https://cdn.bsky.app/img/feed_thumbnail/.../photo.jpg", "description": "Demonstration of …" }
],
"author": {
"did": "did:plc:z72i7hdynmk6r22z27h6tvur",
"handle": "bsky.app",
"displayName": "Bluesky",
"avatar": "https://cdn.bsky.app/img/avatar/plain/.../jpeg"
},
"authorHandle": "bsky.app",
"scrapedAt": "2026-05-06T05:24:18Z"
}

Use cases

  • Social listening / brand monitoring — Track mentions of your brand or product on Bluesky in real time.
  • Trend research — Pull mode=feed "What's Hot" for a daily snapshot of viral content.
  • Influencer discovery — Combine actorSearch + minLikes filters to surface high-impact accounts in any niche.
  • Academic research — Snapshot public conversations on the AT Protocol, with full media + facet provenance.
  • Cross-platform social monitoring — Pair with our Mastodon / Twitter / Reddit scrapers for full coverage of post-X social media.
  • Content discovery — Surface high-engagement posts on a specific hashtag for content curation.
  • Competitor tracking — Use fromUser + keyword to monitor what specific competitors post about specific topics.

FAQ

Do I need a Bluesky account or login? No. Every endpoint this actor uses (searchPosts, getProfile, getAuthorFeed, searchActors, getFeed) is part of Bluesky's public AppView and serves anonymous traffic.

How does Bluesky's search work? Bluesky supports its standard search operators in the searchQuery:

  • from:handle — posts by a specific user
  • since:YYYY-MM-DD / until:YYYY-MM-DD — date range
  • lang:en — language filter
  • #hashtag — exact hashtag match

The actor also exposes since, until, fromUser, and language as dedicated input fields that get folded into the query.

What's the difference between mode=search and mode=actorSearch?

  • mode=search runs full-text search across posts.
  • mode=actorSearch runs typeahead-style search across accounts (handles + display names + bios).

What's a "feed" and which shortnames are supported? A feed is a curated post stream produced by a feed-generator service. Built-in shortnames: whats-hot / discover (Bluesky's official trending feed), bsky-team, mutuals. Pass any AT URI directly via feedUri to scrape custom feeds.

How are reposts handled? A repost surfaced via getAuthorFeed is emitted as one record with isRepost=true and repostedBy=<handle>, with the underlying post's text/media/counts preserved. Use excludeReposts=true to drop these.

How are quoted posts handled? A quote-post is emitted as one record with the quoter's text in text and the quoted post's metadata in quotedPost: {uri, cid, text, authorHandle, authorDid}.

How current is the data? Live — every run hits Bluesky's AppView at request time. Schedule the actor for hourly / daily refreshes.

Do I need a proxy? No. The Bluesky AppView is happy to serve datacenter IPs. The actor sets a polite User-Agent and stays well under any rate limit.

Limitations

  • 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.