Bluesky Scraper - Posts, Profiles & Keyword Search avatar

Bluesky Scraper - Posts, Profiles & Keyword Search

Pricing

$2.00 / 1,000 post returneds

Go to Apify Store
Bluesky Scraper - Posts, Profiles & Keyword Search

Bluesky Scraper - Posts, Profiles & Keyword Search

Bluesky serves a profile and an author's timeline to anyone who asks. Its keyword search stopped: signed-out requests come back 403, so archive search here needs an app password of your own. Without one the run watches the live stream. $2.00 per 1,000 posts, no start fee.

Pricing

$2.00 / 1,000 post returneds

Rating

5.0

(1)

Developer

Dami's Studio

Dami's Studio

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

2 days ago

Last modified

Share

Bluesky Scraper

Bluesky serves a profile and an author's timeline to anyone who asks, straight off the public AT Protocol AppView, with no account involved. Two things this does: scrape a list of author handles (their profile plus their recent posts), or search for a keyword.

Author scraping needs no login. Keyword search is more complicated, and it's worth reading the next section before you buy.

Bluesky stopped serving archive search to signed-out clients. A logged-out request to the search endpoint gets a 403. That's their change, and no proxy or user agent gets around it.

So a keyword query has three possible lanes, and the row tells you which one you got in its source field:

sourceWhat it actually isNeeds an app password
archive_searchThe real historical index. Everything Bluesky has.Yes
topic_feedPublic Bluesky topic feeds whose own name or description matches your keyword, and their recent posts. Historical and on-topic, but it's a feed, not a search.No
live_captureWatches the public post stream for a set window and keeps posts matching your keyword. Only catches things posted while the run is watching.No

Left on auto, the actor uses the archive if you gave it credentials, tries topic feeds if you didn't, and falls back to live capture. Every keyless run also writes one uncharged notice row spelling out which lane it used, so you're never guessing.

If you want the full historical index, supply blueskyIdentifier and blueskyAppPassword. That's an app password from bsky.app → Settings → Privacy and security → App passwords, never your real account password. Set searchMode to archive and the run won't quietly substitute a lesser lane. Without credentials it says archive search is unavailable and returns nothing, uncharged.

Rows from topic_feed carry a matchesQueryText flag: true when the post text itself contains your keyword, false when the feed was on-topic but the post never used your exact word. Both happen.

What you get

A post row:

{
"type": "post",
"uri": "at://did:plc:zwzbnzr6dzo3lbr2wnfuggfi/app.bsky.feed.post/3mtlyz56v7s2b",
"postUrl": "https://bsky.app/profile/testament3.blacksky.app/post/3mtlyz56v7s2b",
"authorHandle": "testament3.blacksky.app",
"authorName": "testament3",
"authorDid": "did:plc:zwzbnzr6dzo3lbr2wnfuggfi",
"text": "It sux that it's become enmeshed in my #LikeList, but I do enjoy how exasperated he gets...",
"createdAt": "2026-08-21T14:49:26.435Z",
"likeCount": 0,
"repostCount": 0,
"replyCount": 0,
"quoteCount": 0,
"langs": ["en"],
"source": "live_capture",
"matchedQuery": "music",
"capturedDuringSecs": 40
}

A profile row, one per handle in authorHandles:

{
"type": "profile",
"did": "did:plc:z72i7hdynmk6r22z27h6tvur",
"handle": "bsky.app",
"displayName": "Bluesky",
"description": "official bluesky account",
"followersCount": 1234567,
"followsCount": 42,
"postsCount": 890,
"avatar": "https://cdn.bsky.app/img/avatar/plain/...",
"banner": "https://cdn.bsky.app/img/banner/plain/...",
"createdAt": "2023-04-12T04:53:57.057Z",
"profileUrl": "https://bsky.app/profile/bsky.app"
}

Counts on a freshly captured post are usually zero. You caught it seconds after it was written and nobody has liked it yet. If you want engagement numbers, scrape the author's timeline later instead.

Input

Scrape authors, no login:

{
"authorHandles": ["bsky.app", "jay.bsky.team"],
"maxItems": 200
}

Search the full archive:

{
"searchQuery": "artificial intelligence",
"searchMode": "archive",
"blueskyIdentifier": "yourname.bsky.social",
"blueskyAppPassword": "xxxx-xxxx-xxxx-xxxx",
"maxItems": 500
}

Monitor a keyword in real time, no login:

{
"searchQuery": "product launch",
"searchMode": "live",
"liveWatchSecs": 300,
"maxItems": 100
}
  • maxItems — per query or per author handle, not a run total. Ceiling 1,000, default 100.
  • liveWatchSecs — how long live capture watches, 10 to 900 seconds, default 60. It stops early once it hits maxItems. A common word fills up in seconds. A rare one may watch the whole window and return two posts.
  • authorHandles — the leading @ is optional.
  • searchQuery — quoted "phrases" stay whole; several bare words must all appear.
  • proxyConfiguration — off by default. The public API has no anti-bot, so you don't need it. Turn it on only if your region is being rate-limited.

You can also write each post into Notion as it finishes, via notionConnector. Results land in the dataset either way.

Limits

  • Live capture only sees the future. It cannot reach back for a post written before the run started.
  • Archive search needs your own credentials. There is no shared account behind this actor.
  • 1,000 items per query or author, per run.
  • Author timelines return recent posts, not the complete lifetime history of the account.

Billing

$2.00 per 1,000 posts, and there is no run-start fee.

Profile rows and notice rows are not charged. You pay for posts, deduplicated by post URI, so the same post appearing in two feeds bills once. A run that returns nothing costs nothing, which is the case worth knowing about for live capture on a rare keyword.