Social media
Bluesky Scraper — Feed Posts
Export posts from any public Bluesky custom or algorithm feed via the AT Protocol API — feed metadata and engagement counts — to JSON or CSV. No login needed; we page through and retry so the whole feed lands.
Free Apify credit covers a first run. No credit card to try.
What this Actor scrapes
Two operating modes, controlled by which input field you set:
1. Single-feed mode — provide a feed URI (AT URI or bsky.app/profile/.../feed/... web URL) and the Actor exports every post in that feed up to the per-feed cap. 2. Creator-discovery mode — provide a creator's Bluesky handle (e.g. bsky.app) and the Actor calls app.bsky.feed.getActorFeeds to enumerate every feed that creator publishes, then scrapes each one in turn.
What we handle for you
- What we handle for you: fingerprint rotation (curl-cffi browser impersonation — Chrome / Firefox profiles), exponential back-off on
408 / 429 / 503withRetry-Afterhonoured, up to 5 retries per failed request, proxy routing via Apify Proxy on demand, and Pydantic v2-validated rows. You get the clean CSV; we get the error logs. - Two operating modes: single feed URI or discover-all-feeds-by-creator via
getActorFeeds. - Accepts either AT URIs (
at://did:plc:.../app.bsky.feed.generator/whats-hot) orbsky.appweb URLs — the Actor rewrites web URLs to AT URI form automatically. - Denormalised output — feed metadata (name, description, creator handle) on every post row, no joins needed for downstream analytics or CSV exports.
- Cursor-based pagination with a client-side per-feed cap so you only pay for what you need.
- Pure HTTP scraping with browser fingerprint impersonation — no browser automation overhead.
- Pydantic v2 input validation with XOR guard: exactly one of
feedUriorcreatorHandlemust be set. - Pairs with the companion
bluesky-starter-packActor as the Bluesky Intel Suite. - Pay only for results that land — no data written means no
result-rowcharges (only the smallactor-startwarm-up fee).
Use cases
- Algorithm research — sample what posts the "Discover" / "What's Hot" algorithmic feeds actually surface across days or weeks; analyse topic drift and amplification patterns.
- Newsroom monitoring — subscribe to curated topic feeds for breaking-news posts on specific beats, then pipe to Slack or a Google Sheet via Apify integrations.
- Marketing intelligence — see which posts are amplified by community feeds in your niche; measure which content formats dominate each feed's engagement distribution.
- Creator analytics — pull every post a niche feed generator surfaces and rank by like / repost / quote ratios to benchmark your own posts against feed peers.
- Dataset bootstrap — collect labelled training data from topic-curated feeds for downstream NLP or sentiment models without manual tagging of raw timelines.
- Competitive monitoring — track community-curated feeds that aggregate competitor announcements, support complaints, or product mentions.
- Academic social-media research — Bluesky's public AT Protocol data is significantly more research-accessible than the current Twitter / X API; this Actor is a low-cost entry point for longitudinal feed studies.
Input
Paste this into the Apify Console, or send it as the run input over the API. Proxy settings are on by default; you rarely need to touch them.
| Field | Type | Required | What it does |
|---|---|---|---|
feedUri | string | no | AT URI (at://did:plc:.../app.bsky.feed.generator/...) or Bluesky web URL (https://bsky.app/profile/handle/feed/rkey) of one feed generator. Mutually exclusive with Creator handle. |
creatorHandle | string | no | Bluesky handle (e.g. bsky.app) or DID of a feed creator. The Actor enumerates every feed published by that user via app.bsky.feed.getActorFeeds and scrapes each. Mutually exclusive with Feed URI. |
maxPostsPerFeed | integer | no | Maximum number of post rows emitted per feed. Acts as a client-side cap; pagination stops when this limit is reached. Default 100. |
maxFeeds | integer | no | Maximum number of feeds to process when using creator-discovery mode. Ignored in single-feed mode. Default 5. |
useProxy | boolean | no | Route requests through Apify Proxy (BUYPROXIES94952, a static US datacenter pack). The AT Protocol public API does not block datacenter IPs — leave disabled unless you are behind a restrictive ISP. |
{
"feedUri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot",
"maxPostsPerFeed": 100,
"useProxy": false
} Output
One row per result, schema-validated before it is written. Export JSON, CSV, Excel or XML from the run, or read it over the API.
feed_urifeed_display_namefeed_creator_handlefeed_descriptionpost_uripost_cidpost_indexed_atpost_textpost_langpost_reply_countpost_repost_countpost_like_countpost_quote_countauthor_didauthor_handleauthor_display_name
{
"feed_uri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot",
"feed_display_name": "Discover",
"feed_creator_handle": "bsky.app",
"feed_description": "Trending content from your personal network",
"post_uri": "at://did:plc:sj5wj7libgr7omqiotenxadx/app.bsky.feed.post/3mlxmr4jyfs2s",
"post_cid": "bafyreidgimgd7v3g3pazsp5oq7ur6bvedpnwohul26mss7cbffg6bdqjkm",
"post_indexed_at": "2026-05-16T10:20:40.467Z",
"post_text": "If you never read the book or saw the movie, you missed one of the greatest Pulitzer Prize winning sagas ever written.",
"post_lang": "en",
"post_reply_count": 89,
"post_repost_count": 414,
"post_like_count": 1288,
"post_quote_count": 27,
"author_did": "did:plc:sj5wj7libgr7omqiotenxadx",
"author_handle": "louiseplease.bsky.social",
"author_display_name": "Louise",
"scraped_at": "2026-05-16T12:00:00+00:00"
} Pricing
| Event | Price | When |
|---|---|---|
| Actor start | $0.20 | Once per run, covers warm-up and proxy session setup. |
| Post row emitted | $0.0020 | Per result written to the dataset. |
You pay only for results that land. Cap any run with maxTotalChargeUsd. See pricing & billing for worked examples.
Limitations
- Private or access-restricted feeds are not exposed by the public AppView API — only feeds whose data is visible at
public.api.bsky.appcan be scraped. - Global feed discovery by keyword is not supported — Bluesky's
getPopularFeedGeneratorsendpoint returnsMethodNotImplementedon the public AppView. Use creator-discovery mode (creatorHandle) to enumerate one creator's feeds at a time. - Post images, embeds, and quoted-post bodies are not extracted — only the plain-text body (
post_text) is captured. Image ALT text, external link cards, and quoted-post content are outside the current schema. - Reply thread expansion is out of scope — only the top-level post row is emitted. Threaded context (parent / root posts) would require additional
getPostThreadcalls and is not wired in this version. - The
maxPostsPerFeedcap is client-side — the Actor paginates until it has collected the cap or the API cursor is exhausted. If a feed has fewer posts than the cap, fewer rows are returned. This is expected behaviour, not a failure. - Storage retention on FREE Apify plans — run-scoped storage is retained for 7 days. Export your dataset immediately after the run or upgrade to a paid plan for longer retention.
- Rate limiting — the Actor retries on
429with exponential back-off and honoursRetry-After, but very large scrapes (tens of thousands of rows) may require splitting into multiple runs to stay within per-window limits. - AT Protocol is pre-1.0 — Bluesky's endpoint surface has changed without warning in the past. We monitor the AT Protocol Discord
#breaking-changeschannel and ship patches within days of validated breakage reports.
FAQ
Do I need a Bluesky account to use this Actor?
public.api.bsky.app/xrpc/ is unauthenticated by design — every endpoint this Actor calls is open without a login or API key. You run the Actor; we handle the protocol plumbing.What is a feed URI?
at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot. The segment after at:// is a DID — a decentralized identifier. The collection is always app.bsky.feed.generator. The final segment is the rkey that identifies the specific feed. You can also paste a bsky.app web URL — the Actor converts it automatically.How do I scrape all feeds published by a single creator?
creatorHandle input to the creator's Bluesky handle (e.g. bsky.app) and leave feedUri blank. The Actor calls app.bsky.feed.getActorFeeds and scrapes each feed in turn, up to the maxFeeds cap.Can I export Bluesky's built-in feeds like "Discover" or "What's Hot"?
bsky.app account. Use the feed URI at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot for "Discover" / "What's Hot", or paste the bsky.app/profile/bsky.app/feed/whats-hot URL. You can also use creator-discovery mode with creatorHandle: "bsky.app" to get all feeds that account publishes.Is this a good Twitter / X API alternative in 2026?
Is exporting public Bluesky feeds legal?
public.api.bsky.app is explicitly unauthenticated and publicly accessible. The Bluesky Terms of Service permit accessing public data programmatically as long as you do not impersonate users or violate AT Protocol data-portability principles. Always verify the current Terms of Service at bsky.social/about/support/tos and your local jurisdiction's data-protection rules before using scraped data commercially.How do I export to Google Sheets?
=IMPORTDATA("...") in Sheets.What happens if a feed is empty or the URI is wrong?
"No posts emitted — feed may be empty, private, or the URI invalid." The dataset will have zero rows and the actor-start fee is the only charge.Ready to run it?
Open the listing on Apify, paste the input above, and watch rows land. If it ever breaks, it is our problem before it is yours.
Related Actors