Bluesky Scraper — Posts, Profiles & Search avatar

Bluesky Scraper — Posts, Profiles & Search

Pricing

$1.00 / 1,000 results

Go to Apify Store
Bluesky Scraper — Posts, Profiles & Search

Bluesky Scraper — Posts, Profiles & Search

Scrape Bluesky without a login: posts, profiles, threads, hashtags and full-text search over the decentralized AT Protocol. Built for social listening and research. Multiple relays with deduplication, incremental mode returns only new posts. Empty runs cost nothing.

Pricing

$1.00 / 1,000 results

Rating

0.0

(0)

Developer

Radosław Szal

Radosław Szal

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

11 hours ago

Last modified

Share

Bluesky Scraper — Posts, Profiles, Hashtags & Search (AT Protocol)

🔗 Part of the Apify actors collection — actors that chain: scrape → clean → use.

Scrape Bluesky without a login: posts, profiles, threads, hashtags, follower graphs and full-text search, exported as clean JSON, CSV or Excel. Built directly on the public AT Protocol — the decentralized protocol Bluesky itself runs on — so there is no browser, no proxy and no fragile HTML parsing to break when the site changes.

Built for social listening, brand monitoring and research. $0.001 per record — $1.00 per 1 000, and an empty run costs nothing.


What you get back, and how fast

Every record is flat and typed — engagement counts, hashtags, mentions, links and media pulled up to top-level fields, with a real clickable https://bsky.app/... URL. Post records carry

uri, url, cid, text, createdAt, indexedAt, langs, author{did,handle,displayName,avatar}, likeCount, repostCount, replyCount, quoteCount, hashtags, mentions, links, media[{url,alt,type}], quotedPost, isReply, isRepost, labels
. Profile records carry
did, handle, url, displayName, description, avatar, banner, followersCount, followsCount, postsCount, createdAt, labels
.

A typical run finishes in about 6 seconds (25 records, measured), against Apify's 5-minute limit for automated checks. There is no browser and no proxy in the path — this reads the AT Protocol directly — which is why it is both fast and cheap to run.

Full samples are in Output below.

What can this Bluesky scraper do?

Seven jobs in one Actor. Pick a mode:

ModeWhat it doesLogin?
author_postsEvery post from one or more accounts, with reply and media filtersNo
search_postsFull-text keyword search across Bluesky — date, language, author and hashtag filtersApp password
profilesFull profile details for given accountsNo
search_profilesFind accounts by keywordNo
post_threadThe complete reply tree under a postNo
followersAn account's followersNo
followsWho an account followsNo

Only keyword post search needs an app password — Bluesky does not serve that one endpoint anonymously. Everything else runs on the public AppView out of the box.

Why use this one rather than another Bluesky scraper?

  • Image alt-text. media[].alt carries the author's own description of each image. Most scrapers drop it; it is the single most useful field for AI, search and accessibility work.
  • The quoted post, in full. When a post quotes another, you get the quoted text, author and URL — not just an opaque reference.
  • handleResolved. You can tell a verified handle from an unresolved one (handle.invalid), and you get a working profile URL either way.
  • A flat, stable schema — engagement counts, hashtags, mentions, links and media pulled up to top-level fields, and a real clickable https://bsky.app/... URL on every post. Not a raw API dump.
  • Incremental monitoring built in. Set onlyNew and a scheduled run returns only what it has not seen before — so a daily brand-alert costs you the new posts, not the same ones again.
  • It fails loudly. A run that fetches data and delivers nothing does not report success. See What happens when something fails?

How do I use it?

Get an account's latest posts (no login):

{ "mode": "author_posts", "handles": ["nytimes.com", "bsky.app"], "maxItems": 100 }

Search posts by keyword (needs an app password):

{
"mode": "search_posts",
"searchQuery": "electric vehicles",
"lang": "en",
"since": "2026-07-01",
"sort": "latest",
"maxItems": 500,
"blueskyIdentifier": "you.bsky.social",
"blueskyAppPassword": "<your-app-password>"
}

Monitor mentions of your brand — schedule it hourly and pay only for new posts:

{
"mode": "search_posts",
"searchQuery": "\"YourBrand\"",
"onlyNew": true,
"stateLabel": "yourbrand-mentions",
"blueskyIdentifier": "you.bsky.social",
"blueskyAppPassword": "<your-app-password>"
}

Get the full thread under a post (no login):

{ "mode": "post_thread", "postUrls": ["https://bsky.app/profile/bsky.app/post/3l..."], "threadDepth": 6 }

How do I scrape a Bluesky hashtag?

Two ways, depending on what you want:

{ "mode": "search_posts", "hashtags": ["climate"], "since": "2026-07-01",
"blueskyIdentifier": "you.bsky.social", "blueskyAppPassword": "<your-app-password>" }

That searches all of Bluesky for the tag. If instead you want a specific account's tagged posts, use author_posts and filter on the hashtags field in the output — every post record carries its hashtags as a top-level array.

How do I narrow what I get back — and pay less?

Billing is per delivered record, so every filter below is also a discount.

InputWhat it does
maxItemsHard stop on records delivered. The cheapest way to try the Actor.
authorFeedFilterWhich slice of an author's feed: posts_and_author_threads keeps their posts and own threads, posts_no_replies drops replies to other people, posts_with_media keeps only posts with images or video.
since / untilISO date bounds. Use both to pull a fixed window — one calendar month — rather than "everything newer than X".
fromAuthorIn search_posts, restricts the search to one author. "What did this account say about Y" in a single run instead of two.
langRestricts search to one language.
onlyNew + stateLabelReturns only records not seen in previous runs under the same key. Turns any scrape into a monitor.

How do I get a Bluesky app password?

  1. Open Bluesky → Settings → Privacy and Security → App Passwords.
  2. Add App Password, name it (e.g. "Apify"), copy the value (format xxxx-xxxx-xxxx-xxxx).
  3. Paste your handle into Bluesky handle and the value into Bluesky app password.

An app password is revocable and scoped — it is not your main password. It is sent only to Bluesky's own createSession endpoint to sign in, and is never written to the dataset or the logs.

⬆️ Output — what you get back

📝 Posts (author_posts, search_posts, post_thread)

{
"uri": "at://did:plc:.../app.bsky.feed.post/3l...",
"url": "https://bsky.app/profile/handle/post/3l...",
"cid": "bafy...",
"text": "the post text",
"createdAt": "2026-07-20T10:00:00.000Z",
"indexedAt": "2026-07-20T10:00:01.000Z",
"langs": ["en"],
"author": {
"did": "did:plc:...", "handle": "handle", "handleResolved": true,
"displayName": "Name", "avatar": "https://..."
},
"likeCount": 6512, "repostCount": 539, "replyCount": 88, "quoteCount": 12, "bookmarkCount": 4,
"hashtags": ["climate"], "mentions": ["did:plc:..."], "links": ["https://..."],
"embedType": "images",
"media": [{ "url": "https://...", "alt": "a solar farm at sunset", "type": "image" }],
"quotedPost": {
"uri": "at://...", "url": "https://bsky.app/profile/.../post/...",
"author": "quoted.handle", "text": "the quoted post"
},
"external": null,
"isReply": false, "isRepost": false, "replyParent": null, "replyRoot": null,
"labels": []
}

👤 Profiles (profiles, search_profiles, followers, follows)

{
"did": "did:plc:...", "handle": "handle", "handleResolved": true,
"url": "https://bsky.app/profile/handle",
"displayName": "Name", "description": "bio text",
"avatar": "https://...", "banner": "https://...",
"followersCount": 12043, "followsCount": 311, "postsCount": 2894,
"createdAt": "2023-05-01T09:12:00.000Z", "indexedAt": "2026-07-20T10:00:01.000Z",
"labels": []
}

Download from the run's Dataset tab as JSON, CSV or Excel, or pull it through the Apify API.

What happens when something fails?

Failures are never written into your dataset as records, and you are never charged for one.

SituationWhat the Actor does
Bad or missing input for the chosen modeFails immediately with a message naming the problem.
App password rejectedFails with Authentication failed, and still bills only what was already delivered — a mid-run auth failure never re-delivers or double-charges next run.
One target account errors, others workContinues, delivers what worked, and counts the failure.
Data fetched but zero records deliveredThe run fails with the reason — every record dropped in normalisation, every target errored, or pagination hit a safety backstop. A broken run never reports success.
onlyNew finds nothing newSucceeds with zero records. That is a legitimate quiet poll, not a failure, and it costs nothing.
Pagination stops at a safety backstopReported as truncated — a partial result is never passed off as a complete one.
Billing calls keep failingDelivery stops rather than giving data away unpaid, and the run says how many records it delivered first.

The two rows that matter most are the fourth and the fifth. Distinguishing "nothing broke, there is simply nothing new" from "everything broke and you got nothing" is the difference between a monitor you can trust on a schedule and one you have to check by hand.

How much does it cost?

  • $0.001 per record delivered (result-item), flat — $1.00 per 1 000.
  • An empty run costs nothing. No record written, no charge.
  • Nothing is charged for compute time, pagination, retries or bandwidth. A slow run costs the same as a fast one.
  • To try it cheaply, set maxItems to 10. That is three cents.

What can I do with the data?

  • Social listening and brand monitoring on the fastest-growing X alternative — schedule search_posts with onlyNew and get only what is new since the last check.
  • Research datasets for AI and academia: public data, open protocol, alt-text included.
  • Topic and hashtag tracking as Bluesky adoption grows.
  • Community and lead research — find accounts around a topic, then profile them.
  • Clean it first: pipe the dataset straight into Dataset Deduplicator & Cleaner to merge duplicates across runs before analysis.

FAQ

Can I use it with the Apify API?

Yes. POST /v2/acts/eszetael_lab~bluesky-scraper/runs with your input as the JSON body, then read the run's dataset. Standard API, CLI and client libraries all work.

Can I use it through an MCP server?

Yes. It is exposed through Apify's Actors MCP server like any public Actor, so an AI agent can call it as a tool. It is also enabled for agentic payments — an agent can run and pay for it without a human in the loop.

Can I schedule it to run automatically?

Yes — use Apify Schedules, and set onlyNew: true with a stateLabel. Each run then returns only posts it has not seen before, so a daily monitor costs you the new posts rather than the whole feed again.

Do I need a proxy?

No. The AT Protocol AppView serves public data directly. There is no anti-bot layer to defeat, which is also why this Actor is cheap to run and does not break when a page layout changes.

Does it scrape private posts or DMs?

No. It reads only public data through the official public AppView. No private posts, no logged-in-only content, no fake accounts.

Reading public posts from an open protocol is broadly lawful, but profile and follower data is personal data under GDPR. You need your own lawful basis for processing it, and you are responsible for how you store and use what you export. This Actor gives you the data; it does not give you the basis.

Your feedback

Found a bug, or a case where a mode returns something odd? Open an issue on the Actor's Issues tab. Real failure reports are worth more to us than feature requests.

Three tools built to chain into each other — scrape, then clean, then use.

  • Dataset Deduplicator & Cleaner — pass this Actor's dataset ID straight in to merge duplicates across runs before analysis. Six times cheaper than a scraper, because it processes data you already paid to collect.
  • Python Web Scraper — when your target is an ordinary website rather than Bluesky, write your own Python page function and get exactly the fields you want, with no template to fight.

All three are on pay-per-result pricing, and an empty run costs nothing in every one of them.


Built on the AT Protocol (app.bsky.*). Keywords: bluesky scraper, bluesky api, at protocol scraper, scrape bluesky posts, bluesky profile scraper, bluesky hashtag, bluesky search, social listening, decentralized social, social media scraper, bluesky data export.