Bluesky Posts Search Scraper - AT Protocol API, No Key avatar

Bluesky Posts Search Scraper - AT Protocol API, No Key

Pricing

from $1.00 / 1,000 post rows

Go to Apify Store
Bluesky Posts Search Scraper - AT Protocol API, No Key

Bluesky Posts Search Scraper - AT Protocol API, No Key

Search Bluesky posts and author feeds through the public AT Protocol endpoints: text, handle, timestamps, likes, reposts, replies, links and images. No login or key. dryRun prices a run before you pay; charged only for posts delivered.

Pricing

from $1.00 / 1,000 post rows

Rating

0.0

(0)

Developer

Natalia Ivanova

Natalia Ivanova

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

12 days ago

Last modified

Share

Bluesky Posts & Search Scraper - AT Protocol, No API Key

Search every public post on Bluesky by keyword, or pull the full public feed of any account, and get clean rows: post text, permalink, author handle, timestamps, likes, reposts, replies, quotes, declared languages, outbound links, link cards, images with alt text, hashtags and mentions. It talks to the official public AT Protocol endpoints — app.bsky.feed.searchPosts, app.bsky.feed.getAuthorFeed and app.bsky.actor.getProfile — so there is no login, no app password, no API key and no browser to babysit.

What you can do with it

  • Brand and competitor monitoring — every mention of your product, your domain or a rival's name since yesterday, straight into Slack or a Google Sheet through Apify integrations.
  • Hashtag and campaign tracking — all posts carrying #yourconference in a date window, with engagement counts so you can rank them.
  • Link and traffic research — which Bluesky posts link to example.com, who posted them and how far they travelled.
  • Account archives — the complete public post history of an account, replies and reposts included or excluded as you like.
  • Datasets for analysis — a language-filtered slice of public conversation about a topic, ready for sentiment work or topic modelling.
  • AI agents — "what is Bluesky saying about X this week?" through the Apify MCP server.

Bluesky search: find posts by keyword

Set mode to search and give queries one or more terms. Every term is searched separately, results are merged and deduplicated by post URI, and matchedQuery on each row tells you which term produced it. Bluesky's own search syntax works inside a query too — "exact phrase", from:handle, domain:example.com — and sort picks between newest first and Bluesky's relevance ranking.

{ "mode": "search", "queries": ["apify", "web scraping"], "sinceDate": "7 days", "language": "en", "maxItems": 1000 }

Bluesky posts from one account: the author feed

Set mode to author-feed and list authors as handles, profile URLs or DIDs. Each feed is read newest first until the sinceDate boundary, so an incremental daily run is cheap. The account's public profile (display name, bio, follower counts, post count) lands in the run summary.

{ "mode": "author-feed", "authors": ["bsky.app"], "includeReplies": true, "includeReposts": true, "maxItems": 1000 }

Input

FieldTypeDefaultDescription
modeselectsearchsearch (keyword search, needs queries) or author-feed (posts of given accounts, needs authors).
queriesarray[]Required in search mode. Words, phrases, hashtags or domains; merged and deduplicated.
authorsarray[]Required in author-feed mode. Handles (bsky.app), profile URLs or DIDs.
sortselectlatestlatest or top. Search mode only; author feeds are always newest first.
sinceDate / untilDatestring—2026-10-01, today, yesterday, 24 hours, 7 days, 1 year or a full ISO stamp.
languagestring—Two-letter code the post declares: en, pt, ja. pt also matches pt-BR.
searchAuthorstring—Search mode: keep only results from this handle or DID.
includeRepliesbooleantrueKeep posts that reply to another post.
includeRepostsbooleanfalseAuthor-feed mode: also return reposts (isRepost, repostedBy).
maxItemsPerQuerynumber1000Cap per query or per author.
maxItemsnumber1000Cap for the whole run.
proxyConfigurationobjectoffOptional. Needed only if the public hosts refuse your run with HTTP 403.

More examples:

{ "mode": "search", "queries": ["#buildinpublic"], "sort": "top", "sinceDate": "30 days", "includeReplies": false }
{ "mode": "search", "queries": ["domain:example.com"], "sinceDate": "90 days", "maxItemsPerQuery": 500 }
{ "mode": "search", "queries": ["postgres"], "searchAuthor": "bsky.app", "language": "en" }

Output

One row per post:

{
"uri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3mx5e63uvns2d",
"cid": "bafyreidlxv7m376e3knixcu5ylvglltzkotygwtvh5ifsg4zcfow2z6rp4",
"url": "https://bsky.app/profile/bsky.app/post/3mx5e63uvns2d",
"text": "Congratulations to Nobel Prize winner @deisseroth.bsky.social!",
"createdAt": "2026-10-05T16:39:54.000Z",
"indexedAt": "2026-10-05T16:39:55.112Z",
"author": { "handle": "bsky.app", "displayName": "Bluesky", "did": "did:plc:z72i7hdynmk6r22z27h6tvur", "avatar": "https://cdn.bsky.app/img/avatar/plain/did:plc:z72i7hdynmk6r22z27h6tvur/bafkrei....jpeg" },
"authorHandle": "bsky.app",
"likeCount": 2841,
"repostCount": 312,
"replyCount": 47,
"quoteCount": 9,
"langs": ["en"],
"isReply": false,
"parentUri": null,
"rootUri": null,
"isRepost": false,
"repostedBy": null,
"hashtags": [],
"mentions": [{ "handle": "deisseroth.bsky.social", "did": "did:plc:qmmohi6hskhsvqbw46eflibx" }],
"links": [],
"externalLinks": [],
"images": [],
"hasVideo": false,
"quotedPostUri": "at://did:plc:ilmbc32kos5zwmkqh2nxamwc/app.bsky.feed.post/3mx4smdh4el2k",
"quotedPostUrl": "https://bsky.app/profile/nobelprize.org/post/3mx4smdh4el2k",
"quotedPostAuthor": "nobelprize.org",
"quotedPostText": "The 2026 Nobel Prize announcements start today.",
"matchedQuery": "nobel",
"scrapedAt": "2026-10-12T11:37:45Z"
}

links holds URLs written in the post text, externalLinks holds the link card the post attached (url, title, description, thumbnailUrl), and images holds url, thumbnailUrl, alt, width, height per image. mentions carries both the handle, read from the post's richtext facet, and the stable DID. The OUTPUT record in the key-value store lists posts per query or author, duplicates skipped, posts filtered out, API requests made, author profiles and any errors.

A Bluesky scraper without API key: how it works

Bluesky's AppView serves its read endpoints publicly: no session, no app password, no developer registration, no rate-limit key. This Actor calls them directly over HTTPS and maps the lexicon's postView records into flat rows. That means your results are exactly what the official client sees, you are never asked for your Bluesky credentials, and nothing breaks when the website's HTML changes.

Why the AT Protocol endpoints and not the website

Scraping bsky.app in a browser is slower, heavier and fragile. The AT Protocol lexicons are versioned, documented and stable, and they hand over the structured fields — byte-indexed richtext facets, embed views, engagement counts — that an HTML page only hints at. Hashtags and mentions here come from the facets the author actually published, not from a regular expression over the text, so #tag inside a URL never becomes a false hashtag.

Pricing

Pay per event: a small fee per Actor start plus a fee per post returned. Current prices are in the Pricing tab.

Good to know

  • Search covers Bluesky's public index. Very old posts and posts from accounts that opted out of public indexing may not appear; an author feed is the exhaustive route for one account.
  • Engagement counts are a snapshot taken at scrape time. Run again later for fresh numbers.
  • langs is what the author's client declared, not detected language. Posts that declare nothing are skipped when you set language — leave it empty to keep them.
  • Search never returns reposts, so includeReposts only matters for author feeds.
  • Bluesky's public AppView fronts its endpoints with a CDN that answers HTTP 403 for some endpoint and network combinations — search is the one that gets blocked in practice. The Actor falls back to a second public AT Protocol host automatically and records in the run summary which host served the data; if both refuse, switch on proxyConfiguration (residential group) and run again.
  • A handle that does not resolve is reported as one error in the summary and does not stop the other authors.

Use with AI agents (MCP)

Add the Actor to the Apify MCP server and ask: "What is Bluesky saying about SQLite this week?" → { "mode": "search", "queries": ["sqlite"], "sinceDate": "7 days" }.

Public data and personal data

This Actor returns only what the authors published publicly: post text, their chosen handle and display name, their public avatar URL, public timestamps and public engagement counts. It never logs in, never reads direct messages, follower lists or blocked lists, never touches anything behind a login, and collects no e-mail addresses, phone numbers, locations or any other field aimed at identifying a person beyond the public handle they chose themselves.

Public does not mean unregulated. Posts are personal data under the GDPR and comparable laws when they are about identifiable people, and the content belongs to its authors. You, the operator of the run, are the controller of whatever you collect and are responsible for having a lawful basis, for honouring deletion requests, for retention limits and for complying with Bluesky's terms. Do not use the output to profile individuals, to build identity dossiers, to train on personal data without a basis, or for anything else the authors would not expect.

Disclaimer

Not affiliated with Bluesky Social PBC or the AT Protocol project. Data comes from the public AT Protocol AppView endpoints; all content belongs to its authors.

Cost control

Pay per event only works if you can see the bill before you pay it:

  • Set dryRun to count every result and print what a full run would cost - nothing is charged, and only a few sample rows are stored.
  • You are charged only for rows actually delivered to the dataset; a run that finds nothing costs nothing beyond the start event.
  • maxItems is respected exactly, and the run stops before the platform's Max total charge for the run.
  • Every run writes a COST record to the key-value store: chargeable events, charged events, the amount in USD and whether a limit was hit.