# Bluesky Scraper & API - Posts, Search, Profiles, Followers (`apeye/bluesky-scraper`) Actor

Scrape Bluesky through the official API: keyword post search, posts with like, repost and reply counts, profiles with follower totals, follower lists, user search and full threads. Clean JSON for social listening, influencer research and AI agents. No login needed except for post search.

- **URL**: https://apify.com/apeye/bluesky-scraper.md
- **Developed by:** [Pasquale Nirta](https://apify.com/apeye) (community)
- **Categories:** Social media, AI, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 results

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## Bluesky Scraper: posts, search, profiles, followers and threads

Collect public data from Bluesky through the official AT Protocol API. Give it a list of handles, search terms or post URLs and it returns clean JSON rows: posts with full engagement counts, profiles with follower and post totals, follower and following lists, user search results, or a complete reply thread.

Because it reads Bluesky's official API rather than scraping HTML, results are fast and stable. No login or cookies are needed for anything except keyword post search, which Bluesky itself gates behind login (a revocable app password of your own).

### What it does

| Operation | You provide | You get |
|---|---|---|
| Posts | handles or profile URLs | Each user's posts with likes, reposts, replies, quotes, images, link cards |
| Profiles | handles or profile URLs | Bio, follower count, following count, post count per user |
| Followers | handles | The accounts following each user |
| Following | handles | The accounts each user follows |
| Search users | keywords | Matching accounts with profile data |
| Search posts | keywords + your app password | Latest posts matching each keyword, with engagement counts |
| Thread | post URLs | The post and every reply beneath it, flattened |

Typical uses: social listening and brand monitoring, influencer research, audience analysis, tracking what a set of accounts posts over time (run it on a schedule and diff by post URI), and feeding Bluesky data to AI agents. The Actor works from Apify's MCP server, so agents in Claude, Cursor and similar tools can call it directly.

### Input

```json
{
    "operation": "posts",
    "targets": ["bsky.app", "https://bsky.app/profile/atproto.com"],
    "maxItemsPerTarget": 100,
    "includeReplies": false,
    "includeReposts": false
}
````

Targets are flexible: handles (`name.bsky.social`), custom-domain handles (`bsky.app`), DIDs, or profile URLs all work. For the thread operation, paste a post URL straight from your browser.

### Output

One row per item. Post rows:

```json
{
    "type": "post",
    "uri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3l6oveex3ii2l",
    "url": "https://bsky.app/profile/bsky.app/post/3l6oveex3ii2l",
    "handle": "bsky.app",
    "displayName": "Bluesky",
    "text": "…",
    "createdAt": "2026-07-01T18:04:12.000Z",
    "likeCount": 4120,
    "repostCount": 388,
    "replyCount": 214,
    "quoteCount": 77,
    "isReply": false,
    "images": ["https://cdn.bsky.app/img/feed_fullsize/..."],
    "externalLink": null,
    "source": "bsky.app"
}
```

User rows carry `handle`, `displayName`, `description`, `followersCount`, `followsCount`, `postsCount` and `avatar`.

Export as JSON, CSV, Excel or RSS, or read the dataset through the Apify API from your own code.

### Pricing

Pay per event: a small fee when a run starts, then a fee per row in your results. Duplicate items are filtered out before charging.

### Use from AI agents

This Actor works out of the box with AI agents through [Apify's MCP server](https://mcp.apify.com). Connect an agent (Claude, Cursor, or anything MCP-compatible) to Apify and it can call `apeye/bluesky-scraper` directly: ask "what has this account posted about pricing this month, and who are its most-followed followers?" and the agent picks the operations, runs them and reads the results. Row types and field names are kept flat and predictable so models can consume them without custom parsing.

### FAQ

**Is this legal?** Yes. The Actor reads the official, publicly documented AT Protocol API that serves Bluesky's own app. Only public data is collected, the same data anyone sees without logging in.

**How does post search work?** Bluesky requires login for post search (their rule, not ours), so the searchPosts operation takes your handle and an app password. App passwords are Bluesky's official mechanism for third-party tools: create one at Settings > App Passwords, revoke it any time, and it never grants access to your main password or account settings. The credential field is stored encrypted and used only to log in. Every other operation needs no credentials at all.

**How fresh is the data?** It's read live from the API at run time. Engagement counts are the values at the moment of the run.

**What about rate limits?** The Actor paces itself within Bluesky's public API limits and retries transient errors automatically.

### Support

If something breaks or you need another operation (lists, likes of a post, feeds), open an issue on the Issues tab. I check most days and usually reply within a day or two.

# Actor input Schema

## `operation` (type: `string`):

The kind of data to collect. Each run does one operation; results land in the dataset as one row per item.

## `targets` (type: `array`):

What to scrape, one entry per line. For <b>posts / profiles / followers / following</b>: Bluesky handles (<code>bsky.app</code>, <code>name.bsky.social</code>), DIDs, or profile URLs (<code>https://bsky.app/profile/handle</code>). For <b>searchUsers</b>: search keywords. For <b>thread</b>: post URLs (<code>https://bsky.app/profile/handle/post/xyz</code>) or <code>at://</code> URIs.

## `maxItemsPerTarget` (type: `integer`):

Cap on collected items per target (per handle, query or thread).

## `includeReplies` (type: `boolean`):

When scraping author feeds, keep the user's replies as well as their original posts.

## `includeReposts` (type: `boolean`):

When scraping author feeds, keep items the user reposted (marked with repostedBy).

## `blueskyIdentifier` (type: `string`):

Your Bluesky handle, e.g. <code>name.bsky.social</code>. Only needed for the searchPosts operation — Bluesky requires login for post search. All other operations need no credentials.

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

An app password created at Bluesky Settings > App Passwords (not your main account password). Stored encrypted, used only to log in for post search, revocable any time.

## Actor input object example

```json
{
  "operation": "posts",
  "targets": [
    "bsky.app"
  ],
  "maxItemsPerTarget": 100,
  "includeReplies": false,
  "includeReposts": false
}
```

# Actor output Schema

## `items` (type: `string`):

All collected items as JSON.

## `csvExport` (type: `string`):

The same results as a CSV download.

# 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 = {
    "targets": [
        "bsky.app"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("apeye/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 = { "targets": ["bsky.app"] }

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

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

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

```

## CLI example

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=apeye/bluesky-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Bluesky Scraper & API - Posts, Search, Profiles, Followers",
        "description": "Scrape Bluesky through the official API: keyword post search, posts with like, repost and reply counts, profiles with follower totals, follower lists, user search and full threads. Clean JSON for social listening, influencer research and AI agents. No login needed except for post search.",
        "version": "0.1",
        "x-build-id": "bCp8Jb5kPzmK12hfp"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/apeye~bluesky-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-apeye-bluesky-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/apeye~bluesky-scraper/runs": {
            "post": {
                "operationId": "runs-sync-apeye-bluesky-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/apeye~bluesky-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-apeye-bluesky-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "operation",
                    "targets"
                ],
                "properties": {
                    "operation": {
                        "title": "What to scrape",
                        "enum": [
                            "posts",
                            "profiles",
                            "followers",
                            "following",
                            "searchUsers",
                            "searchPosts",
                            "thread"
                        ],
                        "type": "string",
                        "description": "The kind of data to collect. Each run does one operation; results land in the dataset as one row per item.",
                        "default": "posts"
                    },
                    "targets": {
                        "title": "Targets",
                        "type": "array",
                        "description": "What to scrape, one entry per line. For <b>posts / profiles / followers / following</b>: Bluesky handles (<code>bsky.app</code>, <code>name.bsky.social</code>), DIDs, or profile URLs (<code>https://bsky.app/profile/handle</code>). For <b>searchUsers</b>: search keywords. For <b>thread</b>: post URLs (<code>https://bsky.app/profile/handle/post/xyz</code>) or <code>at://</code> URIs.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxItemsPerTarget": {
                        "title": "Max items per target",
                        "minimum": 1,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "Cap on collected items per target (per handle, query or thread).",
                        "default": 100
                    },
                    "includeReplies": {
                        "title": "Include replies (posts operation)",
                        "type": "boolean",
                        "description": "When scraping author feeds, keep the user's replies as well as their original posts.",
                        "default": false
                    },
                    "includeReposts": {
                        "title": "Include reposts (posts operation)",
                        "type": "boolean",
                        "description": "When scraping author feeds, keep items the user reposted (marked with repostedBy).",
                        "default": false
                    },
                    "blueskyIdentifier": {
                        "title": "Bluesky handle (searchPosts only)",
                        "type": "string",
                        "description": "Your Bluesky handle, e.g. <code>name.bsky.social</code>. Only needed for the searchPosts operation — Bluesky requires login for post search. All other operations need no credentials."
                    },
                    "blueskyAppPassword": {
                        "title": "Bluesky app password (searchPosts only)",
                        "type": "string",
                        "description": "An app password created at Bluesky Settings > App Passwords (not your main account password). Stored encrypted, used only to log in for post search, revocable any time."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
