# Bluesky Scraper (`goat255/bluesky-scraper`) Actor

Scrape Bluesky posts, profiles, threads, and search results without a login. Pull a user's posts by handle, a post plus its reply thread, or keyword search results. Walks pagination up to your chosen limit.

- **URL**: https://apify.com/goat255/bluesky-scraper.md
- **Developed by:** [Goutam Soni](https://apify.com/goat255) (community)
- **Categories:** Social media, Lead generation, News
- **Features:** Limited permissions
- **Stats:** 5 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

Scrape Bluesky posts, profiles, threads, and keyword search results with no login and no API key. Give it handles, post links, or search terms and it returns clean structured rows with full engagement metrics, author details, media, and timestamps.

The Bluesky Scraper extracts public data from Bluesky at scale. Pull a user's recent posts by handle, fetch a single post with its full reply thread, or run keyword searches across the network. Pagination is walked automatically up to the limit you set, so you can collect hundreds or thousands of posts per source in one run.

### What it does

- **User posts by handle.** Collect a user's recent posts, with optional replies and a profile header row (display name, bio, follower and post counts).
- **Post threads from a URL.** Fetch any post plus its nested reply tree, flattened into rows.
- **Keyword search.** Search public posts by term, sorted by latest or top.
- **Full engagement metrics.** Likes, reposts, replies, and quotes on every post.
- **Media and links.** Photo URLs, video stream and poster image, link-card previews, and richtext links.
- **Rich post detail.** Author identity, post text, language, hashtags, mentions, reply flags, repost flags, and timestamps.
- **Automatic pagination and deduplication.** Walks multiple pages per source and drops duplicate rows so every result is unique.
- **No login, no password, no API key.** Runs against public read-only endpoints.

### Use cases

- **Brand and topic monitoring.** Track keyword searches to see who is talking about your product, niche, or industry on Bluesky.
- **Lead generation and outreach.** Pull posters around a topic and capture their handle, display name, and bio for prospecting.
- **Market and competitor research.** Analyze a competitor's posting cadence, engagement, and audience by scraping their handle (use a public placeholder like `example.bsky.social`).
- **Sentiment and trend analysis.** Collect large post samples for a query and feed text plus engagement counts into your own analysis.
- **Thread archiving.** Save a post and its full reply thread for research, support, or compliance records.

### Input

| Field | Type | Description |
|---|---|---|
| `handles` | array | Handles to pull posts from. With or without `@`, or a full profile link (e.g. `example.bsky.social`). |
| `postUrls` | array | Post links to fetch with their reply thread. |
| `searchQueries` | array | Keyword searches to run across public posts. |
| `maxItemsPerSource` | integer | Cap on items returned per handle, post, or query. Default 100. |
| `includeReplies` | boolean | Include a handle's replies, not just top-level posts. Default false. |
| `includeProfile` | boolean | Emit one profile row per handle before its posts. Default true. |
| `searchSort` | string | Search order: `latest` or `top`. |
| `concurrency` | integer | Number of sources processed in parallel. Default 5. |
| `proxyConfig` | object | Optional proxy. The public endpoints do not require one. |

#### Example input

```json
{
  "handles": ["example.bsky.social"],
  "searchQueries": ["open source"],
  "maxItemsPerSource": 200,
  "includeReplies": false,
  "includeProfile": true,
  "searchSort": "latest"
}
```

### Output

Each post is one row:

```json
{
  "type": "post",
  "uri": "at://did:plc:example/app.bsky.feed.post/abc123",
  "url": "https://bsky.app/profile/example.bsky.social/post/abc123",
  "authorHandle": "example.bsky.social",
  "authorDisplayName": "Example User",
  "authorDid": "did:plc:example",
  "likeCount": 42,
  "repostCount": 7,
  "replyCount": 3,
  "quoteCount": 1,
  "text": "An example post about open source.",
  "lang": "en",
  "tags": ["opensource"],
  "mentions": [],
  "links": ["https://example.com"],
  "thumbnail": "https://example.com/preview.jpg",
  "images": [],
  "video": null,
  "isReply": false,
  "replyToUri": null,
  "isRepost": false,
  "cid": "bafyexamplecid",
  "createdAt": "2026-06-01T12:00:00.000Z",
  "indexedAt": "2026-06-01T12:00:05.000Z"
}
```

Key fields:

- `url` is the public permalink to the post.
- `likeCount`, `repostCount`, `replyCount`, `quoteCount` are the engagement counts at scrape time.
- `thumbnail` is the best single preview image for the post (attached photo, video poster frame, or link-card preview), so the media column is filled even for link posts.
- `isReply` / `replyToUri` flag reply posts; `isRepost` flags posts that appeared in a feed via a repost.

When `includeProfile` is on, each handle also emits one profile row with `handle`, `url`, `displayName`, `did`, `followersCount`, `followsCount`, `postsCount`, `description`, `avatar`, `banner`, and `createdAt`.

### FAQ

**Do I need a Bluesky login or API key?**
No. The scraper reads public data through public endpoints. No account, password, or key is required.

**Is it free?**
The actor itself is pay-per-result, so you only pay for the rows you collect. Apify platform usage applies as normal. There is no per-run start fee.

**How many results can I get?**
Set `maxItemsPerSource` to your target. The scraper walks pagination across multiple pages until it reaches your cap or the source runs out of posts. You can collect hundreds or thousands of posts per handle or query.

**How fast is it?**
Sources run in parallel (set with `concurrency`). A few hundred posts per source typically complete in seconds to a couple of minutes depending on how many sources and pages are involved.

**Can I scrape a private account?**
No. Only public posts, profiles, and threads are available.

**What input formats does it accept for handles and posts?**
Handles can be plain (`example.bsky.social`), prefixed (`@example.bsky.social`), or a full profile URL. Post inputs accept the standard `bsky.app` post link.

### Privacy

To improve our actors we collect anonymized usage telemetry (run stats and input patterns). No personal account data is collected.

# Actor input Schema

## `handles` (type: `array`):

Bluesky handles to pull recent posts from. With or without the @ prefix, or a full profile link. Example: example.bsky.social, @example.bsky.social, https://bsky.app/profile/example.bsky.social.

## `postUrls` (type: `array`):

Specific post links to fetch with their reply thread. Example: https://bsky.app/profile/example.bsky.social/post/abc123.

## `searchQueries` (type: `array`):

Keyword searches to run across Bluesky posts. Example: open source, machine learning.

## `maxItemsPerSource` (type: `integer`):

Cap on items returned per handle, post, or query. Pagination is walked across multiple pages until this is reached or the source is exhausted.

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

When on, a handle's reply posts are included alongside its top-level posts.

## `includeProfile` (type: `boolean`):

When on, each handle also emits one profile record (display name, bio, follower counts) before its posts.

## `searchSort` (type: `string`):

Sort order for search results. Latest or Top.

## `concurrency` (type: `integer`):

How many sources to process in parallel.

## `proxyConfig` (type: `object`):

Optional proxy. The public read endpoints do not require a proxy, but you may route through one if you wish.

## Actor input object example

```json
{
  "handles": [
    "bsky.app"
  ],
  "postUrls": [],
  "searchQueries": [],
  "maxItemsPerSource": 100,
  "includeReplies": false,
  "includeProfile": true,
  "searchSort": "latest",
  "concurrency": 5,
  "proxyConfig": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `posts` (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 = {
    "handles": [
        "bsky.app"
    ],
    "postUrls": [],
    "searchQueries": []
};

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

# Run the Actor and wait for it to finish
run = client.actor("goat255/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 '{
  "handles": [
    "bsky.app"
  ],
  "postUrls": [],
  "searchQueries": []
}' |
apify call goat255/bluesky-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,goat255/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/KHKU5qje6JGyAq5jQ/builds/QNxpZrCJFGcfQjf2I/openapi.json
