Bluesky Scraper avatar

Bluesky Scraper

Pricing

$0.50 / 1,000 rows

Go to Apify Store
Bluesky Scraper

Bluesky Scraper

Scrapes Bluesky posts from profiles, single posts and threads, custom feeds, lists and keyword searches, with likes, reposts, replies, quotes, images, link cards and hashtags. Optionally adds profile rows and follower or following lists. No login needed.

Pricing

$0.50 / 1,000 rows

Rating

0.0

(0)

Developer

Mina

Mina

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

6 days ago

Last modified

Share

What does Bluesky Scraper do?

Bluesky Scraper collects posts from Bluesky as clean, structured data: the full text, date, likes, reposts, replies, quotes and bookmarks, the author, images with alt text, videos, link cards, quoted posts, hashtags, mentions and links. Paste profiles, single posts, custom feeds or lists, or type search words, and get one row per post. Turn on extra rows for profiles (follower, following and post counts), followers and followed accounts, and every reply in a thread.

It reads Bluesky's own public API, so it needs no login, no account and no cookies, and it is fast: the prefilled example returns 40 posts in about 4 seconds. Running on the Apify platform also gives you API access, scheduled runs, integrations (Google Sheets, Make, Zapier, webhooks), run monitoring, and automatic retries through Apify Proxy if Bluesky is ever slow to answer.

Why scrape Bluesky?

  • Social listening and brand monitoring: track every new post that mentions your brand, product, hashtag or competitor.
  • Research and journalism: collect what politicians, journalists, scientists or any public account posts, with engagement counts, for analysis.
  • Influencer and audience research: compare accounts by followers, posting rate and the likes and reposts their posts earn; export follower lists.
  • Trend tracking: read custom feeds and curated lists to see what a community is talking about right now.
  • AI and NLP datasets: build labelled text datasets with language tags, alt text and conversation structure (reply parent and root).

How to scrape Bluesky

  1. Open a profile, post, feed or list on bsky.app and copy the address bar, for example https://bsky.app/profile/bsky.app. A handle such as @bsky.app works too.
  2. Paste it into Bluesky links or handles, one per line. To search instead, type words into Search posts.
  3. Set Max posts per input, and optionally a language or a date range.
  4. Click Start. Download the results as JSON, CSV or Excel when the run finishes.

Input

Everything is set on the Input tab. In JSON, an input looks like this:

{
"startUrls": [
"https://bsky.app/profile/bsky.app",
"https://bsky.app/profile/bsky.app/post/3l6oveex3ii2l",
"https://bsky.app/profile/bsky.app/feed/whats-hot",
"https://bsky.app/profile/bsky.app/lists/3lvpca43j5z26"
],
"searchQueries": ["open source", "#photography", "climate from:nytimes.com"],
"maxPostsPerInput": 100,
"includeThreadReplies": true,
"searchSort": "latest",
"language": "en",
"since": "30 days",
"includeProfiles": true
}
FieldWhat it does
startUrlsProfiles (bsky.app/profile/<handle>, @handle, a bare handle, or a did:plc:… id), post links (…/post/<id>), custom feeds (…/feed/<name>), lists (…/lists/<id>), and bsky.app search or hashtag links. Plain strings or {"url": "…"} objects.
searchQueriesWords to search all of Bluesky for. Operators work: from:handle, mentions:handle, #hashtag, "exact phrase", domain:example.com, -word, lang:ja, since:2026-09-01, until:2026-10-01.
maxPostsPerInputMost posts saved per link or search. Default 100. For a post link, the most replies saved under the post. 0 saves only profile, follower and following rows.
includeRepliesFor profiles and lists, also save replies to other people's posts. Default off: own posts and own threads only.
includeRepostsFor profiles, also save posts the account reposted, with repostedBy and repostedAt. Default off.
includeThreadRepliesFor post links, also save the replies in the thread: the post plus up to maxPostsPerInput replies, so up to 1 + N billed rows per link. Default off.
searchSortlatest (default) or top.
languageOnly posts tagged with this language, such as en, ja, pt-BR.
since / untilDate range: a date (2026-09-01, UTC), a date and time, or an age (7 days, 12 hours). Applies to profiles, feeds, lists and searches.
includeProfilesOne row per profile link with its counts, bio, avatar and join date.
includeFollowers / includeFollowingOne row per follower / followed account of each profile link, newest first.
maxFollowsPerProfileMost followers, and most followed accounts, per profile. Default 100.
proxyConfigurationLeave empty. Bluesky's API usually answers the Actor directly; when a request is refused or stalls, the Actor retries through Apify datacenter and then residential proxies by itself.

Output

Every post, profile and account becomes one row, marked by type. Here is a real post row:

{
"type": "post",
"uri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3mxu3hsnebc2v",
"url": "https://bsky.app/profile/bsky.app/post/3mxu3hsnebc2v",
"cid": "bafyreihprzpev5lpm4wkevfteaurguvmtmzq4cmg6guzwxvmlumvfdcsmy",
"text": "saw some cool clouds today",
"createdAt": "2026-10-14T17:35:30.592Z",
"indexedAt": "2026-10-14T17:35:33.661Z",
"authorHandle": "bsky.app",
"authorDid": "did:plc:z72i7hdynmk6r22z27h6tvur",
"authorDisplayName": "Bluesky",
"authorAvatar": "https://cdn.bsky.app/img/avatar/plain/did:plc:z72i7hdynmk6r22z27h6tvur/bafkrei…",
"replyCount": 234,
"repostCount": 410,
"likeCount": 7650,
"quoteCount": 44,
"bookmarkCount": 156,
"languages": ["en"],
"hashtags": [],
"mentions": [],
"links": [],
"images": [
{
"url": "https://cdn.bsky.app/img/feed_fullsize/plain/did:plc:z72i7hdynmk6r22z27h6tvur/bafkrei…",
"thumbnailUrl": "https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:z72i7hdynmk6r22z27h6tvur/bafkrei…",
"alt": "Photo taken from a hill showing a cloud inversion in the valley below, underneath a bright blue sky with a few streaks of clouds",
"width": 1200,
"height": 1600
}
],
"video": null,
"externalLink": null,
"quotedPost": null,
"embeddedRecord": null,
"replyParentUri": null,
"replyRootUri": null,
"labels": [],
"repostedBy": null,
"repostedAt": null,
"sourceInput": "https://bsky.app/profile/bsky.app",
"scrapedAt": "2026-10-20T15:13:22.838510+00:00"
}

And a profile row (with Save profile rows on):

{
"type": "profile",
"did": "did:plc:z72i7hdynmk6r22z27h6tvur",
"handle": "bsky.app",
"displayName": "Bluesky",
"description": "official Bluesky account (check username👆)\n\nBugs, feature requests, feedback: support@bsky.app",
"avatar": "https://cdn.bsky.app/img/avatar/plain/did:plc:z72i7hdynmk6r22z27h6tvur/bafkrei…",
"createdAt": "2023-04-12T04:53:57.057Z",
"isVerified": false,
"labels": [],
"url": "https://bsky.app/profile/bsky.app",
"banner": "https://cdn.bsky.app/img/banner/plain/did:plc:z72i7hdynmk6r22z27h6tvur/bafkrei…",
"followersCount": 35319612,
"followsCount": 22,
"postsCount": 883,
"listsCount": 18,
"feedsCount": 7,
"starterPacksCount": 15,
"pinnedPostUri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3l6oveex3ii2l",
"sourceInput": "https://bsky.app/profile/bsky.app",
"scrapedAt": "2026-10-20T15:13:21.690549+00:00"
}

Follower and following rows (type follower or following) have the same account fields as a profile row, without the counts, plus ofHandle and ofDid: the profile they follow or are followed by.

The Output tab has two views, Posts and Profiles, followers and following. You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

Data fields

Post rows (type is post):

FieldDescription
uri, cidThe post's AT Protocol id and content hash.
urlLink to the post on bsky.app.
textThe full post text.
createdAtWhen it was posted, as the author's app stated it (UTC, ISO 8601).
indexedAtWhen Bluesky first saw it (UTC, ISO 8601).
authorHandle, authorDid, authorDisplayName, authorAvatarWho posted it.
replyCount, repostCount, likeCount, quoteCount, bookmarkCountEngagement counts, as numbers.
languagesLanguage tags the author's app set, such as ["en"].
hashtagsHashtags, without the #.
mentionsMentioned accounts as {did, handle}.
linksWeb addresses linked in the text, then the link card's address.
imagesEach image's full-size url, thumbnailUrl, alt text, width and height.
videoplaylistUrl (HLS), thumbnailUrl, alt, width, height, or null.
externalLinkThe link card: url, title, description, thumbnailUrl, or null.
quotedPostThe quoted post's uri, url, text, createdAt, author and counts; status is available, notFound, blocked or detached.
embeddedRecordA shared feed, list or starter pack: kind, uri, name, url, creatorHandle.
replyParentUri, replyRootUriFor replies, the post replied to and the thread's first post.
labelsModeration labels on the post (for example adult-content labels); usually empty.
repostedBy, repostedAtFor reposts saved from a profile, who reposted it and when.
sourceInputThe link or search the row came from.
scrapedAtWhen the row was saved.

Profile rows (type is profile): did, handle, displayName, description, avatar, banner, createdAt (join date), isVerified, labels, url, followersCount, followsCount, postsCount, listsCount, feedsCount, starterPacksCount, pinnedPostUri. Follower and following rows add ofHandle and ofDid. An account whose handle no longer resolves has handle set to null, and its url uses its DID.

How much does it cost to scrape Bluesky?

You pay per row saved; see the Pricing tab for the exact price. Rows are cheap to make: the Actor uses Bluesky's JSON API with plain HTTP requests (no browser), 512 MB of memory, and usually no proxy, so a run of 1,000 posts typically finishes in seconds. Nothing is charged for links that give no data.

Tips and advanced options

  • Searching an account's posts: cats from:bsky.app searches one account. For all of an account's posts, paste its profile link instead: it pages back much further.
  • Search depth: latest searches page back through time as far as your limit. top returns Bluesky's best-ranked posts, at most 100 per search. A search made only of operators (such as from:bsky.app or mentions:bsky.app, with no plain word) also returns at most about 100 posts, because Bluesky gives logged-out users only one page of those.
  • Dates: since stops profiles, lists and searches as soon as posts get older than the date, so a small date range keeps runs short.
  • Lists: Bluesky only lets logged-in users read a list's feed, so the Actor rebuilds it: it reads every member's own posts (up to 500 members) and merges them newest first. Reposts are left out, and replies only come in with Include profiles' replies on, so the result can differ a little from the list feed in the Bluesky app. Large lists take a little longer.
  • Custom feeds are ranked by their creator, not by date, so since and until filter them instead of stopping them, and very deep pages of some feeds are refused by Bluesky.
  • Threads: a post link with Include replies under post links saves the post first, then up to Max posts per input replies depth first (so up to 1 + N rows, each billed), each with replyParentUri so you can rebuild the conversation.

FAQ, disclaimers, and support

Do I need a Bluesky account? No. The Actor reads only what Bluesky shows to logged-out visitors through its public API. Posts that their author restricted to logged-in users are not visible to it.

Why did an input give nothing? Unknown handles, deleted posts, missing feeds, moderation lists and searches with no results are skipped, not billed, and listed with the reason in the FAILED_INPUTS record of the run's key-value store. The run's status message sums them up.

Is it legal to scrape Bluesky? This Actor collects only publicly available data. Posts and profiles can contain personal data, which is protected by laws such as the GDPR in the EU. Follower and following rows in particular hold other people's handles, names, bios and avatars, not just the profile you asked for. Only collect personal data when you have a legitimate reason to, and check with a lawyer if you are unsure. Please also respect Bluesky's terms of service.

Something does not work, or you need a feature? Open an issue on the Issues tab and it will be looked at quickly. If you need a custom solution, get in touch through the same tab.