# Bluesky Scraper — Posts, Graphs & AT Protocol (`scrapingmonkey/bluesky-at-protocol-scraper`) Actor

Scrape public Bluesky profiles, posts, threads, search, followers, likes, reposts, lists, feeds, trends, and AT Protocol repository records with stable DID and AT URI provenance.

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

## Pricing

from $1.00 / 1,000 profile 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 - Profiles, Posts, Search, Followers and Feeds

Collect public Bluesky profiles, posts, threads, search results, interactions, social graph data, lists, feeds, trends, and AT Protocol repository records.

- Extract profile identity, bio, verification data, audience counts, avatars, and banners
- Collect author feeds, individual posts, complete threads, parents, replies, media, links, and engagement counts
- Search public posts or accounts with available sorting, language, and date filters
- Export likes, reposts, quotes, followers, follows, list members, and suggested accounts
- Discover public lists, custom feeds, popular feeds, and current trend records
- Read public AT Protocol repository collections directly from each actor's discovered PDS
- No Bluesky account, app password, cookies, browser, or user-supplied proxy is required; requests use the built-in Apify Residential Proxy
- Export results to JSON, CSV, Excel, XML, RSS, or access them through the Apify API

### What can you do with this Actor?

| Mode / action | Input | Output | Best for |
| --- | --- | --- | --- |
| `profiles` | Handles, DIDs, or profile URLs | `profile` rows | Profile metrics and creator research |
| `authorFeeds` | Handles, DIDs, or profile URLs | Paginated `post` rows | Publishing analysis and monitoring |
| `posts` | AT URIs or public post URLs | Complete `post` rows | Batch post enrichment |
| `threads` | AT URIs or public post URLs | Root, parent, and reply `post` rows | Conversation and reply analysis |
| `postInteractions` | AT URIs or public post URLs plus interaction types | `interaction` rows | Likes, reposts, and quote relationships |
| `searchPosts` | Search terms and optional filters | Matching `post` rows | Topic research and social listening |
| `searchActors` | Search terms | Matching `profile` rows | Account discovery |
| `followers` / `follows` | Handles, DIDs, or profile URLs | Connected `profile` rows | Public audience and network analysis |
| `lists` / `listItems` | Actors or public list AT URIs | `list` or member `profile` rows | Curated network research |
| `actorFeeds` / `popularFeeds` | Actors or no specific target | Public `feed` rows | Feed discovery and cataloging |
| `customFeed` | Public feed-generator AT URIs | Feed `post` rows | Custom-feed content analysis |
| `trends` | No target beyond the selected mode | Public `trend` rows | Topic and trend tracking |
| `suggestedFollows` | Handles, DIDs, or profile URLs | Suggested `profile` rows | Account discovery and graph expansion |
| `repoRecords` | Actors and public AT Protocol collections | `repoRecord` rows from each actor's PDS | Protocol research and public record export |
| `auto` | Mixed public profile and post URLs | `profile` or `post` rows selected from each URL | Batch processing mixed known targets |

Choose one mode per run. Multiple actors, posts, lists, feeds, or search terms can be processed in one run, and `maxItems` applies separately to each input target or collection.

### Quick start

1. Open the Actor and click **Try for free**.
2. Keep **Author Feeds** selected or choose another public Bluesky workflow.
3. Enter handles, DIDs, URLs, AT URIs, or search terms and set the result limit.
4. Click **Start**.
5. Preview the single **Results** table or download it in your preferred format.

The default input collects recent public posts from `bsky.app` and is ready to run.

### Input examples

#### Profiles and counts

```json
{
  "mode": "profiles",
  "actors": [
    "bsky.app",
    "jay.bsky.team"
  ],
  "country": "US"
}
```

#### Recent author posts

```json
{
  "mode": "authorFeeds",
  "actors": [
    "bsky.app"
  ],
  "maxItems": 100,
  "feedFilter": "posts_with_replies",
  "country": "US"
}
```

#### Search posts

```json
{
  "mode": "searchPosts",
  "searchTerms": [
    "open source AI"
  ],
  "searchSort": "latest",
  "maxItems": 100,
  "country": "US"
}
```

#### Thread and replies

```json
{
  "mode": "threads",
  "postUris": [
    "https://bsky.app/profile/bsky.app/post/POST_RKEY"
  ],
  "threadDepth": 20,
  "country": "US"
}
```

#### Followers

```json
{
  "mode": "followers",
  "actors": [
    "bsky.app"
  ],
  "maxItems": 500,
  "country": "US"
}
```

#### Public repository

```json
{
  "mode": "repoRecords",
  "actors": [
    "bsky.app"
  ],
  "collections": [
    "app.bsky.feed.post"
  ],
  "maxItems": 100,
  "country": "US"
}
```

#### Post details

```json
{
  "mode": "posts",
  "postUris": [
    "https://bsky.app/profile/bsky.app/post/POST_RKEY"
  ],
  "country": "US"
}
```

#### Likes, reposts, and quotes

```json
{
  "mode": "postInteractions",
  "postUris": [
    "https://bsky.app/profile/bsky.app/post/POST_RKEY"
  ],
  "interactionTypes": [
    "likes",
    "reposts",
    "quotes"
  ],
  "maxItems": 500,
  "country": "US"
}
```

#### Search actors

```json
{
  "mode": "searchActors",
  "searchTerms": [
    "open source"
  ],
  "maxItems": 100,
  "country": "US"
}
```

#### Accounts followed by an actor

```json
{
  "mode": "follows",
  "actors": [
    "bsky.app"
  ],
  "maxItems": 500,
  "country": "US"
}
```

#### Lists created by an actor

```json
{
  "mode": "lists",
  "actors": [
    "bsky.app"
  ],
  "maxItems": 100,
  "country": "US"
}
```

#### Members of a public list

```json
{
  "mode": "listItems",
  "listUris": [
    "at://did:plc:EXAMPLE/app.bsky.graph.list/LIST_RKEY"
  ],
  "maxItems": 500,
  "country": "US"
}
```

#### Feed generators created by an actor

```json
{
  "mode": "actorFeeds",
  "actors": [
    "bsky.app"
  ],
  "maxItems": 100,
  "country": "US"
}
```

#### Posts from a custom feed

```json
{
  "mode": "customFeed",
  "feedUris": [
    "at://did:plc:EXAMPLE/app.bsky.feed.generator/FEED_RKEY"
  ],
  "maxItems": 100,
  "country": "US"
}
```

#### Popular public feeds

```json
{
  "mode": "popularFeeds",
  "maxItems": 100,
  "country": "US"
}
```

#### Public trends

```json
{
  "mode": "trends",
  "maxItems": 100,
  "country": "US"
}
```

#### Suggested follows for an actor

```json
{
  "mode": "suggestedFollows",
  "actors": [
    "bsky.app"
  ],
  "maxItems": 100,
  "country": "US"
}
```

#### Auto-detect mixed public URLs

```json
{
  "mode": "auto",
  "startUrls": [
    "https://bsky.app/profile/bsky.app",
    "https://bsky.app/profile/bsky.app/post/POST_RKEY"
  ],
  "country": "US"
}
```

The examples cover every supported mode. One dataset row represents a profile, post, interaction, list, feed, trend, or repository record and always uses the same 63-field top-level contract.

### Complete output examples

Every result row contains exactly 63 top-level fields. The same complete key set makes mixed result types predictable in JSON exports and keeps every field visible in the single Results view.

#### Complete `profile` row — 63 top-level fields

```json
{
  "recordType": "profile",
  "sourceMode": "profiles",
  "sourceTarget": "example-target",
  "sourceUrl": "https://example.com/public-result",
  "sourceEndpoints": [],
  "did": "example-id",
  "handle": null,
  "displayName": "Example public record",
  "description": "Example public content",
  "profileUrl": "https://example.com/public-result",
  "avatarUrl": "https://cdn.example.com/image.jpg",
  "bannerUrl": "https://cdn.example.com/image.jpg",
  "followersCount": 0,
  "followsCount": 0,
  "postsCount": 0,
  "indexedAt": "2026-08-13T12:00:00Z",
  "createdAt": "2026-08-13T12:00:00Z",
  "labels": [],
  "verification": {},
  "uri": "example-id",
  "cid": "example-id",
  "postUrl": "https://example.com/public-result",
  "text": "Example public content",
  "languages": [],
  "replyCount": 0,
  "repostCount": 0,
  "likeCount": 0,
  "quoteCount": 0,
  "author": {},
  "embed": {},
  "facets": [],
  "reply": {},
  "threadRootUri": null,
  "threadDepth": 0,
  "interactionType": null,
  "targetUri": null,
  "edgeActor": {},
  "searchTerm": null,
  "listUri": null,
  "listName": "Example public record",
  "listPurpose": null,
  "listAvatar": "https://cdn.example.com/image.jpg",
  "feedUri": null,
  "feedName": "Example public record",
  "feedDescription": null,
  "feedCreator": {},
  "trendTopic": null,
  "trendDisplayName": null,
  "trendDescription": null,
  "trendLink": "https://example.com/public-result",
  "trendStatus": null,
  "trendPostCount": 0,
  "repoDid": null,
  "collection": null,
  "recordKey": "example-id",
  "pds": "https://example.com/public-result",
  "recordValue": {},
  "isPartial": false,
  "monitorStatus": null,
  "changedFields": [],
  "previousCapturedAt": "2026-08-13T12:00:00Z",
  "capturedAt": "2026-08-13T12:00:00Z",
  "raw": {}
}
```

#### Complete `post` row — 63 top-level fields

```json
{
  "recordType": "post",
  "sourceMode": "authorFeeds",
  "sourceTarget": "example-target",
  "sourceUrl": "https://example.com/public-result",
  "sourceEndpoints": [],
  "did": "example-id",
  "handle": null,
  "displayName": "Example public record",
  "description": "Example public content",
  "profileUrl": "https://example.com/public-result",
  "avatarUrl": "https://cdn.example.com/image.jpg",
  "bannerUrl": "https://cdn.example.com/image.jpg",
  "followersCount": 0,
  "followsCount": 0,
  "postsCount": 0,
  "indexedAt": "2026-08-13T12:00:00Z",
  "createdAt": "2026-08-13T12:00:00Z",
  "labels": [],
  "verification": {},
  "uri": "example-id",
  "cid": "example-id",
  "postUrl": "https://example.com/public-result",
  "text": "Example public content",
  "languages": [],
  "replyCount": 0,
  "repostCount": 0,
  "likeCount": 0,
  "quoteCount": 0,
  "author": {},
  "embed": {},
  "facets": [],
  "reply": {},
  "threadRootUri": null,
  "threadDepth": 0,
  "interactionType": null,
  "targetUri": null,
  "edgeActor": {},
  "searchTerm": null,
  "listUri": null,
  "listName": "Example public record",
  "listPurpose": null,
  "listAvatar": "https://cdn.example.com/image.jpg",
  "feedUri": null,
  "feedName": "Example public record",
  "feedDescription": null,
  "feedCreator": {},
  "trendTopic": null,
  "trendDisplayName": null,
  "trendDescription": null,
  "trendLink": "https://example.com/public-result",
  "trendStatus": null,
  "trendPostCount": 0,
  "repoDid": null,
  "collection": null,
  "recordKey": "example-id",
  "pds": "https://example.com/public-result",
  "recordValue": {},
  "isPartial": false,
  "monitorStatus": null,
  "changedFields": [],
  "previousCapturedAt": "2026-08-13T12:00:00Z",
  "capturedAt": "2026-08-13T12:00:00Z",
  "raw": {}
}
```

#### Complete `interaction` row — 63 top-level fields

```json
{
  "recordType": "interaction",
  "sourceMode": "postInteractions",
  "sourceTarget": "example-target",
  "sourceUrl": "https://example.com/public-result",
  "sourceEndpoints": [],
  "did": "example-id",
  "handle": null,
  "displayName": "Example public record",
  "description": "Example public content",
  "profileUrl": "https://example.com/public-result",
  "avatarUrl": "https://cdn.example.com/image.jpg",
  "bannerUrl": "https://cdn.example.com/image.jpg",
  "followersCount": 0,
  "followsCount": 0,
  "postsCount": 0,
  "indexedAt": "2026-08-13T12:00:00Z",
  "createdAt": "2026-08-13T12:00:00Z",
  "labels": [],
  "verification": {},
  "uri": "example-id",
  "cid": "example-id",
  "postUrl": "https://example.com/public-result",
  "text": "Example public content",
  "languages": [],
  "replyCount": 0,
  "repostCount": 0,
  "likeCount": 0,
  "quoteCount": 0,
  "author": {},
  "embed": {},
  "facets": [],
  "reply": {},
  "threadRootUri": null,
  "threadDepth": 0,
  "interactionType": null,
  "targetUri": null,
  "edgeActor": {},
  "searchTerm": null,
  "listUri": null,
  "listName": "Example public record",
  "listPurpose": null,
  "listAvatar": "https://cdn.example.com/image.jpg",
  "feedUri": null,
  "feedName": "Example public record",
  "feedDescription": null,
  "feedCreator": {},
  "trendTopic": null,
  "trendDisplayName": null,
  "trendDescription": null,
  "trendLink": "https://example.com/public-result",
  "trendStatus": null,
  "trendPostCount": 0,
  "repoDid": null,
  "collection": null,
  "recordKey": "example-id",
  "pds": "https://example.com/public-result",
  "recordValue": {},
  "isPartial": false,
  "monitorStatus": null,
  "changedFields": [],
  "previousCapturedAt": "2026-08-13T12:00:00Z",
  "capturedAt": "2026-08-13T12:00:00Z",
  "raw": {}
}
```

#### Complete `list` row — 63 top-level fields

```json
{
  "recordType": "list",
  "sourceMode": "lists",
  "sourceTarget": "example-target",
  "sourceUrl": "https://example.com/public-result",
  "sourceEndpoints": [],
  "did": "example-id",
  "handle": null,
  "displayName": "Example public record",
  "description": "Example public content",
  "profileUrl": "https://example.com/public-result",
  "avatarUrl": "https://cdn.example.com/image.jpg",
  "bannerUrl": "https://cdn.example.com/image.jpg",
  "followersCount": 0,
  "followsCount": 0,
  "postsCount": 0,
  "indexedAt": "2026-08-13T12:00:00Z",
  "createdAt": "2026-08-13T12:00:00Z",
  "labels": [],
  "verification": {},
  "uri": "example-id",
  "cid": "example-id",
  "postUrl": "https://example.com/public-result",
  "text": "Example public content",
  "languages": [],
  "replyCount": 0,
  "repostCount": 0,
  "likeCount": 0,
  "quoteCount": 0,
  "author": {},
  "embed": {},
  "facets": [],
  "reply": {},
  "threadRootUri": null,
  "threadDepth": 0,
  "interactionType": null,
  "targetUri": null,
  "edgeActor": {},
  "searchTerm": null,
  "listUri": null,
  "listName": "Example public record",
  "listPurpose": null,
  "listAvatar": "https://cdn.example.com/image.jpg",
  "feedUri": null,
  "feedName": "Example public record",
  "feedDescription": null,
  "feedCreator": {},
  "trendTopic": null,
  "trendDisplayName": null,
  "trendDescription": null,
  "trendLink": "https://example.com/public-result",
  "trendStatus": null,
  "trendPostCount": 0,
  "repoDid": null,
  "collection": null,
  "recordKey": "example-id",
  "pds": "https://example.com/public-result",
  "recordValue": {},
  "isPartial": false,
  "monitorStatus": null,
  "changedFields": [],
  "previousCapturedAt": "2026-08-13T12:00:00Z",
  "capturedAt": "2026-08-13T12:00:00Z",
  "raw": {}
}
```

#### Complete `feed` row — 63 top-level fields

```json
{
  "recordType": "feed",
  "sourceMode": "actorFeeds",
  "sourceTarget": "example-target",
  "sourceUrl": "https://example.com/public-result",
  "sourceEndpoints": [],
  "did": "example-id",
  "handle": null,
  "displayName": "Example public record",
  "description": "Example public content",
  "profileUrl": "https://example.com/public-result",
  "avatarUrl": "https://cdn.example.com/image.jpg",
  "bannerUrl": "https://cdn.example.com/image.jpg",
  "followersCount": 0,
  "followsCount": 0,
  "postsCount": 0,
  "indexedAt": "2026-08-13T12:00:00Z",
  "createdAt": "2026-08-13T12:00:00Z",
  "labels": [],
  "verification": {},
  "uri": "example-id",
  "cid": "example-id",
  "postUrl": "https://example.com/public-result",
  "text": "Example public content",
  "languages": [],
  "replyCount": 0,
  "repostCount": 0,
  "likeCount": 0,
  "quoteCount": 0,
  "author": {},
  "embed": {},
  "facets": [],
  "reply": {},
  "threadRootUri": null,
  "threadDepth": 0,
  "interactionType": null,
  "targetUri": null,
  "edgeActor": {},
  "searchTerm": null,
  "listUri": null,
  "listName": "Example public record",
  "listPurpose": null,
  "listAvatar": "https://cdn.example.com/image.jpg",
  "feedUri": null,
  "feedName": "Example public record",
  "feedDescription": null,
  "feedCreator": {},
  "trendTopic": null,
  "trendDisplayName": null,
  "trendDescription": null,
  "trendLink": "https://example.com/public-result",
  "trendStatus": null,
  "trendPostCount": 0,
  "repoDid": null,
  "collection": null,
  "recordKey": "example-id",
  "pds": "https://example.com/public-result",
  "recordValue": {},
  "isPartial": false,
  "monitorStatus": null,
  "changedFields": [],
  "previousCapturedAt": "2026-08-13T12:00:00Z",
  "capturedAt": "2026-08-13T12:00:00Z",
  "raw": {}
}
```

#### Complete `trend` row — 63 top-level fields

```json
{
  "recordType": "trend",
  "sourceMode": "trends",
  "sourceTarget": "example-target",
  "sourceUrl": "https://example.com/public-result",
  "sourceEndpoints": [],
  "did": "example-id",
  "handle": null,
  "displayName": "Example public record",
  "description": "Example public content",
  "profileUrl": "https://example.com/public-result",
  "avatarUrl": "https://cdn.example.com/image.jpg",
  "bannerUrl": "https://cdn.example.com/image.jpg",
  "followersCount": 0,
  "followsCount": 0,
  "postsCount": 0,
  "indexedAt": "2026-08-13T12:00:00Z",
  "createdAt": "2026-08-13T12:00:00Z",
  "labels": [],
  "verification": {},
  "uri": "example-id",
  "cid": "example-id",
  "postUrl": "https://example.com/public-result",
  "text": "Example public content",
  "languages": [],
  "replyCount": 0,
  "repostCount": 0,
  "likeCount": 0,
  "quoteCount": 0,
  "author": {},
  "embed": {},
  "facets": [],
  "reply": {},
  "threadRootUri": null,
  "threadDepth": 0,
  "interactionType": null,
  "targetUri": null,
  "edgeActor": {},
  "searchTerm": null,
  "listUri": null,
  "listName": "Example public record",
  "listPurpose": null,
  "listAvatar": "https://cdn.example.com/image.jpg",
  "feedUri": null,
  "feedName": "Example public record",
  "feedDescription": null,
  "feedCreator": {},
  "trendTopic": null,
  "trendDisplayName": null,
  "trendDescription": null,
  "trendLink": "https://example.com/public-result",
  "trendStatus": null,
  "trendPostCount": 0,
  "repoDid": null,
  "collection": null,
  "recordKey": "example-id",
  "pds": "https://example.com/public-result",
  "recordValue": {},
  "isPartial": false,
  "monitorStatus": null,
  "changedFields": [],
  "previousCapturedAt": "2026-08-13T12:00:00Z",
  "capturedAt": "2026-08-13T12:00:00Z",
  "raw": {}
}
```

#### Complete `repoRecord` row — 63 top-level fields

```json
{
  "recordType": "repoRecord",
  "sourceMode": "repoRecords",
  "sourceTarget": "example-target",
  "sourceUrl": "https://example.com/public-result",
  "sourceEndpoints": [],
  "did": "example-id",
  "handle": null,
  "displayName": "Example public record",
  "description": "Example public content",
  "profileUrl": "https://example.com/public-result",
  "avatarUrl": "https://cdn.example.com/image.jpg",
  "bannerUrl": "https://cdn.example.com/image.jpg",
  "followersCount": 0,
  "followsCount": 0,
  "postsCount": 0,
  "indexedAt": "2026-08-13T12:00:00Z",
  "createdAt": "2026-08-13T12:00:00Z",
  "labels": [],
  "verification": {},
  "uri": "example-id",
  "cid": "example-id",
  "postUrl": "https://example.com/public-result",
  "text": "Example public content",
  "languages": [],
  "replyCount": 0,
  "repostCount": 0,
  "likeCount": 0,
  "quoteCount": 0,
  "author": {},
  "embed": {},
  "facets": [],
  "reply": {},
  "threadRootUri": null,
  "threadDepth": 0,
  "interactionType": null,
  "targetUri": null,
  "edgeActor": {},
  "searchTerm": null,
  "listUri": null,
  "listName": "Example public record",
  "listPurpose": null,
  "listAvatar": "https://cdn.example.com/image.jpg",
  "feedUri": null,
  "feedName": "Example public record",
  "feedDescription": null,
  "feedCreator": {},
  "trendTopic": null,
  "trendDisplayName": null,
  "trendDescription": null,
  "trendLink": "https://example.com/public-result",
  "trendStatus": null,
  "trendPostCount": 0,
  "repoDid": null,
  "collection": null,
  "recordKey": "example-id",
  "pds": "https://example.com/public-result",
  "recordValue": {},
  "isPartial": false,
  "monitorStatus": null,
  "changedFields": [],
  "previousCapturedAt": "2026-08-13T12:00:00Z",
  "capturedAt": "2026-08-13T12:00:00Z",
  "raw": {}
}
```

### What data can you extract?

| Category | Fields |
| --- | --- |
| Source and capture | `recordType`, `sourceMode`, `sourceTarget`, `sourceUrl`, `sourceEndpoints`, `capturedAt` |
| Profile identity | `did`, `handle`, `displayName`, `description`, `profileUrl`, `avatarUrl`, `bannerUrl`, `indexedAt`, `createdAt`, `labels`, `verification` |
| Profile metrics | `followersCount`, `followsCount`, `postsCount` |
| Posts and threads | `uri`, `cid`, `postUrl`, `text`, `languages`, `replyCount`, `repostCount`, `likeCount`, `quoteCount`, `author`, `embed`, `facets`, `reply`, `threadRootUri`, `threadDepth` |
| Social interactions | `interactionType`, `targetUri`, `edgeActor` |
| Search provenance | `searchTerm` |
| Lists | `listUri`, `listName`, `listPurpose`, `listAvatar` |
| Feeds | `feedUri`, `feedName`, `feedDescription`, `feedCreator` |
| Trends | `trendTopic`, `trendDisplayName`, `trendDescription`, `trendLink`, `trendStatus`, `trendPostCount` |
| Repository records | `repoDid`, `collection`, `recordKey`, `pds`, `recordValue` |
| Monitoring and diagnostics | `isPartial`, `monitorStatus`, `changedFields`, `previousCapturedAt`, `raw` |

Nested fields such as `labels`, `verification`, `author`, `embed`, `facets`, `reply`, `edgeActor`, `feedCreator`, `recordValue`, and optional `raw` retain the public AT Protocol object structure. Their nested keys and union variants are source-controlled and can change; the 63 top-level keys above are fixed by the Actor.

### Input parameters

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `mode` | `string` | No | `"authorFeeds"` | Select one of the 18 public Bluesky or AT Protocol workflows listed above. |
| `actors` | `string[]` | In actor-based modes | `["bsky.app"]` | Bluesky handles, DIDs, or profile URLs. |
| `postUris` | `string[]` | In post modes | `[]` | AT URIs or public `bsky.app` post URLs. |
| `listUris` | `string[]` | In `listItems` | `[]` | Public `at://` list URIs. |
| `feedUris` | `string[]` | In `customFeed` | `[]` | Public `at://` feed-generator URIs. |
| `searchTerms` | `string[]` | In search modes | `[]` | Queries for public post or actor search. |
| `startUrls` | `string[]` | In `auto` | `[]` | Mixed public profile or post URLs. |
| `maxItems` | `integer` | No | `100` | Maximum retained records per target or collection, from 1 to 100,000. |
| `maxPages` | `integer` | No | `20` | Maximum XRPC cursor pages per endpoint, from 1 to 1,000. |
| `searchSort` | `string` | No | `"latest"` | `latest` or `top` for public post search. |
| `language` | `string` | No | `""` | Optional BCP 47 language filter for post search. |
| `since` | `string` | No | `""` | Optional ISO date/timestamp lower bound for post search. |
| `until` | `string` | No | `""` | Optional ISO date/timestamp upper bound for post search. |
| `feedFilter` | `string` | No | `"posts_with_replies"` | `posts_with_replies`, `posts_no_replies`, `posts_with_media`, or `posts_and_author_threads`. |
| `threadDepth` | `integer` | No | `20` | Requested child depth for threads, from 0 to 1,000. |
| `parentHeight` | `integer` | No | `20` | Requested parent height for threads, from 0 to 1,000. |
| `interactionTypes` | `string[]` | No | `["likes", "reposts", "quotes"]` | Public relationship types extracted by `postInteractions`. |
| `collections` | `string[]` | In `repoRecords` | `["app.bsky.feed.post"]` | Public AT Protocol collections requested from each actor's PDS. |
| `maxConcurrency` | `integer` | No | `10` | Concurrent public targets, from 1 to 50. |
| `country` | `string` | No | `"US"` | Two-letter ISO country used for the internal residential proxy region. |
| `includeRaw` | `boolean` | No | `false` | Include the redacted public source object; increases dataset size. |
| `monitorMode` | `string` | No | `"off"` | `off`, `onlyNew`, or `newAndChanged`. |
| `monitorKey` | `string` | With monitoring | `"default"` | Stable comparison-state namespace for recurring runs. |
| `maxSessionRotations` | `integer` | No | `3` | Fresh residential sessions tried after blocks, from 1 to 6. |
| `requestTimeoutSecs` | `integer` | No | `45` | Per-request timeout in seconds, from 15 to 120. |

### Pay-per-event result types

| Event | Charged when |
| --- | --- |
| `profile-result` | One `profile` row is accepted by the Dataset. |
| `post-result` | One `post` row is accepted by the Dataset. |
| `interaction-result` | One `interaction` row is accepted by the Dataset. |
| `list-result` | One `list` row is accepted by the Dataset. |
| `feed-result` | One `feed` row is accepted by the Dataset. |
| `trend-result` | One `trend` row is accepted by the Dataset. |
| `repo-record-result` | One `repoRecord` row is accepted by the Dataset. |

The Actor does not emit a paid error event. Failed targets are counted by category in `RUN_SUMMARY`; successful targets continue. Actual event prices are shown on the Actor's Pricing tab.

### Use cases

#### Social listening and content research

Search public posts, collect author feeds, and analyze text, embeds, replies, reposts, likes, quotes, and thread structure.

#### Creator and network intelligence

Enrich profiles and export public follower, following, list, and interaction relationships for graph or audience analysis.

#### Feed and trend discovery

Catalog public custom feeds, popular feeds, suggested accounts, and current trend records.

#### AT Protocol research

Export public repository records with DID, collection, record key, PDS, CID, and complete public record values.

#### Data and automation pipelines

Send normalized rows to Google Sheets, Airtable, Make, Zapier, n8n, Airbyte, webhooks, or a data warehouse.

### Performance and cost

Direct HTTP generally uses substantially less memory and bandwidth than launching a browser, but source response size, retries, optional enrichment, raw objects, and pagination determine actual cost. Start with a small limit, inspect the Dataset and RUN\_SUMMARY, then scale. Lower concurrency is usually more reliable on stricter public sites.

### API usage

Replace `YOUR_USERNAME` with the publishing Apify username after publication:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/YOUR_USERNAME~bluesky-scraper/runs?token=APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "authorFeeds",
    "actors": ["bsky.app"],
    "maxItems": 100,
    "country": "US"
  }'
```

The request body is the same JSON used in Apify Console. Read results from the run's default Dataset or use the output link that opens `view=overview`.

### Best for / not for

**Best for:** public profiles and posts, threads, interactions, search, public graph data, lists, feeds, trends, and AT Protocol repository exports.

**Not for:** notifications, bookmarks, chats, private data, account writes, moderation actions, or endpoints that require an authenticated Bluesky session.

### Limits and good to know

Only anonymous public AppView, PLC, and PDS endpoints are used. Authenticated notifications, private data, writes, moderation actions, chat, and endpoints that reject anonymous traffic are outside scope. A row can be marked isPartial when a host stops later cursor pages.

A missing public value is returned as `null` or an empty array. One failed input does not create a frightening error row in Results. If every input fails, the run fails after writing diagnostic counts to RUN\_SUMMARY.

### Frequently asked questions

#### What input should I provide?

Depending on the mode, provide handles, DIDs, profile URLs, AT URIs, public post URLs, list or feed AT URIs, search terms, or public repository collection names.

#### How many results can I extract?

`maxItems` accepts 1-100,000 per input target or collection and `maxPages` accepts 1-1,000. Public endpoint limits, cursor exhaustion, moderation, and host availability can reduce the result count.

#### Can I process multiple inputs?

Yes. All target fields are arrays, and independent targets continue when one target or endpoint fails.

#### Can I schedule recurring runs?

Yes. Use Apify schedules and webhooks. For delta output, set `monitorMode` and reuse a stable `monitorKey` across runs.

#### Does this Actor open a browser?

No. Runtime extraction uses direct HTTP only and contains no Playwright, Selenium, Chromium, or browser installation.

#### Do I need an account or cookies?

No. The supported modes use public pages and anonymous endpoints. Cookies or authorization values from research captures are never embedded in the release.

#### Do I need to configure a proxy?

No. On Apify, the Actor creates a Residential Proxy configuration internally and does not expose proxy settings in Input. Local developers may privately point the documented test-only environment variable at a proxy file; that variable is not an Actor input and is ignored on the platform.

#### Why are some fields empty?

The single Results view covers every result type. Fields that do not apply to a row remain empty, while the complete key set is preserved in JSON.

### Responsible use

Collect only public Bluesky data you are permitted to process. Respect applicable law, privacy rights, platform terms, rate limits, and intellectual-property rights. This Actor is not affiliated with or endorsed by Bluesky.

### Support

For a reproducible issue, include the Apify run ID, mode, a non-sensitive public target, expected result, and actual result. Never send account credentials, cookies, access tokens, proxy passwords, or private content.

### Local development

For local read-only smoke tests only, `BLUESKY_TEST_PROXY_FILE` may point to a private file containing one `login:password@host:port` proxy per line. The file is never read on Apify and must not be committed.

# Actor input Schema

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

Choose a public Bluesky or AT Protocol workflow.

## `actors` (type: `array`):

Bluesky handles, DIDs, or profile URLs for actor-based modes.

## `postUris` (type: `array`):

AT URIs or public bsky.app post URLs.

## `listUris` (type: `array`):

Public at:// list URIs.

## `feedUris` (type: `array`):

Public at:// custom feed generator URIs.

## `searchTerms` (type: `array`):

Queries for public post or actor search.

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

Public profile or post URLs for auto and post modes.

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

Maximum records retained for each input target or collection.

## `maxPages` (type: `integer`):

Maximum public XRPC cursor pages requested per endpoint.

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

Order returned by Bluesky post search.

## `language` (type: `string`):

Optional BCP 47 language filter for post search.

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

Optional ISO timestamp lower bound for post search.

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

Optional ISO timestamp upper bound for post search.

## `feedFilter` (type: `string`):

Bluesky author-feed filter value.

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

Maximum child depth requested from the thread endpoint.

## `parentHeight` (type: `integer`):

Maximum number of parent levels requested for a thread.

## `interactionTypes` (type: `array`):

Public likes, reposts, and quote-post relationships to extract.

## `collections` (type: `array`):

Public AT Protocol collections requested directly from the actor's PDS.

## `maxConcurrency` (type: `integer`):

Maximum public Bluesky targets processed at once.

## `country` (type: `string`):

Two-letter ISO country used as the public request region.

## `includeRaw` (type: `boolean`):

Add the complete public source object after cookie, authorization, token, and signature fields are redacted. Increases dataset size.

## `monitorMode` (type: `string`):

Optionally save only new records or new and changed records between named runs.

## `monitorKey` (type: `string`):

Stable namespace for comparison state. Use a different key for independent monitors.

## `maxSessionRotations` (type: `integer`):

Maximum fresh residential proxy sessions tried after blocks, limits, or challenges.

## `requestTimeoutSecs` (type: `integer`):

Maximum time in seconds for one public HTTP request.

## Actor input object example

```json
{
  "mode": "authorFeeds",
  "actors": [
    "bsky.app"
  ],
  "postUris": [],
  "listUris": [],
  "feedUris": [],
  "searchTerms": [],
  "startUrls": [],
  "maxItems": 100,
  "maxPages": 20,
  "searchSort": "latest",
  "language": "",
  "since": "",
  "until": "",
  "feedFilter": "posts_with_replies",
  "threadDepth": 20,
  "parentHeight": 20,
  "interactionTypes": [
    "likes",
    "reposts",
    "quotes"
  ],
  "collections": [
    "app.bsky.feed.post"
  ],
  "maxConcurrency": 10,
  "country": "US",
  "includeRaw": false,
  "monitorMode": "off",
  "monitorKey": "default",
  "maxSessionRotations": 3,
  "requestTimeoutSecs": 45
}
```

# Actor output Schema

## `dataset` (type: `string`):

All 63 fields in one complete Results table.

## `runSummary` (type: `string`):

Request, retry, failure, byte, result, and charged-event counts.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapingmonkey/bluesky-at-protocol-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("scrapingmonkey/bluesky-at-protocol-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 '{}' |
apify call scrapingmonkey/bluesky-at-protocol-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapingmonkey/bluesky-at-protocol-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/WBspav3DbpI4FT5n5/builds/LjCfuvuE2qCBoHJ5M/openapi.json
