# Bluesky Omni Scraper (`actorpilot/bluesky-scraper`) Actor

Extract posts, profiles, threads and followers from Bluesky via the official AT Protocol API. Search by keyword or hashtag, scrape author feeds, full threads and follower lists. No browser, no login. Export to JSON, CSV or Excel.

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

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-usage

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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, Threads & More

**Extract posts, profiles, threads, followers, and custom feeds from Bluesky** — the fast-growing decentralized social network built on the AT Protocol. No account required. No browser. No proxies. Pure API.

Try it now: click **Try for free** above.

---

### Why Bluesky Scraper?

Most Bluesky scrapers handle one use case. This Actor handles seven — and does it faster, cheaper, and more accurately than browser-based alternatives.

| ## | What makes it better | Why it matters |
|---|---|---|
| 1 | **7 scrape modes in one actor** | Search, author feed, thread, profile, followers, following, and custom feed. Competitors often need separate actors per mode. |
| 2 | **Direct AT Protocol API** | No headless browser, no proxies, no fragile HTML parsing. Pure API calls = faster runs, lower cost, higher reliability. |
| 3 | **Engagement rate auto-calculated** | In `authorFeed` mode, follower count is pre-fetched once and `engagementRate = (likes + reposts + quotes) / followers` is computed per post. No spreadsheet formulas needed. |
| 4 | **Structured hashtags and mentions via facets** | Tags and mentions are extracted from AT Protocol facets — machine-readable structured data, not regex on raw text. Always accurate, even for posts with special characters or non-Latin scripts. |
| 5 | **Custom feed generator support** | Scrape any public Bluesky algorithm (What's Hot, topic feeds, community feeds) by URI. Unique to Bluesky's open protocol. |
| 6 | **No login required** | 100% public API. No credentials, no session tokens, no risk of account bans. |
| 7 | **Stable AT URIs as post IDs** | Every post gets its `postId` as a permanent AT URI (e.g. `at://did:plc:.../...`). These decentralized identifiers never break when users change their handle. |
| 8 | **Smart rate-limit handling** | Automatically honors `Retry-After` headers from the API. No wasted retries, no failed runs. |
| 9 | **Full media extraction** | Image URLs, alt texts, and video thumbnails are extracted and indexed per post. |
| 10 | **MCP-ready** | Works out of the box with Claude Desktop via Apify's MCP server. Run natural-language Bluesky queries without writing a single line of code. |

---

### What does Bluesky Scraper do?

The Actor connects directly to the **AT Protocol public AppView API** (`api.bsky.app`) and supports seven distinct scrape modes:

| Mode | What it collects |
|---|---|
| `searchPosts` | Posts matching a keyword, phrase, or hashtag — with optional date range and language filters |
| `authorFeed` | All posts (and optionally reposts/replies) from one or more Bluesky accounts |
| `postThread` | A full post thread including all nested replies |
| `profile` | Detailed profile stats for one or more accounts |
| `followers` | The complete follower list of an account |
| `follows` | The complete following list of an account |
| `customFeed` | Any public Bluesky feed generator, identified by its AT URI |

All modes support automatic cursor-based pagination to collect results beyond the first page.

**Common use cases:**

- **Brand monitoring** — track mentions of your product, company, or topic in real time
- **Research and journalism** — snapshot public conversations with date-range filters
- **Influencer discovery** — surface high-engagement accounts via follower and engagement metrics
- **Academic datasets** — build labeled corpora for NLP, sentiment analysis, or network studies
- **Competitor intelligence** — monitor what your industry is discussing on Bluesky
- **Content curation** — find top posts on any hashtag ranked by engagement

---

### How to use Bluesky Scraper

1. Click **Try for free** to open the Actor input form
2. Select a **Scrape mode** from the dropdown (e.g. `searchPosts`)
3. Enter your **search query** (e.g. `#AI` or `climate change`) or one or more Bluesky handles
4. Set **Max items** to control how many results to collect
5. Optionally add date filters, a language filter, or a custom feed URI
6. Click **Start** and find your structured results in the **Output** tab — downloadable as JSON, CSV, or Excel

---

### Input

All fields are configured in the **Input** tab or via JSON.

| Field | Required | Description |
|---|---|---|
| `mode` | Yes | One of: `searchPosts`, `authorFeed`, `postThread`, `profile`, `followers`, `follows`, `customFeed` |
| `searchQuery` | For `searchPosts` | Keyword, phrase, or hashtag — e.g. `#AI` or `"machine learning"` |
| `handles` | For `authorFeed`, `profile`, `followers`, `follows` | One or more Bluesky handles, e.g. `["user.bsky.social"]` |
| `postUrl` | For `postThread` | Full post URL or AT URI |
| `feedUri` | For `customFeed` | AT URI of the feed generator, e.g. `at://did:plc:z72i7hd/app.bsky.feed.generator/whats-hot` |
| `maxItems` | No | Max items to collect (default: 100, `0` = unlimited; UI maximum: 10,000) |
| `searchSort` | No | `latest` or `top` (default: `latest`) |
| `searchSince` | No | Start date filter, e.g. `2024-01-01` |
| `searchUntil` | No | End date filter, e.g. `2024-12-31` |
| `searchLang` | No | ISO 639-1 language code, e.g. `en`, `de`, `ja` |
| `includeReplies` | No | Include replies in author feed (default: `false`) |
| `includeReposts` | No | Include reposts in author feed (default: `false`) |

**Example — hashtag search:**
```json
{
  "mode": "searchPosts",
  "searchQuery": "#AI",
  "searchSort": "latest",
  "searchLang": "en",
  "maxItems": 500
}
````

**Example — custom feed:**

```json
{
  "mode": "customFeed",
  "feedUri": "at://did:plc:z72i7hdynmchkltzmefcsowb/app.bsky.feed.generator/whats-hot",
  "maxItems": 100
}
```

***

### Output

Each item is pushed to the default Apify dataset. Download results as **JSON, CSV, HTML, or Excel** from the Storage tab.

**Example post output item:**

```json
{
  "postId": "at://did:plc:abc123/app.bsky.feed.post/3kwikpostabcde",
  "url": "https://bsky.app/profile/alice.bsky.social/post/3kwikpostabcde",
  "text": "Really enjoying the discourse around #AI safety this week.",
  "authorHandle": "alice.bsky.social",
  "authorDid": "did:plc:abc123",
  "authorDisplayName": "Alice",
  "authorFollowerCount": 3200,
  "authorFollowingCount": 410,
  "authorPostCount": 812,
  "authorAvatarUrl": "https://cdn.bsky.app/img/avatar/plain/did:plc:abc123/bafkreiabcdef@jpeg",
  "likeCount": 47,
  "repostCount": 12,
  "replyCount": 8,
  "quoteCount": 3,
  "engagementRate": 0.0192,
  "createdAt": "2024-11-15T14:22:30.000Z",
  "indexedAt": "2024-11-15T14:22:31.500Z",
  "lang": ["en"],
  "hasMedia": false,
  "mediaUrls": null,
  "mediaAltTexts": null,
  "externalUrl": null,
  "externalTitle": null,
  "inReplyToUri": null,
  "inReplyToUrl": null,
  "inReplyToHandle": null,
  "isRepost": false,
  "repostOf": null,
  "labels": null,
  "tags": ["AI"],
  "mentionedDids": [],
  "scrapedMode": "authorFeed"
}
```

**Example profile output item** (modes: `profile`, `followers`, `follows`):

```json
{
  "did": "did:plc:abc123",
  "handle": "alice.bsky.social",
  "displayName": "Alice",
  "description": "Researcher. Bluesky enthusiast.",
  "followerCount": 3200,
  "followingCount": 410,
  "postCount": 812,
  "avatarUrl": "https://cdn.bsky.app/img/avatar/plain/did:plc:abc123/bafkreiabcdef@jpeg",
  "bannerUrl": null,
  "createdAt": "2023-05-01T10:00:00.000Z",
  "indexedAt": "2024-01-15T08:30:00.000Z",
  "labels": [],
  "scrapedMode": "profile"
}
```

***

### Data table

#### Post fields (modes: `searchPosts`, `authorFeed`, `postThread`, `customFeed`)

| Field | Type | Description |
|---|---|---|
| `postId` | string | Permanent AT URI for the post (e.g. `at://did:plc:.../app.bsky.feed.post/...`) |
| `url` | string | Public bsky.app URL |
| `text` | string | null | Full post text |
| `authorHandle` | string | Author's Bluesky handle |
| `authorDid` | string | Author's decentralized identifier |
| `authorDisplayName` | string | null | Author's display name |
| `authorFollowerCount` | integer | null | Follower count at scrape time. `null` in `searchPosts` mode — the search API returns minimal author objects without stats. |
| `authorFollowingCount` | integer | null | Following count. `null` in `searchPosts` mode (same reason). |
| `authorPostCount` | integer | null | Total post count. `null` in `searchPosts` mode (same reason). |
| `authorAvatarUrl` | string | null | Avatar image URL. `null` in `searchPosts` mode (same reason). |
| `likeCount` | integer | Number of likes |
| `repostCount` | integer | Number of reposts |
| `replyCount` | integer | Number of replies |
| `quoteCount` | integer | Number of quote posts |
| `engagementRate` | float | null | `(likes + reposts + quotes) / authorFollowerCount`. Populated in `authorFeed` mode only; `null` in other modes. |
| `createdAt` | string | null | ISO 8601 creation timestamp |
| `indexedAt` | string | null | ISO 8601 timestamp when the post was indexed by Bluesky |
| `lang` | string\[] | null | Detected language codes |
| `hasMedia` | boolean | `true` if the post contains images or video |
| `mediaUrls` | string\[] | null | Image or video thumbnail URLs |
| `mediaAltTexts` | (string | null)\[] | null | Alt text per image in the same order as `mediaUrls`; individual entries may be `null` if no alt text was provided |
| `externalUrl` | string | null | Embedded link card URL |
| `externalTitle` | string | null | Embedded link card title |
| `inReplyToUri` | string | null | Parent post AT URI if this is a reply |
| `inReplyToUrl` | string | null | Parent post public URL if this is a reply |
| `inReplyToHandle` | string | null | Parent post author handle. `null` in `searchPosts` mode (parent author not embedded in search results). |
| `isRepost` | boolean | `true` if this item is a repost |
| `repostOf` | string | null | AT URI of the original post if `isRepost` is `true`; otherwise `null` |
| `labels` | string\[] | null | Moderation labels applied to the post |
| `tags` | string\[] | Hashtags extracted from AT Protocol facets (empty array if none) |
| `mentionedDids` | string\[] | DIDs of accounts mentioned in the post, extracted from facets (empty array if none) |
| `scrapedMode` | string | The Actor mode that produced this item |

#### Profile fields (modes: `profile`, `followers`, `follows`)

| Field | Type | Description |
|---|---|---|
| `did` | string | Decentralized identifier of the account |
| `handle` | string | Bluesky handle (e.g. `user.bsky.social`) |
| `displayName` | string | null | Account display name |
| `description` | string | null | Bio / profile description |
| `followerCount` | integer | null | Number of followers |
| `followingCount` | integer | null | Number of accounts followed |
| `postCount` | integer | null | Total post count |
| `avatarUrl` | string | null | Profile picture URL |
| `bannerUrl` | string | null | Banner image URL |
| `createdAt` | string | null | Account creation timestamp |
| `indexedAt` | string | null | Timestamp when indexed by Bluesky |
| `labels` | string\[] | null | Moderation labels applied to the account |
| `scrapedMode` | string | The Actor mode that produced this item |

***

### Pricing / Cost estimation

This Actor uses Apify's pay-per-event pricing. Typical costs:

- **Small run (100 posts)**: ~$0.01–$0.05
- **Medium run (1,000 posts)**: ~$0.10–$0.30
- **Large run (10,000 posts)**: ~$1.00–$2.00

New Apify accounts receive a **free tier** with monthly compute units included. Most small research tasks run entirely for free.

***

### Use with Claude Desktop / Cursor / VS Code (via Apify MCP)

Query Bluesky **interactively from Claude Desktop** without writing any code — ideal for ad-hoc research and conversational analysis. This Actor is available as an MCP tool through **Apify's hosted MCP server**, so everything runs in the cloud. No local setup required.

#### What you need

- An [Apify account](https://apify.com) (free tier available)
- Your **Apify API token** (found under Settings → Integrations)

#### Setup (one-time)

Add the following to your `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "apify": {
      "command": "npx",
      "args": ["-y", "@apify/actors-mcp-server"],
      "env": {
        "APIFY_TOKEN": "your_apify_api_token_here"
      }
    }
  }
}
```

Config file location:

- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`

Restart Claude Desktop — the Bluesky Scraper will appear as an available tool in the chat (hammer icon). When prompting Claude, mention the Actor by name so it picks the right tool.

#### Example prompts

> "Search for the 20 most recent posts about #climatepolicy in English and summarize the main arguments."

> "Show me the last 10 posts from @bsky.app and tell me what topics they cover."

> "Fetch the full reply thread for this post: https://bsky.app/profile/user.bsky.social/post/3abc123"

> "Find the top 50 followers of @atproto.com and list their display names and follower counts."

> "Scrape the What's Hot feed and tell me the top 5 trending topics right now."

***

### Tips and advanced options

- **Date range filtering** (`searchSince` / `searchUntil`) narrows search results significantly and reduces unnecessary API calls for historical research.
- **Language filtering** (`searchLang`) is especially useful for multilingual topics like `#AI` — use `en` for English-only results.
- **Author feed mode** with `includeReplies: false` (default) produces cleaner top-level post datasets without conversation noise.
- **Thread mode** is ideal for journalists and researchers who need the full reply context for a specific post.
- **Engagement rate** (`engagementRate`) is only populated in `authorFeed` mode because follower count requires a separate profile lookup — this is done once per handle and cached for the entire run.
- **Custom feed URIs** can be found in the Bluesky app: open any feed, tap the three-dot menu, and copy the link. The AT URI appears in the share URL.
- Set `maxItems: 0` for unlimited scraping — use with care on large accounts or popular hashtags.

***

### FAQ, disclaimers, and support

**Is scraping Bluesky legal?**
This Actor accesses only the public AT Protocol API — the same API used by official Bluesky clients. All data collected is publicly available. You remain responsible for complying with Bluesky's Terms of Service and applicable data protection regulations (GDPR, CCPA, etc.) in your jurisdiction.

**Can I scrape private accounts or DMs?**
No. This Actor only accesses public data via the public AppView API. Private accounts and direct messages are not accessible.

**Why are some fields `null` in `searchPosts` mode?**
Bluesky's search API returns minimal author objects that do not include follower/following/post counts or avatar URLs. Fields like `authorFollowerCount`, `authorFollowingCount`, `authorPostCount`, and `authorAvatarUrl` are `null` for search results. Use `authorFeed` mode if you need full author stats.

**What rate limits apply?**
The AT Protocol AppView API has generous public rate limits. The Actor handles rate-limit responses (HTTP 429) automatically by honoring the `Retry-After` header — no run failures due to throttling.

**I need a custom feature or bulk data pipeline.**
Open an issue on the Issues tab or contact us via the Apify platform — custom solutions are available.

**Known limitations**

- Search result counts may be approximate; the AT Protocol API does not guarantee exact pagination totals
- The `searchUntil` / `searchSince` date parameters may occasionally return slightly out-of-range results — this is known AT Protocol behavior
- Video content is supported (thumbnail URL extracted) but full video file download is not included

# Actor input Schema

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

Choose a scrape mode. Each mode requires different settings below.

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

Keyword or hashtag to search for. Examples: 'climate change', '#AI', 'OpenAI lang:en'. Bluesky search syntax is supported.

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

Sort search results by newest first, or by most likes and reposts. Applies to: searchPosts

## `searchSince` (type: `string`):

Only return posts on or after this date. Format: YYYY-MM-DD, e.g. 2024-01-15. Leave empty for no lower limit. Applies to: searchPosts

## `searchUntil` (type: `string`):

Only return posts on or before this date. Format: YYYY-MM-DD, e.g. 2024-12-31. Leave empty for no upper limit. Applies to: searchPosts

## `searchLang` (type: `string`):

Only return posts in a specific language. Use a two-letter ISO 639-1 code: 'en' for English, 'de' for German, 'fr' for French, 'es' for Spanish, 'ja' for Japanese. Leave empty for all languages. Applies to: searchPosts

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

Enter Bluesky handles without the @ symbol. Both formats work: 'username.bsky.social' or a custom domain like 'nytimes.com'. Multiple handles are processed in sequence.

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

Also collect posts where this account replied to someone. Disabled by default — only top-level posts are returned. Applies to: authorFeed

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

Also collect posts that this account reposted from others. Disabled by default. Applies to: authorFeed

## `postUrl` (type: `string`):

Paste the URL of any Bluesky post directly from your browser address bar. Example: 'https://bsky.app/profile/username.bsky.social/post/abc123'. AT URIs (at://...) are also accepted. Applies to: postThread

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

The AT URI of a Bluesky feed generator. How to find it: (1) Open any feed on bsky.app, click '...' → 'Share feed' and copy the link — then paste the at:// part. (2) Or browse and discover feeds at skyfeed.app. Only public feeds work without login. Example: at://did:plc:.../app.bsky.feed.generator/whats-hot. Applies to: customFeed

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

Maximum number of results to collect. Set to 0 to collect everything available — warning: this can take a very long time and generate high costs for popular accounts or broad search queries. Tip: start with 100 to test your settings first.

## Actor input object example

```json
{
  "mode": "searchPosts",
  "searchQuery": "#AI",
  "searchSort": "latest",
  "searchLang": "en",
  "handles": [
    "bsky.app"
  ],
  "includeReplies": false,
  "includeReposts": false,
  "postUrl": "https://bsky.app/profile/pfrazee.com/post/3mnsxzydov22d",
  "feedUri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot",
  "maxItems": 100
}
```

# Actor output Schema

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

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

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

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchLang": "en",
    "postUrl": "https://bsky.app/profile/pfrazee.com/post/3mnsxzydov22d",
    "feedUri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot",
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("actorpilot/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 = {
    "searchLang": "en",
    "postUrl": "https://bsky.app/profile/pfrazee.com/post/3mnsxzydov22d",
    "feedUri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot",
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("actorpilot/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 '{
  "searchLang": "en",
  "postUrl": "https://bsky.app/profile/pfrazee.com/post/3mnsxzydov22d",
  "feedUri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot",
  "maxItems": 100
}' |
apify call actorpilot/bluesky-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Bluesky Omni Scraper",
        "description": "Extract posts, profiles, threads and followers from Bluesky via the official AT Protocol API. Search by keyword or hashtag, scrape author feeds, full threads and follower lists. No browser, no login. Export to JSON, CSV or Excel.",
        "version": "0.1",
        "x-build-id": "FgRZMfmev6uuCbWcC"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/actorpilot~bluesky-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-actorpilot-bluesky-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/actorpilot~bluesky-scraper/runs": {
            "post": {
                "operationId": "runs-sync-actorpilot-bluesky-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/actorpilot~bluesky-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-actorpilot-bluesky-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "mode"
                ],
                "properties": {
                    "mode": {
                        "title": "What do you want to scrape?",
                        "enum": [
                            "searchPosts",
                            "authorFeed",
                            "postThread",
                            "profile",
                            "followers",
                            "follows",
                            "customFeed"
                        ],
                        "type": "string",
                        "description": "Choose a scrape mode. Each mode requires different settings below.",
                        "default": "searchPosts"
                    },
                    "searchQuery": {
                        "title": "Search query",
                        "minLength": 1,
                        "type": "string",
                        "description": "Keyword or hashtag to search for. Examples: 'climate change', '#AI', 'OpenAI lang:en'. Bluesky search syntax is supported.",
                        "default": "#AI"
                    },
                    "searchSort": {
                        "title": "Sort results by",
                        "enum": [
                            "latest",
                            "top"
                        ],
                        "type": "string",
                        "description": "Sort search results by newest first, or by most likes and reposts. Applies to: searchPosts",
                        "default": "latest"
                    },
                    "searchSince": {
                        "title": "From date",
                        "pattern": "^\\d{4}-\\d{2}-\\d{2}(T[0-9:.Z+-]*)?$",
                        "type": "string",
                        "description": "Only return posts on or after this date. Format: YYYY-MM-DD, e.g. 2024-01-15. Leave empty for no lower limit. Applies to: searchPosts"
                    },
                    "searchUntil": {
                        "title": "To date",
                        "pattern": "^\\d{4}-\\d{2}-\\d{2}(T[0-9:.Z+-]*)?$",
                        "type": "string",
                        "description": "Only return posts on or before this date. Format: YYYY-MM-DD, e.g. 2024-12-31. Leave empty for no upper limit. Applies to: searchPosts"
                    },
                    "searchLang": {
                        "title": "Language filter",
                        "type": "string",
                        "description": "Only return posts in a specific language. Use a two-letter ISO 639-1 code: 'en' for English, 'de' for German, 'fr' for French, 'es' for Spanish, 'ja' for Japanese. Leave empty for all languages. Applies to: searchPosts"
                    },
                    "handles": {
                        "title": "Bluesky handles",
                        "type": "array",
                        "description": "Enter Bluesky handles without the @ symbol. Both formats work: 'username.bsky.social' or a custom domain like 'nytimes.com'. Multiple handles are processed in sequence.",
                        "items": {
                            "type": "string",
                            "pattern": "^(?!@)[a-zA-Z0-9][-a-zA-Z0-9.]*\\.[a-zA-Z]{2,}$"
                        },
                        "default": [
                            "bsky.app"
                        ]
                    },
                    "includeReplies": {
                        "title": "Include replies",
                        "type": "boolean",
                        "description": "Also collect posts where this account replied to someone. Disabled by default — only top-level posts are returned. Applies to: authorFeed",
                        "default": false
                    },
                    "includeReposts": {
                        "title": "Include reposts",
                        "type": "boolean",
                        "description": "Also collect posts that this account reposted from others. Disabled by default. Applies to: authorFeed",
                        "default": false
                    },
                    "postUrl": {
                        "title": "Post URL (copy from bsky.app)",
                        "type": "string",
                        "description": "Paste the URL of any Bluesky post directly from your browser address bar. Example: 'https://bsky.app/profile/username.bsky.social/post/abc123'. AT URIs (at://...) are also accepted. Applies to: postThread"
                    },
                    "feedUri": {
                        "title": "Custom feed URI",
                        "type": "string",
                        "description": "The AT URI of a Bluesky feed generator. How to find it: (1) Open any feed on bsky.app, click '...' → 'Share feed' and copy the link — then paste the at:// part. (2) Or browse and discover feeds at skyfeed.app. Only public feeds work without login. Example: at://did:plc:.../app.bsky.feed.generator/whats-hot. Applies to: customFeed"
                    },
                    "maxItems": {
                        "title": "Max results",
                        "minimum": 0,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "Maximum number of results to collect. Set to 0 to collect everything available — warning: this can take a very long time and generate high costs for popular accounts or broad search queries. Tip: start with 100 to test your settings first.",
                        "default": 100
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
