# Bluesky Scraper - Posts, Profiles, Search & Monitor (`crawloop/bluesky-scraper`) Actor

Scrape Bluesky posts, profiles, keyword/hashtag search, threads, followers, likes, reposts, and custom feeds via the public AT Protocol AppView API. Incremental monitor mode for schedules. No login for public data. Fast async JSON on Apify.

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

## Pricing

from $1.00 / 1,000 scraped items

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 web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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, Profiles, Search & Monitor

> Unofficial tool for publicly accessible Bluesky / AT Protocol AppView data. Bluesky and related trademarks belong to their respective owners. Not affiliated with, sponsored by, or endorsed by Bluesky PBC. Provided for informational use only; users must comply with applicable terms and laws.

| Social discovery | Product launches |
| :--- | :--- |
| **Bluesky Scraper** ◄── you are here | [Product Hunt Scraper](https://apify.com/crawloop/producthunt-scraper) |
| Posts, profiles, search, threads, graph, monitor | Launches, reviews, comments, leaderboards |

**Bluesky scraper** for Apify — extract **posts, profiles, hashtag/keyword search, reply threads, followers, following, likes, reposts, and custom feeds** from Bluesky via the open **AT Protocol** public AppView API. No browser, no Cloudflare fight, and **no login for public data** (including post search).

**Monitor mode** stores per-target watermarks in a named key-value store and returns **only posts newer than the last run** — built for hourly/daily schedules, brand listening, and competitor tracking.

### When to use this Actor

- Brand / hashtag listening without an app password
- Author feed export for influencers, journalists, or competitors
- Profile enrichment (followers, bio, post counts)
- Social graph pulls (followers / following)
- Full conversation trees for research
- Scheduled incremental monitoring of accounts or queries

### Key Features

- **AT Protocol XRPC** — fast `httpx` async client against public AppView endpoints
- **Dual-host search** — routes post search so it works without Bluesky credentials
- **11 modes** — user posts, profiles, search, search users, threads, followers, following, custom feed, likes, reposts, **monitor**
- **Incremental monitor** — named KV watermarks; optional baseline-only first run
- **Batch hydration** — `getProfiles` / `getPosts` (up to 25)
- **RateGate** — client RPS budget + 429 backoff; proxy optional
- **Flat JSON rows** — Store-ready `type` field (`post`, `profile`, `follower`, …)

### Input Parameters

| Parameter | Description |
|-----------|-------------|
| `mode` | `user_posts`, `user_profiles`, `search`, `search_users`, `post_threads`, `followers`, `following`, `custom_feed`, `likes`, `reposts`, `monitor` |
| `startUrls` | Profile / post / feed URLs or `at://` URIs |
| `handles` | Handles or DIDs |
| `searchQuery` / `searchQueries` | Keyword or hashtag queries |
| `searchSort` | `latest` or `top` (search mode) |
| `monitorSource` | `user_posts` | `search` | `custom_feed` |
| `monitorStoreName` | Named KV store for watermarks |
| `monitorBaselineOnly` | First run: set watermark, push nothing |
| `resetMonitorState` | Clear watermarks before run |
| `includeReplies` / `includeReposts` | Author-feed filters |
| `threadDepth` | Max reply depth for threads |
| `maxItems` | Dataset row cap (`0` = unlimited) |
| `concurrency` | Parallel streams (default 8) |
| `maxRequestsPerSecond` | Client rate limit (default 10) |
| `proxyConfiguration` | Optional; usually not required |

Author feed:

```json
{
  "mode": "user_posts",
  "handles": ["jay.bsky.team", "bsky.app"],
  "maxItems": 100,
  "concurrency": 8,
  "maxRequestsPerSecond": 10,
  "includeReplies": true,
  "includeReposts": true,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

Post search (no app password):

```json
{
  "mode": "search",
  "searchQuery": "#ai",
  "searchSort": "latest",
  "maxItems": 200
}
```

Monitor (schedule after a baseline run):

```json
{
  "mode": "monitor",
  "monitorSource": "search",
  "searchQueries": ["#ai", "bluesky"],
  "monitorStoreName": "bluesky-monitor-brand-x",
  "monitorBaselineOnly": true,
  "maxItems": 200,
  "maxRequestsPerSecond": 10
}
```

After the baseline run, set `monitorBaselineOnly` to `false` (or omit it) so later runs push only new posts.

### Output Format

| Field | Description |
|-------|-------------|
| `type` | `post`, `profile`, `follower`, `following`, `like`, `repost` |
| `id` | AT-URI or DID |
| `url` | Web URL on bsky.app |
| `text` | Post body |
| `authorHandle` / `authorDid` | Author identity |
| `likeCount` / `repostCount` / `replyCount` / `quoteCount` | Engagement |
| `hashtags` / `mentions` / `media` | Facets and embeds |
| `followersCount` / `followsCount` / `postsCount` | Profile counters |
| `monitorTarget` / `monitorSource` | Present on monitor rows |

```json
{
  "type": "post",
  "id": "at://did:plc:oky5czdrnfjpqslsw2a5iclo/app.bsky.feed.post/3mrdkahh4xk2r",
  "url": "https://bsky.app/profile/jay.bsky.team/post/3mrdkahh4xk2r",
  "text": "Example post text",
  "authorHandle": "jay.bsky.team",
  "authorDid": "did:plc:oky5czdrnfjpqslsw2a5iclo",
  "likeCount": 42,
  "repostCount": 3,
  "replyCount": 5,
  "hashtags": [],
  "media": [],
  "monitorTarget": "#ai",
  "monitorSource": "search"
}
```

### Workflow tips

1. Use `handles` + `user_posts` / `user_profiles` for known accounts.
2. Prefer `search` for discovery — no Bluesky app password needed.
3. Cap large follower graphs with `maxItems`; add proxies only for very high RPS.
4. For alerts: baseline with `monitorBaselineOnly`, then schedule without it.
5. Give each scheduled monitor a **distinct** `monitorStoreName`.

### Related Actors

| Actor | Role |
| :--- | :--- |
| Bluesky Scraper ◄── you are here | Bluesky / AT Protocol public data |
| [Product Hunt Scraper](https://apify.com/crawloop/producthunt-scraper) | Product launches, reviews, comments |

# Actor input Schema

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

What to scrape from Bluesky public AppView (AT Protocol XRPC).

## `startUrls` (type: `array`):

Bluesky profile, post, or custom feed URLs (or raw at:// URIs). Used by most modes.

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

Bluesky handles (alice.bsky.social) or DIDs. Used for profiles, posts, and graph modes.

## `searchQuery` (type: `string`):

Full-text or hashtag query for search / search\_users / monitor(search) (e.g. python, #ai).

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

Optional list of queries for search or monitor(search). Merged with Search Query.

## `monitorSource` (type: `string`):

For mode=monitor: track author feeds, keyword search, or a custom feed. Only posts newer than the last run are emitted.

## `monitorStoreName` (type: `string`):

Named Apify key-value store holding per-target watermarks across runs. Use a distinct name per schedule/job.

## `monitorBaselineOnly` (type: `boolean`):

If true and no watermark exists yet, set the watermark from the newest posts without pushing results. Next scheduled run emits only truly new posts.

## `resetMonitorState` (type: `boolean`):

Clear watermarks in the monitor store before this run.

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

Sort for post search.

## `authorFilter` (type: `string`):

Optional author handle/DID to restrict post search.

## `lang` (type: `string`):

Optional language code filter for post search (e.g. en).

## `since` (type: `string`):

Optional lower bound for post search (ISO date/datetime).

## `until` (type: `string`):

Optional upper bound for post search (ISO date/datetime).

## `feedUri` (type: `string`):

Feed generator AT-URI for custom\_feed mode (or pass a bsky.app feed URL in Start URLs).

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

In user\_posts mode, include reply posts from the author feed.

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

In user\_posts mode, include reposts from the author feed.

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

Max reply depth for post\_threads mode.

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

Maximum dataset rows to push. 0 = unlimited.

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

Parallel streams (authors / posts). Cursor pages within one stream stay sequential.

## `maxRequestsPerSecond` (type: `number`):

Client-side rate limit per run (shared across workers). Raise carefully; use proxies for higher throughput.

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

Optional. Public AppView usually works without a proxy; enable Datacenter proxies for large parallel jobs.

## Actor input object example

```json
{
  "mode": "user_posts",
  "startUrls": [
    {
      "url": "https://bsky.app/profile/jay.bsky.team"
    }
  ],
  "handles": [
    "jay.bsky.team"
  ],
  "searchQuery": "",
  "searchQueries": [],
  "monitorSource": "user_posts",
  "monitorStoreName": "bluesky-monitor-state",
  "monitorBaselineOnly": false,
  "resetMonitorState": false,
  "searchSort": "latest",
  "authorFilter": "",
  "lang": "",
  "since": "",
  "until": "",
  "feedUri": "",
  "includeReplies": true,
  "includeReposts": true,
  "threadDepth": 6,
  "maxItems": 100,
  "concurrency": 8,
  "maxRequestsPerSecond": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Default dataset items (posts, profiles, followers, likes, etc.).

# 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 = {
    "startUrls": [
        {
            "url": "https://bsky.app/profile/jay.bsky.team"
        }
    ],
    "handles": [
        "jay.bsky.team"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawloop/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 = {
    "startUrls": [{ "url": "https://bsky.app/profile/jay.bsky.team" }],
    "handles": ["jay.bsky.team"],
}

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

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/a3pfbSpbUuen0p2nQ/builds/unEvfP4rBbUo77j4F/openapi.json
