Bluesky Post Detail Scraper
Pricing
from $1.00 / 1,000 results
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
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
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,_scrapedAtenvelope fields so you can join results back to your input list.
How it works
- You provide a list of Bluesky posts (URL, AT URI, or
<handle>/<rkey>). - The actor fetches the post and walks the conversation up (parents) and down (replies) to the depth you set.
- Each post in the thread arrives with author info, full text, media references, and engagement counters.
- 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"]}}
| Field | Type | Description |
|---|---|---|
posts | array | List of Bluesky posts. Each entry can be a bsky.app URL, an at://... URI, or a <handle>/<rkey> shorthand. Handles are auto-resolved. |
depth | integer | How many levels deep to follow the reply tree (0–1000). Default 10. |
parentHeight | integer | How many parent posts above the target to include (0–1000). Default 80. |
proxyConfiguration | object | Apify 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
| Field | Type | Description |
|---|---|---|
_input | string | The post identifier exactly as you supplied it. Use this to join results back to your input list. |
_uri | string | The canonical at:// URI of the post (with the handle resolved to a stable DID). |
_source | string | Internal 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. |
_scrapedAt | string | ISO-8601 UTC timestamp when the record was scraped. |
_error | string | Present only on failure. One of not_found, resolve_failed, invalid_request. |
_errorDetail | string | Present only on failure. Human-readable detail explaining the error. |
thread — the post and its conversation
| Field | Type | Description |
|---|---|---|
thread.post | object | The target post itself (see fields below). |
thread.parent | object | Present if parentHeight > 0 and the post is a reply. Same shape as thread, recurses upward. |
thread.replies | array | Nested reply tree. Each entry has the same shape as thread (post + optional replies). Empty if the post has no replies or depth = 0. |
thread.$type | string | Bluesky's record type. app.bsky.feed.defs#threadViewPost for a regular post, #notFoundPost or #blockedPost for hidden replies. |
thread.post — the post record
| Field | Type | Description |
|---|---|---|
uri | string | The post's at:// URI. Stable across handle changes. |
cid | string | Content-addressed ID of this revision of the record. |
author | object | Author profile: did, handle, displayName, avatar, createdAt, verification, labels. |
record.text | string | The post body text (plain UTF-8, may contain emojis). |
record.createdAt | string | ISO-8601 timestamp the author published the post. |
record.langs | array | Language tags the author declared (e.g. ["en"]). |
record.embed | object | Attached media — quoted post, images, video, or external link card. $type indicates which. |
record.reply | object | Present if the post is itself a reply. Contains parent.uri and root.uri. |
record.facets | array | Inline mentions, hashtags, and links with byte offsets. |
embed | object | The same embed, fully resolved (the quoted post is expanded, image URLs are populated). |
replyCount | integer | Direct reply count. |
repostCount | integer | Number of reposts. |
likeCount | integer | Number of likes. |
quoteCount | integer | Number of quote posts. |
bookmarkCount | integer | Number of bookmarks. |
indexedAt | string | ISO-8601 timestamp the post was indexed by the AppView. |
labels | array | Moderation labels applied to the post. |
threadgate | object | Author's reply restrictions, if any. |
threadgate — author's reply policy (top level)
| Field | Type | Description |
|---|---|---|
record.allow | array | Who is allowed to reply (e.g. mentioned users, followers). Absent = anyone. |
record.hiddenReplies | array | URIs of replies the author chose to hide from the default view. |
lists | array | Lists 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
| Platform | Actor | Best for |
|---|---|---|
| Bluesky | Bluesky Account Scraper | Profile, followers, bio for any handle |
| Bluesky | Bluesky Account Posts Scraper | Paginate every post by an author |
| Bluesky | Bluesky Search Scraper | Keyword search across Bluesky posts |
| Threads | Threads Post Detail Scraper | Single Threads post + reply tree |
| Twitter / X | X Post Detail Scraper | Single tweet + conversation context |
| Mastodon | Mastodon Status Detail Scraper | Single Mastodon status + replies |
| Reddit Post Detail Scraper | Reddit post + nested comments | |
| Instagram Post Detail Scraper | Single 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
depthis 10 levels of replies andparentHeightis 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#blockedPostor#notFoundPostentries insidethread.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_uriis 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.