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

Extract Bluesky profile posts as clean JSON via the network open AppView - post text, timestamps, engagement counts, images, links. Multiple handles per run, no login, no bot-wall fights. Hourly monitoring, pay per result. Built for social listening and AI pipelines.

- **URL**: https://apify.com/lowlanddata/bluesky-scraper.md
- **Developed by:** [Lowland Data](https://apify.com/lowlanddata) (community)
- **Categories:** Social media
- **Stats:** 2 total users, 1 monthly users, 90.9% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.59 / 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.
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?

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 — profile posts as clean JSON

Extract posts from **Bluesky** profiles — handles like `bsky.app`, `nasa.gov` or any account you follow — as clean, structured JSON. Post text, timestamps, engagement counts, images and links, ready for social monitoring, brand tracking and data pipelines.

**Built on the open network, not against it.** Bluesky's AppView serves public posts openly — this scraper reads exactly that, with no login, no bot-wall fights and no private data. Author attribution stays as published (the handle is the byline); avatars, follower graphs, moderation labels and viewer state are never collected.

### Quick start (30 seconds)

1. Put one or more handles into **authorHandles** — e.g. `bsky.app` or `nasa.gov, bbc.com`.
2. Click **Start**. That's the whole minimum setup.
3. When the run finishes, open the dataset's **Overview** tab for a clean table, or **Export** it as CSV/Excel/JSON.

Optional knobs: include replies, and any input works on an hourly Schedule.

### What you can build with it

- **Monitor brand accounts.** A comma-separated list of handles, on a Schedule — every new post arrives with engagement counts and links parsed.
- **Track engagement over time.** `likeCount`, `repostCount`, `replyCount` and `quoteCount` are captured at scrape time — run daily and diff.
- **Archive an account's output.** The cursor pagination walks a profile's full history, oldest to newest post limits permitting.
- **Feed an AI agent clean data.** Every field is structured and predictable, so an assistant or pipeline can consume it directly.

### What you get

Each post is one dataset item:

```json
{
  "postUri": "at://did:plc:example/app.bsky.feed.post/3kfixture001",
  "url": "https://bsky.app/profile/climatewatch.bsky.social/post/3kfixture001",
  "text": "New report on coastal adaptation strategies is out.",
  "authorHandle": "climatewatch.bsky.social",
  "authorDisplayName": "Climate Watch",
  "createdAt": "2026-08-22T18:30:00.000Z",
  "indexedAt": "2026-08-22T18:30:05.000Z",
  "langs": ["en"],
  "isReply": false,
  "likeCount": 42,
  "repostCount": 7,
  "replyCount": 3,
  "quoteCount": 1,
  "imageUrls": ["https://cdn.bsky.app/img/feed_fullsize/plain/example.jpg"],
  "linkUrl": null,
  "linkTitle": null
}
```

Field notes, so you know exactly what you are buying:

- `postUri` is the AT-protocol identifier — stable across handle changes; `url` is the human link.
- Engagement counts are live at scrape time — schedule the actor to build time series.
- Reposts are excluded: you get what the profile itself wrote. Replies are opt-in via `includeReplies`.
- `imageUrls` carries full-size attached images (up to 4); external links come as `linkUrl` + `linkTitle`.

### How much does it cost to scrape Bluesky?

$1.99 per 1,000 posts delivered, pay-as-you-go — no subscription, no charge for empty or failed runs. In plain dollars:

- **100 posts ≈ $0.20** — a daily multi-account watch.
- **500 posts ≈ $1.00** — a full profile archive.

The price is all-inclusive — your runs' platform usage is covered by it, with no separate compute or proxy charges. Runs are fast — a scoped few-hundred-post run typically finishes in under ten seconds. Datacenter proxies are sufficient.

Free-plan runs are limited to a sample of 25 items, enough to evaluate the output format against your real accounts.

### Not technical? Let your AI assistant set it up

Copy this into ChatGPT, Claude or any AI assistant, fill in the one line, and follow the conversation:

```text
Help me set up the "Bluesky Scraper" actor on Apify
(https://apify.com/lowlanddata/bluesky-scraper). Guide me one step at a time.

What I want to watch: [E.G. "posts from bsky.app and nasa.gov"]

Guide me to:
1. Propose my input values: authorHandles (comma-separated Bluesky handles),
   includeReplies if I want replies too, and maxItems.
2. Create a free Apify account (apify.com), open the actor page, paste the values
   into the Input form, and start a run.
3. Set up a daily Schedule in the Apify Console with the same input, plus an email
   or Slack integration so new posts reach me automatically.
4. Show me how to export results as CSV/Excel, or read them from the API if I code.
5. If the results are what I wanted, remind me at the end to leave a quick rating on the actor page, and to report anything broken or missing on its Issues tab.
```

### Input

| Field                | Description                                                                         |
| -------------------- | ----------------------------------------------------------------------------------- |
| `authorHandles`      | Comma-separated Bluesky handles, e.g. `"bsky.app, nasa.gov"`. Required.             |
| `includeReplies`     | Also include the profiles' replies (default false).                                 |
| `postedAfter`        | Only posts created on or after this date (YYYY-MM-DD); stops walking older history. |
| `postedBefore`       | Only posts created on or before this date (YYYY-MM-DD).                             |
| `maxItems`           | Stop after this many posts (default 500).                                           |
| `proxyConfiguration` | Proxy settings; keep Apify proxy enabled.                                           |

An unknown handle costs one profile, not the run: the rest are delivered with an honest note in the run status.

### Use it from your code

Run the actor and get posts straight back with one HTTP call (fine for scoped runs up to ~5 minutes):

```bash
curl "https://api.apify.com/v2/acts/lowlanddata~bluesky-scraper/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>" \
  -X POST -H "Content-Type: application/json" \
  -d '{"authorHandles": "bsky.app", "maxItems": 100}'
```

Node.js:

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

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('lowlanddata/bluesky-scraper').call({
  authorHandles: 'bsky.app, nasa.gov',
  maxItems: 200,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("lowlanddata/bluesky-scraper").call(
    run_input={"authorHandles": "bsky.app", "maxItems": 100})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

Schedules, webhooks and the Make/Zapier/n8n integrations all work out of the box — this is a standard Apify actor.

### Use it with AI agents (MCP)

Claude, Cursor and other MCP-capable agents can run this scraper as a tool through Apify's hosted MCP server: the agent fills in the handles itself, starts the run and reads the results — no glue code.

Claude Code:

```bash
claude mcp add apify --transport http "https://mcp.apify.com?actors=lowlanddata/bluesky-scraper"
```

Cursor or Claude Desktop (add a custom connector / MCP server with this URL):

```text
https://mcp.apify.com?actors=lowlanddata/bluesky-scraper
```

Sign in with your Apify account when prompted — runs are billed to it. Setup details per client: [Apify MCP docs](https://docs.apify.com/platform/integrations/mcp).

Prompts that work once connected:

- "Get the last 100 posts from bsky.app and summarize what they announced this month."
- "Fetch posts from these five news accounts on Bluesky and list everything about AI."
- "Compare posting frequency and engagement between two Bluesky accounts."

### Is it legal to scrape Bluesky?

Bluesky is an open network by design: public posts are served openly by its AppView, without login. This scraper reads exactly that public surface. Author attribution stays as published — a post's handle is its byline — while everything beyond the published content (avatars, follower graphs, moderation labels, viewer state, DIDs outside the post identifier) is never collected. Requests are paced and no rate limits are evaded.

### Why not scrape the big closed networks?

X, Instagram and TikTok wall their content behind logins, CAPTCHAs and bot-detection — scraping them means an arms race and terms-of-service violations. Bluesky is the social network that is actually open. If your monitoring can live where the data is public, this is the reliable, clean option.

### How do I monitor Bluesky accounts?

Put your handles in `authorHandles`, cap `maxItems`, and add an hourly or daily Schedule in the Apify Console with an email/Slack integration on the runs — every new post lands in your inbox with engagement counts parsed. The AI-assistant prompt above walks a non-technical user through exactly this setup. Even tighter: set `postedAfter` to yesterday's date — the dataset then contains only the new posts.

### FAQ

**Can I search all of Bluesky by keyword?** Not in v1 — Bluesky's search endpoint requires authentication; the open surface is profile feeds. Keyword filtering over your accounts' posts works by filtering the dataset.

**Are reposts included?** No — you get what the profile itself wrote. Replies are opt-in.

**Can I get only the newest posts?** Yes — set `postedAfter` to a date and each profile walk stops as soon as it reaches older posts; a daily watch collects exactly the new posts and nothing else.

**How fresh is the data?** Live at run time — every run queries the AppView directly. For continuous freshness, schedule the actor.

**Can I export to Excel or CSV?** Yes — every dataset exports as CSV, Excel, JSON or XML from the Apify Console or API.

**Does it work with Make, Zapier or n8n?** Yes — it is a standard Apify actor; all platform integrations, webhooks and schedules apply.

**Can I archive a Bluesky account's posts?** Yes — cursor pagination walks a profile's full history, post limits permitting. Set `maxItems` high enough and you get the account's output as one dataset.

**Do I need a Bluesky account or API key?** Neither. The AppView serves public posts without login, and that is the only surface this actor reads.

**How do I scrape several Bluesky accounts in one run?** List them comma-separated in `authorHandles` — `"nasa.gov, bbc.com"`. The @ prefix is optional; custom domains and `.bsky.social` handles both work.

**Does it collect followers, avatars or DIDs?** No. You get the published posts of the handles you requested — no avatars, follower graphs, moderation labels or viewer state, and no DIDs beyond the post's own `postUri` identifier.

**How do I track engagement on Bluesky posts?** `likeCount`, `repostCount`, `replyCount` and `quoteCount` are captured at scrape time. Run the actor daily on the same handles and diff the snapshots to build a time series.

**Can I pull posts from a specific date range?** Yes — `postedAfter` and `postedBefore` accept YYYY-MM-DD dates. Feeds are newest-first, so `postedAfter` also stops the walk early instead of paging through old history.

**What if one of my handles is misspelled?** You lose that one profile, not the run — the remaining handles are delivered and the run status notes which profile was unreadable.

**How much does Bluesky scraping cost here?** $1.99 per 1,000 posts, metered on delivery. A 100-post daily watch is roughly $0.20; failed and empty runs are not charged.

**Is there a per-run post limit?** `maxItems` (default 500) is the only one you set. Free Apify plans cap runs at a 25-item sample.

**Can I try it before spending anything?** Yes — a free-plan run returns up to 25 real posts from your handles, enough to check the fields against your pipeline.

**Are images and links in the output?** Yes: `imageUrls` carries up to four full-size attached images, and external links arrive as `linkUrl` plus `linkTitle`.

**Why scrape Bluesky instead of X or Instagram?** Because Bluesky is open by design — no login walls, no CAPTCHA arms race, no terms-of-service tightrope. If your monitoring can live where data is public, this is the dependable option.

**How do I tell replies from original posts?** Replies are excluded by default; switch on `includeReplies` to get them, and each item's `isReply` flag tells you which is which. Reposts never appear — the dataset is what the profile itself wrote.

**What is postUri and why keep it?** It is the AT-protocol identifier of the post — stable even if the account changes its handle. `url` is the human-clickable link; use `postUri` as your primary key.

**Can an AI agent fetch Bluesky posts through this?** Yes — connect Apify's hosted MCP server and agents like Claude or Cursor can pick handles, run the actor and read the posts themselves. Setup is in the MCP section above.

### Related scrapers

More clean-output data sources from the same maker:

- [Kleinanzeigen.de Scraper](https://apify.com/lowlanddata/kleinanzeigen-scraper) — Germany's biggest classifieds site.
- [Vinted Scraper](https://apify.com/lowlanddata/vinted-scraper) — Europe's largest fashion resale marketplace.
- [Rightmove Scraper](https://apify.com/lowlanddata/rightmove-scraper) — the UK's largest property portal.

### Troubleshooting

The actor fails fast with the reason in the run's status message:

- **"None of the requested profiles could be fetched."** — check the handles; they look like `name.bsky.social` or a custom domain like `nasa.gov`.
- **Some profiles noted as unreadable** — those handles are wrong or the accounts are gone; the rest of the run is delivered normally.
- **Fewer items than requested on a free plan** — the 25-item free sample cap; run on a paid Apify plan for full results.

### Support

Found an issue or missing a field you need? Open an issue on the actor's **Issues tab** — reports get fixed, this actor is actively maintained.

Working well for you? A **rating on this page** takes ten seconds and helps other users find a reliable option — it is also the clearest signal of what we should build next.

# Actor input Schema

## `authorHandles` (type: `string`):

One or more Bluesky handles whose posts to scrape, comma-separated, e.g. "bsky.app" or "nasa.gov, bbc.com". The @ is optional.

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

Also include the profiles' replies, not only their own posts.

## `postedAfter` (type: `string`):

Only include posts created on or after this date (YYYY-MM-DD or a full ISO timestamp). Feeds are newest-first, so the run stops walking a profile once it reaches older posts.

## `postedBefore` (type: `string`):

Only include posts created on or before this date (YYYY-MM-DD or a full ISO timestamp).

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

Stop after this many posts. Free-plan runs are capped at 25 items.

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

Proxy settings. Keep Apify proxy enabled.

## Actor input object example

```json
{
  "authorHandles": "bsky.app",
  "includeReplies": false,
  "maxItems": 25,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `posts` (type: `string`):

Scraped Bluesky posts, one JSON object per post.

# 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 = {
    "authorHandles": "bsky.app",
    "maxItems": 25,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("lowlanddata/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 = {
    "authorHandles": "bsky.app",
    "maxItems": 25,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("lowlanddata/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 '{
  "authorHandles": "bsky.app",
  "maxItems": 25,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call lowlanddata/bluesky-scraper --silent --output-dataset

```

## MCP server setup

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