# Bluesky Scraper: Profiles, Posts, Followers & Threads (`alexburton/bluesky-scraper`) Actor

Scrape Bluesky profiles, author feeds, followers, follows, threads, likes, custom feeds and account search through the official AT Protocol API. No login needed for anything except post search.

- **URL**: https://apify.com/alexburton/bluesky-scraper.md
- **Developed by:** [Alex Burton](https://apify.com/alexburton) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 posts

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Bluesky Scraper: Profiles, Posts, Followers & Threads

Collect Bluesky data through the **official AT Protocol API** — not by scraping web pages. No API key, and no login for eight of the nine jobs.

| Mode | What you get |
|---|---|
| **Profiles** | Handle, display name, bio, follower and following counts, post count, join date, verification status |
| **Account's posts** | Every post with full text, like/repost/reply/quote counts, images, links and quoted posts |
| **Followers** | The full follower list of an account, as profile rows |
| **Following** | Everyone an account follows |
| **Account search** | Accounts matching a query |
| **Thread with replies** | A root post plus its reply tree, flattened with a depth number on every row |
| **Who liked a post** | Every account that liked a given post |
| **Custom feed** | Any feed generator's output by its `at://` URI |
| **Post search** | Full-text post search — the one mode Bluesky requires a login for |

### Why use this one

- **Official API, so it does not silently break.** Bluesky publishes the AT Protocol XRPC endpoints and keeps them stable. Scrapers that parse bsky.app HTML break whenever the site is restyled.
- **No login for almost everything.** Profiles, feeds, followers, threads, likes and account search need no credentials at all.
- **Nine jobs in one Actor.** One subscription, one output format, instead of stitching together several single-purpose tools.
- **Real pagination.** Follower lists and busy feeds are walked with the API's own cursor until your limit is reached, so you get 10,000 followers if you ask for them.
- **Flat output.** One row per post, profile or like — ready for Excel, a database or an AI pipeline, with no nested JSON to unpick.

### How to use it

1. Choose **What to scrape**.
2. Fill in the matching field: **Accounts**, **Posts**, **Search terms** or **Custom feeds**.
3. Set your per-account or per-search limit.
4. Click **Start**, then download results as JSON, CSV, Excel or HTML, or fetch them through the Apify API.

Accounts are accepted in any of these forms:

```
alice.bsky.social
@alice.bsky.social
did:plc:z72i7hdynmk6r22z27h6tvur
https://bsky.app/profile/alice.bsky.social
```

Posts are accepted as either:

```
https://bsky.app/profile/alice.bsky.social/post/3mxuhaky3rc23
at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3mxuhaky3rc23
```

#### Example input: an account's recent posts

```json
{
  "mode": "authorFeed",
  "actors": ["bsky.app"],
  "feedFilter": "posts_no_replies",
  "maxItemsPerAccount": 500
}
```

#### Example input: a full follower list

```json
{
  "mode": "followers",
  "actors": ["alice.bsky.social"],
  "maxItemsPerAccount": 10000
}
```

### Output

Each item carries a `type` field: `post`, `profile` or `like`. The dataset ships with **Posts**, **Profiles** and **Likes** table views.

**Post**

```json
{
  "type": "post",
  "uri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3mxuhaky3rc23",
  "url": "https://bsky.app/profile/bsky.app/post/3mxuhaky3rc23",
  "text": "A new version of the app is rolling out today.",
  "createdAt": "2026-10-16T20:09:31Z",
  "likeCount": 441,
  "repostCount": 61,
  "replyCount": 68,
  "quoteCount": 52,
  "authorHandle": "bsky.app",
  "authorDisplayName": "Bluesky",
  "isReply": false,
  "languages": ["en"],
  "imageUrls": []
}
```

**Profile**

```json
{
  "type": "profile",
  "did": "did:plc:z72i7hdynmk6r22z27h6tvur",
  "handle": "bsky.app",
  "displayName": "Bluesky",
  "description": "Official account.",
  "followersCount": 1234567,
  "followsCount": 42,
  "postsCount": 980,
  "createdAt": "2023-04-12T04:53:57Z",
  "url": "https://bsky.app/profile/bsky.app"
}
```

### Pricing

Pay only for results:

| Result | Price |
|---|---|
| Post | $2.00 per 1,000 |
| Profile (incl. followers and following) | $4.00 per 1,000 |
| Like | $1.00 per 1,000 |

Set a maximum spend per run in the run options and the Actor stops cleanly when it's reached.

### Limits to know about

- **Post search needs a login.** Bluesky answers `app.bsky.feed.searchPosts` with **403** for anonymous callers, so that mode asks for your handle and an **app password**. Create one at *Settings → Privacy and security → App passwords* — never use your real account password. An app password can be revoked at any time and cannot change your account settings. Every other mode ignores these fields.
- **Only public data.** The API returns what a logged-out visitor can see. Posts from accounts that have opted out of public visibility, and anything behind a block, are not returned.
- **Threads are capped** at 2,000 posts per root post to keep runs predictable. Very large reply trees are truncated.
- **Follower order** is Bluesky's own and is not strictly chronological.
- **Follower, following, like and account-search rows are Bluesky's short profile**: handle, display name, bio, avatar and join date. Bluesky's list endpoints leave out follower and post counts, so those fields are null there; run **Profiles** on the accounts you care about to get them.
- The public AppView rate-limits heavy use. If the log shows repeated retries, lower *Max parallel requests*.

### FAQ

**Do I need a Bluesky account?** Not for profiles, feeds, followers, threads, likes or account search. Only post search does.

**Is the app password safe to give?** Apify stores secret inputs encrypted, and the Actor only uses it to mint a short-lived session token for the search request. It is never written to the dataset or the log. You can revoke it in Bluesky's settings whenever you like.

**Can I monitor an account daily?** Yes. Use *Account's posts*, set a schedule in Apify Console, and connect the dataset to Slack, Google Sheets, Zapier or Make.

**Why did a custom feed return nothing?** The feed `at://` URI was wrong or the generator is offline. Open the feed on bsky.app and copy its URI again.

**Is this allowed?** The Actor uses Bluesky's documented public API and reads only public data. Profiles and posts contain personal data, so handle the output in line with GDPR and any other law that applies to you.

### Feedback

Found a bug or need a field that's missing? Open an issue on the Actor's **Issues** tab.

# Actor input Schema

## `mode` (type: `string`):

Pick one job. Everything except Post search works without a login.

## `actors` (type: `array`):

For Profiles, Account's posts, Followers and Following. Use a handle (alice.bsky.social), a DID (did:plc:…) or a profile link (https://bsky.app/profile/alice.bsky.social).

## `posts` (type: `array`):

For Thread with replies and Who liked a post. Use a post link (https://bsky.app/profile/alice.bsky.social/post/3abc…) or an at:// URI.

## `searchTerms` (type: `array`):

For Account search and Post search. One query per line.

## `feeds` (type: `array`):

For Custom feed. Paste the feed's at:// URI, for example at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot.

## `feedFilter` (type: `string`):

Filter applied to Account's posts.

## `threadDepth` (type: `integer`):

How many reply levels to walk below the root post.

## `postSearchSort` (type: `string`):

Only used by Post search.

## `maxItemsPerAccount` (type: `integer`):

Caps posts per account, followers per account and likes per post.

## `maxItemsPerSearch` (type: `integer`):

Caps results for Account search, Post search and Custom feed.

## `blueskyHandle` (type: `string`):

Only needed for Post search, which Bluesky closed to anonymous callers. Example: alice.bsky.social

## `blueskyAppPassword` (type: `string`):

Create one at Bluesky Settings > Privacy and security > App passwords. Never use your real account password. Stored encrypted by Apify and only used to mint a short-lived search session.

## `maxItems` (type: `integer`):

Stop the run after saving this many items. Leave empty for no limit.

## `maxConcurrency` (type: `integer`):

Lower this if you see rate-limit retries in the log.

## `proxyConfiguration` (type: `object`):

Not needed for most runs. Turn on Apify Proxy only for very large jobs.

## Actor input object example

```json
{
  "mode": "profiles",
  "actors": [
    "bsky.app"
  ],
  "feedFilter": "posts_with_replies",
  "threadDepth": 6,
  "postSearchSort": "latest",
  "maxItemsPerAccount": 100,
  "maxItemsPerSearch": 100,
  "maxConcurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "actors": [
        "bsky.app"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("alexburton/bluesky-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "actors": ["bsky.app"] }

# Run the Actor and wait for it to finish
run = client.actor("alexburton/bluesky-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "actors": [
    "bsky.app"
  ]
}' |
apify call alexburton/bluesky-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,alexburton/bluesky-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/FSca6Hg7abmGxgtJ6/builds/bEDZ4Csr88V4KFPKs/openapi.json
