Bluesky Posts Scraper
Last updated November 9, 2026
Search Bluesky posts by keyword, read an account's posts, or read a post and its replies. Exact like, reply, repost, and quote counts, with dates, hashtags, links, and images. No login and no key. You pay per row.
Features
- Keyword search with sort, date, and language filters.
- An account's posts, with or without its replies and reposts.
- A post and its replies from a post address.
- Exact like, reply, repost, and quote counts.
- A free status row per source says what it returned or why it stopped.
- Pay per event: Post row at $0.0011.
Input
queriesarrayoptionalKeywords to search, up to 20. Without your own app password each search returns one page, about 100 posts. Text from Clay splits on new lines, so a query can hold a comma.
authorsarrayoptionalBluesky handles, profile addresses, or DIDs, up to 20. Returns each account's own posts, newest first.
post_urlsarrayoptionalAddresses of Bluesky posts to read, up to 100.
sortstringoptionallatest or top. Default latest. Used for queries.
since_datestringoptionalOnly posts from this date, such as 2026-10-01.
until_datestringoptionalOnly posts before this date, such as 2026-11-01.
languagestringoptionalLanguage code such as en or de. Used for queries. Reads the language the post's author set.
max_posts_per_sourcestringoptionalPer query or account, up to 2000. Default 100. A search with no app password stops at about 100.
include_repliesstringoptionalyes or no. Default no. Reads the replies under each post found. Each reply is a charged row.
max_replies_per_poststringoptionalUp to 200. Default 20.
include_account_repliesstringoptionalyes or no. Default no. Used for accounts.
include_repostsstringoptionalyes or no. Default no. Used for accounts. A repost row shows the original author.
bluesky_handlestringoptionalOptional, with the app password. Used only to page a search past its first page.
bluesky_app_passwordstringoptionalOptional. Create an app password in Bluesky settings; never use your main password. Sent only to Bluesky. Without it a search returns one page, about 100 posts. Accounts and post addresses need no password.
max_charge_usdstringoptionalOptional. The run stops before a charge that would pass this amount. Summary rows are always returned.
Output schema
{
"row_type": "string",
"row_key": "string",
"source_type": "string",
"query": "string",
"account": "string",
"input_url": "string",
"query_in_text": "boolean",
"post_uri": "string",
"url": "string",
"text": "string",
"author_handle": "string",
"author_name": "string",
"author_did": "string",
"author_url": "string",
"created_at": "string",
"indexed_at": "string",
"likes": "integer",
"replies": "integer",
"reposts": "integer",
"quotes": "integer",
"languages": "array",
"hashtags": "array",
"mentions": "array",
"links": "array",
"image_urls": "array",
"is_reply": "boolean",
"parent_uri": "string",
"root_uri": "string",
"posts_returned": "integer",
"replies_returned": "integer",
"list_complete": "boolean",
"row_status": "string",
"error_reason": "string",
"billable_events_json": "string",
"scraped_at": "string"
}Pricing
| Event | Free plan price |
|---|---|
| Post row | $0.0011 |
| Actor Start | $0.005 |
Pay per event on the Apify platform. Paid Apify plans pay less per event. No subscription, no seat license.
On the Apify free plan the actor stops at $1.50 of charges a month, about 1,364 post rows. Any paid Apify plan removes the cap.
Limits
- A search with no account returns one page, about 100 posts per query. Bluesky answers any later search page with HTTP 403 "forbidden by administrative rules" from every exit tested. The status row reads partial and says so. The actor does not slice dates to get past this. To page further, give your own bluesky_handle and bluesky_app_password.
- The app password route has not run on a real account. Fixtures and the refused password path are the test, and the first buyer's password is the live test. Use an app password, never your main password. It is sent only to Bluesky, stays out of rows and logs, and is used only for search.
- A login session lasts about 2 hours by Bluesky's own setting, and a longer search then ends as partial.
- Accounts page with no account of your own: 2,000 unique posts from one account in one test run, 303 seconds. 2,000 per source is the actor's maximum.
- Bluesky decides what a search matches, and it also matches things a row does not show, such as a link target. query_in_text reads false on those rows. In one test, 13 of 99 read false, and these rows are charged.
- Replies come from the first 6 levels of a thread. Blocked and deleted replies are skipped.
- If the first 5 sources return nothing, the run stops with a free row, so a list of dead entries does not run on. After any row is returned, every source runs.
- A repost row shows the original author and post, not who reposted it.
- An author who asks Bluesky not to show them to logged out viewers is skipped, free, on every route, including when you give an app password. On one search page, 10 of 100 posts were skipped this way, so a search can return fewer rows than the maximum. An account or post input like this reads no_results and says why.