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

Scrape Bluesky posts by keyword or hashtag, user profiles, author feeds, followers, follows and full reply threads. No login, no browser — fast, cheap, clean JSON.

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

## Pricing

from $0.60 / 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 — Posts, Profiles, Followers & Search API

**Bluesky has 30M+ users and almost no good scrapers.** This one gives you clean, ready-to-use data on Bluesky posts, hashtags, profiles, followers and full reply threads. There's no login, no browser and no waiting: most runs finish in seconds.

Export to JSON, CSV, Excel or HTML, or pull the results straight into your app, spreadsheet, AI agent or automation.

### What can it scrape?

| Mode | You give it | You get |
|---|---|---|
| **Search posts** | Keywords or hashtags (`#ai`, `climate change`, `from:bsky.app`) | Matching posts, newest or most popular first |
| **Profile details** | Handles (`bsky.app`) or profile links | Bio, website, follower / following / post counts, avatar, banner, join date |
| **Author feed** | Handles | Everything a user posted, optionally with replies and reposts |
| **Followers** | Handles | Everyone who follows the account, with full profile details |
| **Follows** | Handles | Everyone the account follows, with full profile details |
| **Thread replies** | Post links | The post plus every reply in the conversation, with reply depth |

Every post includes its text, link, author, date, likes, reposts, replies, quotes, languages, hashtags, mentions, links, images (full size + alt text), video, link previews and quoted posts.

### Use cases

- **Social listening & brand monitoring.** Track mentions of your brand, product or competitors, and schedule the Actor to run hourly for a live feed.
- **Lead generation & influencer discovery.** Pull the followers of a niche account, sort by follower count, and read their bios and websites.
- **Market & academic research.** Build datasets of conversations around a topic, event or hashtag, with full reply threads for discourse analysis.
- **AI agents & RAG.** Feed fresh, structured Bluesky content to LLMs, vector databases and agents via the API or MCP.
- **Content & trend monitoring.** See which posts get traction, which links get shared, and what hashtags are rising.

### Why this scraper?

- **No login required.** Uses Bluesky's official public API, so there's no account and no cookies to break.
- **Fast and cheap.** No browser; runs usually return in seconds.
- **Clean, flat data.** Consistent field names, ISO-8601 dates, real numbers, `null` instead of empty strings, and no duplicates.
- **Respects privacy choices.** Accounts that asked Bluesky to hide their content from logged-out visitors are skipped automatically.
- **Budget-safe.** The run stops cleanly at your maximum cost, and you're never charged for items you didn't get.

### Sample output

Here are the first 3 results from a real run with the default input (search `#ai`), trimmed to the most useful fields. The full output also includes `cid`, `authorDid`, `authorAvatar`, `indexedAt`, `mentionDids`, `video`, `quotedPost`, reply/repost/thread fields, `labels`, `source` and `scrapedAt`.

```json
[
  {
    "url": "https://bsky.app/profile/nextlogic-ai.bsky.social/post/3mwgtfe5cge2z",
    "uri": "at://did:plc:37qq64lnbpp5rswmszg67qgq/app.bsky.feed.post/3mwgtfe5cge2z",
    "authorHandle": "nextlogic-ai.bsky.social",
    "authorDisplayName": "NextLogic-AI",
    "text": "🎨 New Post: Revolutionizing Cancer Detection: How Liquid Biopsies Could Transform Healthcare Careers\n#ai #biotechnology #cancer  #TechNews ...\n\n👇 View Full Illustration:\nhttps://nextlogic-ai.achlabo.com/en/revolutionizing-cancer-detection-how-liquid-biopsies-could-transform-healthcare-careers/",
    "createdAt": "2026-09-26T17:41:07.000Z",
    "likeCount": 0,
    "repostCount": 0,
    "replyCount": 0,
    "quoteCount": 0,
    "langs": [],
    "hashtags": ["ai", "biotechnology", "cancer", "TechNews"],
    "links": ["https://nextlogic-ai.achlabo.com/en/revolutionizing-cancer-detection-how-liquid-biopsies-could-transform-healthcare-careers/"],
    "embedType": "images",
    "images": [
      {
        "fullsize": "https://cdn.bsky.app/img/feed_fullsize/plain/did:plc:37qq64lnbpp5rswmszg67qgq/bafkreiduoimzny45u3qgjxzvmqiaixxfsgeuqgwg7logobwoda5h4i26wy",
        "alt": "Revolutionizing Cancer Detection: How Liquid Biopsies Could Transform Healthcare Careers"
      }
    ],
    "externalLink": null,
    "isReply": false
  },
  {
    "url": "https://bsky.app/profile/autoflow.bsky.social/post/3mwgteoy4my2p",
    "uri": "at://did:plc:ait3ewyppkd4ubgkldb6pvn3/app.bsky.feed.post/3mwgteoy4my2p",
    "authorHandle": "autoflow.bsky.social",
    "authorDisplayName": "Automation",
    "text": "Stop hardcoding your AI agent’s logic. Switch to \"State-Driven\" workflows using tools like LangGraph. By keeping the conversation state external, you can make your agents pause, human-in-the-loop, and recover from errors easily. #AI #Automation",
    "createdAt": "2026-09-26T17:40:47.737Z",
    "likeCount": 0,
    "repostCount": 0,
    "replyCount": 0,
    "quoteCount": 0,
    "langs": ["en"],
    "hashtags": ["AI", "Automation"],
    "links": [],
    "embedType": null,
    "images": [],
    "externalLink": null,
    "isReply": false
  },
  {
    "url": "https://bsky.app/profile/schoenenberger.bsky.social/post/3mwgtdubmys2e",
    "uri": "at://did:plc:bz6mqlgvztm3otrubyvmniyb/app.bsky.feed.post/3mwgtdubmys2e",
    "authorHandle": "schoenenberger.bsky.social",
    "authorDisplayName": "Henning Schoenenberger",
    "text": "Can visual AI help us understand cities without reducing urban life to what cameras can capture? #MIT researchers examine both the promise and peril.\n\nnews.mit.edu/2026/studyin...\n\n#Sociology #UrbanStudies #AI",
    "createdAt": "2026-09-26T17:40:19.927Z",
    "likeCount": 0,
    "repostCount": 0,
    "replyCount": 0,
    "quoteCount": 0,
    "langs": ["de"],
    "hashtags": ["MIT", "Sociology", "UrbanStudies", "AI"],
    "links": ["https://news.mit.edu/2026/studying-cities-using-visual-ai-fabio-duarte-martina-mazzarello-carlo-ratti-fan-zhang-book-0924"],
    "embedType": "external",
    "images": [],
    "externalLink": {
      "url": "https://news.mit.edu/2026/studying-cities-using-visual-ai-fabio-duarte-martina-mazzarello-carlo-ratti-fan-zhang-book-0924",
      "title": "The promise and peril of using visual AI to study cities"
    },
    "isReply": false
  }
]
```

A **profile** result (profile, followers and follows modes) looks like this:

```json
{
  "type": "profile",
  "did": "did:plc:z72i7hdynmk6r22z27h6tvur",
  "handle": "bsky.app",
  "url": "https://bsky.app/profile/bsky.app",
  "displayName": "Bluesky",
  "description": "official Bluesky account (check username👆)\n\nBugs, feature requests, feedback: support@bsky.app",
  "avatar": "https://cdn.bsky.app/img/avatar/plain/did:plc:z72i7hdynmk6r22z27h6tvur/bafkreihwihm6kpd6zuwhhlro75p5qks5qtrcu55jp3gddbfjsieiv7wuka",
  "followersCount": 35049457,
  "followsCount": 15,
  "postsCount": 864,
  "createdAt": "2023-04-12T04:53:57.057Z",
  "website": null,
  "pinnedPostUri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3l6oveex3ii2l",
  "relation": null,
  "relationSubjectHandle": null
}
```

In **followers** / **follows** mode, `relation` is `"follower"` or `"follows"`, and `relationSubjectHandle` tells you whose list the profile came from. `website` is the first web address found in the bio.

### Pricing

You pay only for results. There's no monthly fee.

| Event | Price | When |
|---|---|---|
| Actor start | **$0.005** | Once per run |
| Post scraped | **$0.0005** | Each post saved (search, author feed, thread) |
| Profile scraped | **$0.002** | Each profile saved (profile, followers, follows) |

**Worked examples:**

- **10,000 posts ≈ $5**: 10,000 × $0.0005 = $5.00, plus $0.005 to start.
- **1,000 posts ≈ $0.51**: $0.50 for the posts, plus $0.005.
- **1,000 followers with full profiles ≈ $2.01**: 1,000 × $0.002 = $2.00, plus $0.005.

Set **Maximum cost per run** in Apify Console and the Actor stops cleanly when it gets there. You're never charged for posts you didn't receive, and duplicates are never charged.

### Input

| Field | What it does | Default |
|---|---|---|
| `mode` | `search`, `profile`, `authorFeed`, `followers`, `follows` or `thread` | `search` |
| `queries` | Search terms or hashtags (Search mode) | `["#ai"]` |
| `handles` | Handles, DIDs or profile links (Profile, Author feed, Followers, Follows) | `["bsky.app"]` |
| `postUrls` | Post links or `at://` URIs (Thread mode) | a sample post |
| `maxItems` | Max results **per** search term / handle / thread (in Profile mode: max handles) | `200` |
| `since` | Only posts created on or after this date (UTC), e.g. `2025-01-31` | — |
| `until` | Only posts created before this date (UTC) | — |
| `includeReplies` | Include replies in Search and Author feed | `false` |
| `includeReposts` | Include reposts in Author feed | `false` |
| `expandEmbeds` | Add full quoted posts and link-preview details | `true` |
| `searchSort` | `latest` or `top` | `latest` |
| `blueskyHandle` | *Optional.* Your handle, to unlock deep search (see FAQ) | — |
| `blueskyAppPassword` | *Optional.* An **app password** (never your main password) | — |
| `blueskyServiceUrl` | Where to log in; change only for self-hosted accounts | `https://bsky.social` |
| `proxyConfiguration` | Proxy settings | Apify Proxy |

Example input:

```json
{
  "mode": "authorFeed",
  "handles": ["bsky.app", "nytimes.com"],
  "maxItems": 500,
  "since": "2025-01-01",
  "includeReposts": false
}
```

### How to use it

#### Apify API (cURL)

```bash
curl -X POST "https://api.apify.com/v2/acts/yasaslive~bluesky-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode":"search","queries":["#ai"],"maxItems":100}'
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("yasaslive/bluesky-scraper").call(run_input={
    "mode": "followers",
    "handles": ["bsky.app"],
    "maxItems": 1000,
})
for profile in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(profile["handle"], profile["followersCount"], profile["website"])
```

#### Node.js

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

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('yasaslive/bluesky-scraper').call({
    mode: 'thread',
    postUrls: ['https://bsky.app/profile/bsky.app/post/3l6oveex3ii2l'],
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, 'posts in the thread');
```

#### Make, n8n and Zapier

- **Make:** add the **Apify → Run an Actor** module, choose `yasaslive/bluesky-scraper`, paste your input JSON, then add **Apify → Get Dataset Items**.
- **n8n:** use the **Apify** node (Run Actor + Get dataset items), or an **HTTP Request** node that POSTs your input to the `run-sync-get-dataset-items` URL above.
- **Zapier:** use the **Apify** app with the **Run Actor** action.

#### AI agents (MCP)

Connect Claude, Cursor or any MCP client to the Apify MCP server and it can call this Actor as a tool:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com/?actors=yasaslive/bluesky-scraper",
      "headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }
    }
  }
}
```

Then ask something like *"Find the latest Bluesky posts about #climate and summarize the main arguments."*

### FAQ

**Do I need a Bluesky account?**
No, every mode works without one. The only exception is **deep search** (below).

**Why does Search return at most ~100 posts per term?**
Bluesky's public API gives logged-out visitors only the first page of search results, and blocks date filters. This Actor respects that limit. You have three options:

1. Add more search terms, since each term gets its own ~100 results.
2. Use **Author feed**, **Followers** or **Thread** modes, which have no such limit.
3. For deep search, fill in `blueskyHandle` and `blueskyAppPassword`. The Actor then logs in with *your* account and pages through all results, with server-side date filters.

Create an app password at [bsky.app/settings/app-passwords](https://bsky.app/settings/app-passwords). App passwords can be revoked at any time and can't change your account password. The login is used for search only. The password is stored encrypted by Apify and never logged.

**Why are some posts or profiles missing?**
Some Bluesky users ask not to be shown to logged-out visitors. Bluesky's own website hides them, and so does this Actor. The run's `STATS` record shows how many were skipped (`optOutSkipped`). Deleted, blocked or suspended content is also unavailable.

**Are follower counts included in Followers / Follows mode?**
Yes. Each profile is enriched with its full details, including follower, following and post counts.

**How fresh is the data?**
Live. Every run reads directly from Bluesky.

**Can I schedule it?**
Yes. Use Apify **Schedules** to run it hourly or daily, and connect a webhook or integration to receive new results.

**Where can I see what happened in a run?**
Open the run's **Storage → Key-value store → STATS**. It shows request counts, errors by type (blocked, rate-limited, proxy, network, parse, not found), items per input, charges, and whether the budget was reached.

### Limitations

- Logged-out search returns up to ~100 posts per search term (see FAQ). Other modes page through everything the API offers.
- Very large threads are returned as far as Bluesky's thread API goes, up to 1,000 levels deep.
- `since` / `until` apply to post modes. In Author feed mode the Actor stops paging once it passes `since`.
- Videos are returned as streaming playlist (`.m3u8`) and thumbnail URLs, not as downloaded files.
- `website` is best-effort, parsed from the bio text.

### Legal and responsible use

This Actor only reads **public** data from Bluesky's official public API. It doesn't log in unless you choose to, it doesn't bypass any access restriction, and it honours users' request not to be shown to logged-out visitors.

Scraped data can still contain personal data. You're responsible for how you use it: comply with the [Bluesky Terms of Service](https://bsky.social/about/support/tos), the [Bluesky developer guidelines](https://docs.bsky.app/docs/support/developer-guidelines), and data-protection laws such as the GDPR and CCPA. Have a legitimate purpose, keep only what you need, and don't use the data for spam, harassment or profiling of individuals. If you're unsure, consult a lawyer.

### Support

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

# Changelog

This Actor's version history is a separate document: https://apify.com/yasaslive/bluesky-scraper/changelog.md

# Actor input Schema

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

Search: posts matching keywords or hashtags. Profile: profile details for handles. Author feed: a user's posts. Followers / Follows: who follows a user / whom they follow. Thread: a post and all its replies.

## `queries` (type: `array`):

Used in Search mode. Keywords, phrases or hashtags, one per line — e.g. "#ai", "climate change", "from:bsky.app". Logged out, Bluesky returns up to ~100 posts per term; add a login below for more.

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

Used in Profile, Author feed, Followers and Follows modes. Handles ("bsky.app", "@jay.bsky.team"), DIDs, or profile URLs.

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

Used in Thread mode. Links like https://bsky.app/profile/bsky.app/post/3l6oveex3ii2l or at:// URIs.

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

Maximum posts or profiles saved for each search term, handle or thread. In Profile mode it caps the number of handles.

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

Only posts created on or after this date (UTC), e.g. 2025-01-31. Leave empty for no lower limit. Applies to post modes.

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

Only posts created before this date (UTC). Leave empty for no upper limit.

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

Include posts that are replies to other posts (Search and Author feed modes). Thread mode always returns replies.

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

Author feed mode: include posts the user reposted. Reposts carry repostedByHandle and repostedAt.

## `expandEmbeds` (type: `boolean`):

Add the full quoted post and link-preview details to each post. Images and video are always included.

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

Search mode: newest first (latest) or most popular (top).

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

Your Bluesky handle (e.g. alice.bsky.social) or account email. Leave empty to run without login. Used only in Search mode.

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

An app password like abcd-efgh-ijkl-mnop, created at https://bsky.app/settings/app-passwords. Never use your main password. It is stored encrypted and never logged.

## `blueskyServiceUrl` (type: `string`):

Where to log in. Keep https://bsky.social unless your account is on a self-hosted PDS.

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

Proxy used to reach Bluesky. The default Apify Proxy spreads requests across IPs to avoid rate limits.

## Actor input object example

```json
{
  "mode": "search",
  "queries": [
    "#ai"
  ],
  "handles": [
    "bsky.app"
  ],
  "postUrls": [
    "https://bsky.app/profile/bsky.app/post/3l6oveex3ii2l"
  ],
  "maxItems": 200,
  "includeReplies": false,
  "includeReposts": false,
  "expandEmbeds": true,
  "searchSort": "latest",
  "blueskyServiceUrl": "https://bsky.social",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Scraped posts or profiles.

## `stats` (type: `string`):

Request, error, charge and per-input counters (STATS record).

# 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 = {
    "mode": "search",
    "queries": [
        "#ai"
    ],
    "handles": [
        "bsky.app"
    ],
    "postUrls": [
        "https://bsky.app/profile/bsky.app/post/3l6oveex3ii2l"
    ],
    "maxItems": 200,
    "includeReplies": false,
    "includeReposts": false,
    "expandEmbeds": true,
    "searchSort": "latest",
    "blueskyServiceUrl": "https://bsky.social",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("yasaslive/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 = {
    "mode": "search",
    "queries": ["#ai"],
    "handles": ["bsky.app"],
    "postUrls": ["https://bsky.app/profile/bsky.app/post/3l6oveex3ii2l"],
    "maxItems": 200,
    "includeReplies": False,
    "includeReposts": False,
    "expandEmbeds": True,
    "searchSort": "latest",
    "blueskyServiceUrl": "https://bsky.social",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("yasaslive/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 '{
  "mode": "search",
  "queries": [
    "#ai"
  ],
  "handles": [
    "bsky.app"
  ],
  "postUrls": [
    "https://bsky.app/profile/bsky.app/post/3l6oveex3ii2l"
  ],
  "maxItems": 200,
  "includeReplies": false,
  "includeReposts": false,
  "expandEmbeds": true,
  "searchSort": "latest",
  "blueskyServiceUrl": "https://bsky.social",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call yasaslive/bluesky-scraper --silent --output-dataset

```

## MCP server setup

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