Bluesky Posts Scraper — Search, Feeds & Threads avatar

Bluesky Posts Scraper — Search, Feeds & Threads

Pricing

from $5.00 / 1,000 public bluesky post scrapeds

Go to Apify Store
Bluesky Posts Scraper — Search, Feeds & Threads

Bluesky Posts Scraper — Search, Feeds & Threads

Search public Bluesky posts, export author feeds and threads, and get clean engagement data for research. Works with Apify MCP and the API.

Pricing

from $5.00 / 1,000 public bluesky post scrapeds

Rating

0.0

(0)

Developer

Khadin Akbar

Khadin Akbar

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

17 days ago

Last modified

Share

What is Bluesky Posts Scraper — Search, Feeds & Threads?

Bluesky Posts Scraper — Search, Feeds & Threads returns one dataset row per public Bluesky post from keyword searches, author feeds or post threads: post text, AT URI and web URL, author handle, DID and display name, created and indexed times, like, repost, reply and quote counts, languages, hashtags, mentions, links, media URLs, reply context and the query or URL that found it. Social listening teams, brand and PR managers, journalists, researchers and AI agents use it to monitor conversations and build Bluesky datasets, with no Bluesky account or app password.

Why people use this Bluesky scraper

  • Three ways in. queries searches all public posts, handles collects author feeds, and postUrls exports a post with its reply thread.
  • Search filters that matter. since, until, language, author, mentions, domain, exactUrl and tags narrow searches on Bluesky itself.
  • Engagement thresholds. minLikes, minReposts and minReplies keep only posts that drew a reaction.
  • Stable IDs. postUri and authorDid stay the same when handles change, so they make clean keys for deduplication and joins.
  • Provenance on every row. sourceType and sourceQuery or sourceUrl show which search, feed or thread each post came from.

Best fit for this Actor

  • Best fit for brand monitoring, news and link tracking, community research and conversation exports on Bluesky.
  • Designed for public posts: searches, public author feeds and public threads.
  • Use domain to see who shares links to a publication or website, and postUrls with includeThreadReplies to export a whole discussion.
  • When you want account details such as bio and follower counts, then pass the authorHandle values to Bluesky Profile Details Scraper.
  • To track the same topic on X, continue with X Twitter Search Scraper and compare the two conversations.

Example workflow: from a publication domain to a share report

A newsroom audience editor starts with domain set to their site, sort set to latest and maxResults at 200. The dataset returns every recent post linking to the site, with authorHandle, likeCount, repostCount and createdAt. They group posts by links and text to see which articles travel, rank sharers by engagement, and pass the most active handles to their community team. They then schedule the same input daily with since set to the previous day and export each run to their analytics sheet.

Input

Search recent posts:

{
"queries": ["climate tech", "renewable energy"],
"sort": "latest",
"language": "en",
"minLikes": 10,
"maxResults": 100
}

Collect author feeds:

{
"handles": ["bsky.app", "https://bsky.app/profile/apify.com"],
"authorFeedFilter": "posts_no_replies",
"maxResults": 50
}

Export a thread:

{
"postUrls": ["https://bsky.app/profile/bsky.app/post/3mw2cdr44fc2a"],
"includeThreadReplies": true,
"threadDepth": 2,
"maxResults": 100
}
FieldTypeWhat it controls
queriesarray of stringsKeywords, phrases, hashtags, URLs or Bluesky search syntax, up to 50.
handlesarray of stringsHandles, DIDs or profile URLs whose feeds to collect.
postUrlsarray of stringsPost URLs or at:// URIs.
maxResultsintegerCap on posts saved across the run, up to 1,000. Default 50.
sortstringSearch order: latest or top. Default latest.
authorFeedFilterstringposts_with_replies, posts_no_replies, posts_with_media, posts_and_author_threads or posts_with_video.
includeThreadReplies, threadDepthboolean, integerCollect public replies under each post, up to 20 levels deep.
since, untilstringsSearch date range as ISO dates or datetimes.
languagestringTwo-letter language code for search results.
author, mentionsstringsLimit search to posts by, or mentioning, a handle or DID.
domain, exactUrlstringsLimit search to posts linking to a domain or an exact URL.
tagsarray of stringsLimit search to tags, entered without #.
minLikes, minReposts, minRepliesintegersMinimum engagement to keep a post.

With every target field empty, the Actor runs a small AI search, so {} works as a quick check.

Output

Every row is a post record.

FieldWhat it contains
postUri, postUrl, cidStable AT URI, web link and content ID
text, languagesPost text and declared languages
hashtags, mentions, linksTags, mentioned accounts and links marked up in the post
mediaUrls, embedTypeImages or link cards and the embed type
authorDid, authorHandle, authorDisplayName, authorAvatarAuthor identity
createdAt, indexedAtWhen the post was written and indexed
likeCount, repostCount, replyCount, quoteCountEngagement at collection time
isReply, replyParentUri, replyRootUriReply context
isRepost, repostedByHandleRepost context in author feeds
sourceType, sourceQuery, sourceUrl, providerHow the post was found: search, author feed, direct_post or thread_reply
scrapedAtCollection time

Example row from a search (author details are illustrative):

{
"recordType": "post",
"postUri": "at://did:plc:exampleauthor000000000000/app.bsky.feed.post/3mwst2vdkgc2b",
"postUrl": "https://bsky.app/profile/sam-writes.bsky.social/post/3mwst2vdkgc2b",
"cid": "bafyreigkx65iafsp4wxivkccboe5vomqlta6khublouehpr6qzjckdvpc4",
"text": "Good overview of where AI chips are heading this year www.theverge.com/tech/...",
"createdAt": "2026-10-01T12:07:15.907Z",
"indexedAt": "2026-10-01T12:07:18.761Z",
"authorDid": "did:plc:exampleauthor000000000000",
"authorHandle": "sam-writes.bsky.social",
"authorDisplayName": "Sam Writes",
"likeCount": 3,
"repostCount": 1,
"replyCount": 0,
"quoteCount": 0,
"languages": ["en"],
"hashtags": [],
"mentions": [],
"links": [],
"mediaUrls": ["https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:exampleauthor000000000000/bafkreihc4xslm66qsulrmzoks7s3i7a754o4tnxplgasilzwmplzizjday"],
"embedType": "external",
"isReply": false,
"isRepost": false,
"sourceType": "search",
"sourceQuery": "AI",
"provider": "bluesky-appview",
"scrapedAt": "2026-10-01T12:11:16.133Z"
}

Each run also writes OUTPUT and RUN_SUMMARY records to the default key-value store with the run outcome and totals.

Pricing

This Actor uses Pay per event plus Apify platform usage. Each unique post saved is one Public Bluesky post scraped event, and each run has one Actor Start event plus the platform usage of the run. Duplicates across queries, feeds and threads are merged before saving, so each post counts once. For example, a daily search capped at 200 posts is up to 200 post events plus the start event and usage. maxResults doubles as a spending limit. The live Pricing tab on this page shows the current event prices.

API example

curl -X POST "https://api.apify.com/v2/acts/khadinakbar~bluesky-posts-scraper/run-sync-get-dataset-items?token=YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"queries": ["open source AI"], "sort": "latest", "maxResults": 100}'
from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("khadinakbar/bluesky-posts-scraper").call(run_input={"handles": ["bsky.app"], "maxResults": 50})
for post in client.dataset(run["defaultDatasetId"]).iterate_items():
print(post["createdAt"], post["likeCount"], post["text"][:80])

Use with AI agents (MCP)

Connect the Actor to Claude, ChatGPT or Cursor through Apify MCP and ask:

Search Bluesky for the latest 50 English posts about open-source AI, then summarize the recurring complaints and cite each post by its URL.

The agent sets queries, language and maxResults, reads rows with get-dataset-items, and cites postUrl or postUri. It can check OUTPUT.outcome to tell a quiet topic from a full result set, and each unique post is one event, so maxResults keeps the cost of the request predictable.

Best results

Starting situationHelpful actionExpected outcome
Brand monitoringSearch the brand with sort set to latest and schedule itNew mentions each run
Signal over noiseSet minLikes or minRepostsPosts that drew engagement
Link trackingUse domain or exactUrlPosts sharing your site or article
A creator's outputUse handles with posts_no_repliesTheir original posts only
A full discussionUse postUrls with includeThreadReplies and a higher threadDepthThe post and its reply tree
Joining datasetsKey on postUri and authorDidStable joins across runs

Builder's note

I built one Actor for search, feeds and threads because Bluesky research usually moves between all three, and a single row shape keeps the analysis simple. I chose the AT URI and DID as the identity of every row since handles on Bluesky can change while those stay fixed, and I kept the source query on each post so every row can be traced back to why it was collected.

FAQ

Do I need a Bluesky account?

No. The Actor reads public Bluesky data with no login or app password.

Are engagement counts live?

They are the counts at collection time. Re-run the same input to refresh them.

How are duplicates handled?

Posts are merged by postUri across every query, feed and thread in a run, and each is saved once.

Responsible use

This Actor collects public Bluesky posts. Posts include handles and display names, which are personal data under laws such as the GDPR and CCPA, so process them with a lawful basis, respect Bluesky's terms, and use the data for research and monitoring rather than profiling individuals. Bluesky is a trademark of its owner; this independent Actor is not affiliated with or endorsed by Bluesky Social PBC.