Bluesky Post Detail Scraper avatar

Bluesky Post Detail Scraper

Pricing

from $1.00 / 1,000 results

Go to Apify Store
Bluesky Post Detail Scraper

Bluesky Post Detail Scraper

Fetch a Bluesky post with its thread (replies + parents) by AT URI or web URL. HTTP-only, no login required.

Pricing

from $1.00 / 1,000 results

Rating

0.0

(0)

Developer

Farhan Febrian Nauval

Farhan Febrian Nauval

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

Share

Extract a single Bluesky post together with its full conversation — author, text, media, counters, the parent chain, and the nested reply tree — in one clean structured JSON record.

Why use this actor

  • No account / no login required — paste a public bsky.app URL and run.
  • No API key needed — get the same data the Bluesky web app shows, in JSON.
  • Whole conversation in one call — parent chain plus the nested reply tree are returned together, no manual stitching.
  • Flexible input — accepts https://bsky.app/profile/<handle>/post/<rkey> URLs, at://... identifiers, or <handle>/<rkey> shorthand; handles are resolved to stable IDs for you.
  • Configurable depth — control how deep the reply tree goes and how many parents above the post you want to capture.
  • Stable JSON output suitable for pipelines, spreadsheets, and databases — every row carries _input, _source, _scrapedAt envelope fields so you can join results back to your input list.

How it works

  1. You provide a list of Bluesky posts (URL, AT URI, or <handle>/<rkey>).
  2. The actor fetches the post and walks the conversation up (parents) and down (replies) to the depth you set.
  3. Each post in the thread arrives with author info, full text, media references, and engagement counters.
  4. Results stream into your dataset, ready to download as JSON, CSV, or Excel.

You do not need to manage scrapers, browsers, or rotating IPs — all handled internally.

Input

{
"posts": [
"https://bsky.app/profile/bsky.app/post/3mlvllqtnmk2g",
"at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3mlr7prm6g22c"
],
"depth": 10,
"parentHeight": 80,
"proxyConfiguration": {
"useApifyProxy": true,
"apifyProxyGroups": ["DATACENTER"]
}
}
FieldTypeDescription
postsarrayList of Bluesky posts. Each entry can be a bsky.app URL, an at://... URI, or a <handle>/<rkey> shorthand. Handles are auto-resolved.
depthintegerHow many levels deep to follow the reply tree (0–1000). Default 10.
parentHeightintegerHow many parent posts above the target to include (0–1000). Default 80.
proxyConfigurationobjectApify Proxy settings. Datacenter proxy works for most cases.

Output

Input: at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3mlvllqtnmk2g

{
"_input": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3mlvllqtnmk2g",
"_uri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3mlvllqtnmk2g",
"_source": "S1-xrpc",
"_scrapedAt": "2026-05-18T10:35:57.147239+00:00",
"thread": {
"$type": "app.bsky.feed.defs#threadViewPost",
"post": {
"uri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3mlvllqtnmk2g",
"cid": "bafyreidkkomfz72otqfbyj4y2zjetrn456hko6pxzj3yhozyoxfx3s6eyy",
"author": {
"did": "did:plc:z72i7hdynmk6r22z27h6tvur",
"handle": "bsky.app",
"displayName": "Bluesky",
"avatar": "https://cdn.bsky.app/img/avatar/plain/did:plc:z72i7hdynmk6r22z27h6tvur/bafkreihwihm6kpd6zuwhhlro75p5qks5qtrcu55jp3gddbfjsieiv7wuka",
"createdAt": "2023-04-12T04:53:57.057Z",
"verification": {
"verifications": [],
"verifiedStatus": "none",
"trustedVerifierStatus": "valid"
},
"labels": []
},
"record": {
"$type": "app.bsky.feed.post",
"createdAt": "2026-05-15T14:54:22.994Z",
"langs": ["en"],
"text": "THE INTERNET FOR $600: This social media app now boasts at least 200 \"Jeopardy!\" contestants and champions (including one host).",
"embed": {
"$type": "app.bsky.embed.record",
"record": {
"cid": "bafyreida3vtrwyjlngev73bmkjmxzi2ccstksiuvirkjhf55larupdvkaa",
"uri": "at://did:plc:qrllvid7s54k4hnwtqxwetrf/app.bsky.feed.post/3kzwdmzvnf223"
}
}
},
"replyCount": 71,
"repostCount": 141,
"likeCount": 1920,
"quoteCount": 28,
"bookmarkCount": 39,
"indexedAt": "2026-05-15T14:54:23.265Z",
"labels": []
},
"replies": [
{
"$type": "app.bsky.feed.defs#threadViewPost",
"post": {
"uri": "at://did:plc:.../app.bsky.feed.post/...",
"author": {
"handle": "solidstalemate.bsky.social",
"displayName": "Solid Stalemate",
"did": "did:plc:..."
},
"record": {
"text": "What is \"MySpace\"?",
"createdAt": "2026-05-15T18:38:09.987Z",
"langs": ["en"]
},
"replyCount": 0,
"repostCount": 0,
"likeCount": 1,
"quoteCount": 0,
"indexedAt": "2026-05-15T18:38:10.568Z"
}
},
{
"$type": "app.bsky.feed.defs#threadViewPost",
"post": {
"author": { "handle": "halfpintptbo.bsky.social" },
"record": {
"text": "We r an app of intelligent people unlike that other place full of idiot magats. Congrats to all!!",
"createdAt": "2026-05-17T16:09:24.812Z"
},
"likeCount": 1,
"replyCount": 0,
"indexedAt": "2026-05-17T16:09:25.168Z"
}
},
"... 66 more"
]
},
"threadgate": {
"uri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.threadgate/3mlvllqtnmk2g",
"cid": "bafyreibv64kb2qju5y7khjnvg4d2x2kwdgpdvhted2yhcgh3cxa5lzc7ty",
"record": {
"$type": "app.bsky.feed.threadgate",
"createdAt": "2026-05-15T15:48:09.490Z",
"hiddenReplies": [
"at://did:plc:3r2ydi2f75r2hct527i637l5/app.bsky.feed.post/3mlvlot3nzc2i",
"... 4 more"
],
"post": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3mlvllqtnmk2g"
},
"lists": []
}
}

Envelope fields

FieldTypeDescription
_inputstringThe post identifier exactly as you supplied it. Use this to join results back to your input list.
_uristringThe canonical at:// URI of the post (with the handle resolved to a stable DID).
_sourcestringInternal tag for the path used to fetch the record. S1-xrpc means the primary path was used; values starting with S2- indicate a fallback was used.
_scrapedAtstringISO-8601 UTC timestamp when the record was scraped.
_errorstringPresent only on failure. One of not_found, resolve_failed, invalid_request.
_errorDetailstringPresent only on failure. Human-readable detail explaining the error.

thread — the post and its conversation

FieldTypeDescription
thread.postobjectThe target post itself (see fields below).
thread.parentobjectPresent if parentHeight > 0 and the post is a reply. Same shape as thread, recurses upward.
thread.repliesarrayNested reply tree. Each entry has the same shape as thread (post + optional replies). Empty if the post has no replies or depth = 0.
thread.$typestringBluesky's record type. app.bsky.feed.defs#threadViewPost for a regular post, #notFoundPost or #blockedPost for hidden replies.

thread.post — the post record

FieldTypeDescription
uristringThe post's at:// URI. Stable across handle changes.
cidstringContent-addressed ID of this revision of the record.
authorobjectAuthor profile: did, handle, displayName, avatar, createdAt, verification, labels.
record.textstringThe post body text (plain UTF-8, may contain emojis).
record.createdAtstringISO-8601 timestamp the author published the post.
record.langsarrayLanguage tags the author declared (e.g. ["en"]).
record.embedobjectAttached media — quoted post, images, video, or external link card. $type indicates which.
record.replyobjectPresent if the post is itself a reply. Contains parent.uri and root.uri.
record.facetsarrayInline mentions, hashtags, and links with byte offsets.
embedobjectThe same embed, fully resolved (the quoted post is expanded, image URLs are populated).
replyCountintegerDirect reply count.
repostCountintegerNumber of reposts.
likeCountintegerNumber of likes.
quoteCountintegerNumber of quote posts.
bookmarkCountintegerNumber of bookmarks.
indexedAtstringISO-8601 timestamp the post was indexed by the AppView.
labelsarrayModeration labels applied to the post.
threadgateobjectAuthor's reply restrictions, if any.

threadgate — author's reply policy (top level)

FieldTypeDescription
record.allowarrayWho is allowed to reply (e.g. mentioned users, followers). Absent = anyone.
record.hiddenRepliesarrayURIs of replies the author chose to hide from the default view.
listsarrayLists referenced by the threadgate (for list-scoped reply permissions).

Error envelope

Posts that don't exist, are deleted, or fail to resolve return a structured error instead of crashing the run:

{
"_input": "https://bsky.app/profile/bsky.app/post/does-not-exist",
"_uri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/does-not-exist",
"_source": "S1-xrpc",
"_scrapedAt": "2026-05-18T10:36:02.487122+00:00",
"_error": "not_found",
"_errorDetail": "NotFound app.bsky.feed.getPostThread {'uri': 'at://...'}"
}

Filter on _error to triage failed rows.

Pricing

This actor is billed per result: $1.50 per 1,000 results. Each successfully scraped post (with its full thread) counts as one result. Errors (not_found, resolve_failed) are not billed.

Other Sosmed Actors

PlatformActorBest for
BlueskyBluesky Account ScraperProfile, followers, bio for any handle
BlueskyBluesky Account Posts ScraperPaginate every post by an author
BlueskyBluesky Search ScraperKeyword search across Bluesky posts
ThreadsThreads Post Detail ScraperSingle Threads post + reply tree
Twitter / XX Post Detail ScraperSingle tweet + conversation context
MastodonMastodon Status Detail ScraperSingle Mastodon status + replies
RedditReddit Post Detail ScraperReddit post + nested comments
InstagramInstagram Post Detail ScraperSingle Instagram post + comments

Browse the full catalog at apify.com/xtracto.

Notes

  • Counters (likeCount, repostCount, replyCount, quoteCount, bookmarkCount) are eventually-consistent and may lag the live network by a few minutes.
  • Default depth is 10 levels of replies and parentHeight is 80 — generous for most analytics needs but lower them for performance on very large threads.
  • Replies from blocked or labeled accounts may surface as $type: app.bsky.feed.defs#blockedPost or #notFoundPost entries inside thread.replies — keep this in mind when counting visible replies.
  • Deleted or never-existed posts return {"_error": "not_found", "_input": "..."} so downstream pipelines can branch on missing data.
  • The at:// URI in _uri is the most reliable identifier — handles can change but the DID inside the URI does not.
  • For very large threads (>5,000 replies) you may hit practical depth limits; for those, paginate replies via the Bluesky Account Posts Scraper against the original author.