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

Extract public Bluesky profiles, posts, search results, feeds, followers, and following through official AT Protocol APIs.

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

## Pricing

from $0.40 / 1,000 useful results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are 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/docs.md):

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

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.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/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

Extract public Bluesky profiles, posts, search results, feeds, followers, and following lists through the official AT Protocol APIs.

The Actor returns normalized JSON records in the default Apify dataset. It does not scrape the Bluesky website, run a browser, download media files, or access private content.

### Billing

The configured public price is:

```text
$0.0004 per saved useful result
$0.40 per 1,000 saved useful results
````

A billing event is attempted only when one of these useful records is saved:

```text
profile
post
search_post
feed_post
follower
following
```

These records are never billed:

```text
feed_metadata
run_summary
error
```

The Actor also does not bill for:

- AT Protocol requests or pagination requests
- retries
- filtered records
- duplicate records skipped during the run
- records rejected as malformed
- requested results that were not saved

Every dataset row includes:

```json
{
  "data": {
    "isBillable": true,
    "billingCategory": "billable_useful_result"
  }
}
```

Control rows use `isBillable=false` and `billingCategory="non_billable_control_record"`.

To prevent accidental overcharging, an Apify cloud run refuses to start unless all of the following are true:

- the pricing model is Pay Per Event
- the `useful-result` event price is exactly `$0.0004`
- the synthetic default dataset-item event is absent or exactly `$0`

This prevents useful rows from being charged at an unintended rate, prevents double charging, and prevents summary or error rows from being charged.

### Run scale and safety caps

`runMode` controls only result and page safety caps. It does not make a run free and it does not change the per-result price.

| Run mode | Maximum useful results | Maximum pages | Billing |
|---|---:|---:|---|
| `evaluation` | 100 | 3 | Per saved useful result |
| `scale` | 10,000 | 100 | Per saved useful result |

Requests above the selected cap are clamped and reported in `run_summary.warnings`.

`limit` is a maximum, not a guaranteed delivery count. Output can be lower when the upstream result set ends, filters remove records, `maxPages` is reached, a failure occurs, or the Apify run charge limit is reached.

### Operation-aware input contract

The Actor never switches operations or infers intent from unrelated fields. A meaningful operation-specific field supplied with the wrong `operation` fails validation before Bluesky client creation, route dispatch, useful-result dataset writes, or billing. For example, `{"operation":"posts","query":"Bitcoin"}` fails clearly because `query` belongs to `search`; it does not fetch the default `bsky.app` posts and produces zero useful-result charge attempts.

Operation-specific fields are enforced as follows:

| Field | Accepted operation(s) |
|---|---|
| `handle` | `profile`, `posts`, `connections` |
| `query`, `language`, `sort` | `search` |
| `feedUrl`, `feedAlias` | `feed` |
| `connectionType` | `connections` |
| `includeReplies`, `includeReposts`, `includeQuotes` | `posts` |
| `cursor` | `posts`, `search`, `feed`, `connections` |
| `since`, `until` | `posts`, `search`, `feed` |

The Apify form can automatically include harmless defaults such as `handle="bsky.app"`, `feedAlias="whats-hot"`, `connectionType="followers"`, `includeReplies=false`, `includeReposts=false`, and `includeQuotes=true`. Those defaults are accepted when irrelevant. Changing an irrelevant field to a meaningful non-default value is rejected instead of ignored. When `feedUrl` is provided, leave `feedAlias` omitted or at its harmless default.

### Supported operations

#### Profile

Fetch one public profile.

```json
{
  "operation": "profile",
  "handle": "bsky.app"
}
```

A profile run always applies a useful-result limit of one.

#### User posts

Fetch posts from one author feed.

```json
{
  "operation": "posts",
  "handle": "bsky.app",
  "limit": 100,
  "maxPages": 3,
  "runMode": "evaluation",
  "includeReplies": false,
  "includeReposts": false,
  "includeQuotes": true
}
```

#### Search posts

Search currently requires Bluesky authentication.

```json
{
  "operation": "search",
  "query": "atproto",
  "sort": "latest",
  "limit": 100,
  "language": "en",
  "blueskyIdentifier": "your-handle.bsky.social",
  "blueskyAppPassword": "your-dedicated-app-password"
}
```

Use a dedicated Bluesky app password, not your account password. Both credential fields must be supplied together.

Search ordering is explicit:

- `sort="latest"` is the default and requests the newest matching posts first.
- `sort="top"` requests Bluesky's relevance-ranked results. Bluesky controls that ranking, so `top` must not be described as simply the most-liked posts.

`limit=10` means the Actor saves up to the first 10 qualifying posts in the selected upstream ordering. It does not mean the oldest 10 posts or every historical match.

#### Feed

Fetch the built-in What's Hot feed:

```json
{
  "operation": "feed",
  "feedAlias": "whats-hot",
  "limit": 100
}
```

Fetch a specific feed using an AT URI or Bluesky feed URL:

```json
{
  "operation": "feed",
  "feedUrl": "https://bsky.app/profile/example.bsky.social/feed/news",
  "limit": 100
}
```

A feed run can include one non-billable `feed_metadata` row in addition to billable `feed_post` rows and the non-billable `run_summary`.

#### Followers or following

```json
{
  "operation": "connections",
  "handle": "bsky.app",
  "connectionType": "followers",
  "limit": 100
}
```

Set `connectionType` to `following` to fetch accounts followed by the target.

### Filters

`since` and `until` apply to post-shaped records from `posts`, `search`, and `feed`.

Timestamps must include a date, time, and explicit timezone:

```json
{
  "since": "2026-07-01T00:00:00Z",
  "until": "2026-07-07T23:59:59Z"
}
```

Accepted timestamps are normalized to UTC before use. Date-only and timezone-less values are rejected to avoid silent timezone assumptions. Upstream post timestamps are held to the same rule for filtering: malformed, timezone-less, or implausibly future timestamps are not used as `sortAt`; the Actor falls back to a valid `indexedAt` when available.

`language` is optional for search. Leave it blank when results should not be restricted by language.

`sort` applies only to search and accepts `latest` or `top`. The default is `latest`. The Apify form may include that default for other operations harmlessly, but `sort="top"` with a non-search operation is rejected before scraping or billing.

### Output format

Every row uses a common envelope:

```json
{
  "recordType": "post",
  "operation": "posts",
  "schemaVersion": "1.0",
  "scrapedAt": "2026-07-11T00:00:00Z",
  "sourceUrl": "https://bsky.app/profile/example.bsky.social/post/abc",
  "input": {
    "operation": "posts",
    "handle": "example.bsky.social",
    "limit": 100,
    "runMode": "evaluation"
  },
  "data": {
    "uri": "at://did:plc:example/app.bsky.feed.post/abc",
    "authorHandle": "example.bsky.social",
    "text": "Example post",
    "isBillable": true,
    "billingCategory": "billable_useful_result"
  }
}
```

Input metadata is allowlist-based. Credential fields and unknown custom fields are not copied into dataset rows.

### Run summary

The Actor attempts to store one non-billable `run_summary` row containing:

- requested and applied limits
- useful records saved
- pages fetched
- duplicates and filtered records skipped
- authentication mode
- run scale
- retry count
- billing attempts, confirmed charges, denials, and unconfigured events
- charge-limit status
- continuation cursor and resume safety status
- warnings and final status

`billingEventsCharged` is `null` when the platform does not provide a trustworthy confirmed charge count. A local run therefore does not pretend that zero is a verified platform charge.

### Pagination and resume behavior

Paginated operations can return `run_summary.data.nextCursor`.

AT Protocol cursors are page-level rather than item-level. If a run stops after saving only part of a page, resuming from the preserved page-start cursor can repeat rows already saved in the previous run. Check:

```text
resumeCursorStatus
resumeCursorNote
warnings
```

When no safe continuation cursor exists, the summary says so instead of presenting an unsafe cursor as exact.

### Authentication and privacy

Anonymous mode is used for supported public reads when credentials are omitted. Search requires authenticated Bluesky access.

#### Is it safe to provide Bluesky credentials?

It is reasonably safe when you follow the precautions below, but no credential handoff to a third-party Actor is risk-free. Use a dedicated, revocable Bluesky app password created specifically for this Actor. **Never provide your main Bluesky account password.**

Both `blueskyIdentifier` and `blueskyAppPassword` are declared as Apify secret inputs. Apify [encrypts secret input fields](https://docs.apify.com/platform/actors/development/actor-definition/input-schema/secret-input) before saving them to the run's default key-value store, including when a run is started through the API. Apify decrypts them only inside the Actor run so the Actor can authenticate with Bluesky.

The Actor's credential data flow is:

1. Apify receives the two secret input fields and stores encrypted values.
2. The running Actor receives the decrypted values in memory.
3. The Actor sends them to Bluesky through the AT Protocol client to create an authenticated session.
4. The Actor does not write the credentials to its dataset, run summary, error records, or status messages.
5. The plaintext values are discarded when the Actor process ends. The encrypted run input remains subject to the user's Apify storage retention settings.

The important trust boundary is step 2: the Actor code necessarily receives plaintext credentials during the run. The current implementation uses them only for Bluesky authentication and has automated and live leakage checks, but users should still limit the impact of any unexpected platform, dependency, or account compromise by using a dedicated app password.

#### Credential safety checklist

- Create a dedicated app password in Bluesky under **Settings → Privacy and security → App passwords**. Do not reuse it for another application.
- Provide both credential fields through the generated Apify input form or as secret fields in the JSON request body. Never place credentials in URLs, query strings, task names, dataset fields, source code, or ordinary log messages.
- If an automation platform, proxy, shell command, or API client starts the run, make sure it also protects request bodies and command history. Apify can encrypt the stored Actor input, but it cannot prevent another system from logging the request before it reaches Apify.
- Restrict access to the Apify account and API token that can start or inspect runs.
- Revoke the dedicated Bluesky app password after one-time use, when it is no longer needed, or immediately if you suspect exposure. Revocation stops future logins; do not assume it cancels a session that is already running.
- Delete the Apify run/default key-value store sooner if your retention requirements demand it. Apify documents the [retention behavior for key-value stores](https://docs.apify.com/storage/key-value-store#retention-period); until deletion or expiry, these two fields remain encrypted at rest.

#### What the Actor guarantees

- credential fields and unknown custom fields are excluded from dataset input metadata
- credential values are redacted from Actor-generated status and error output
- secret-bearing exception chains are suppressed before they reach the Actor boundary
- credentials are not stored in Actor source, result datasets, summaries, or control records
- search request parameters contain the query and filters, not credential fields; authentication is handled by the AT Protocol session

These guarantees cover this Actor's code and output. They do not cover a user's local machine, browser extensions, external automation tools, network proxies, compromised Apify or Bluesky accounts, or Bluesky's own authentication service.

### Validation behavior

The Actor rejects malformed input instead of silently changing the request. Examples include:

- unknown field names
- explicit `null` or empty integer and boolean values
- unsupported enum values
- non-object input
- incomplete credentials
- invalid timestamps
- malformed feed URLs or AT URIs

Useful records must contain stable identity fields before they can be saved and billed. Malformed upstream records fail closed rather than becoming blank billable rows.

### Scope and limitations

The Actor extracts public data exposed by Bluesky's AT Protocol services. Search ordering is requested with `sort="latest"` or `sort="top"`, but the exact ranking, result availability, feed contents, rate limits, and historical coverage are controlled by the upstream service and can change over time.

The Actor does not provide:

```text
private or blocked content extraction
browser or HTML scraping
firehose streaming
media downloads
persistent monitoring or change tracking
multi-account bulk jobs
raw SDK response output
sentiment or content classification
```

Use the extracted data in accordance with applicable law, Bluesky's terms, Apify's terms, and the privacy rights of the people represented in the data.

# Actor input Schema

## `operation` (type: `string`):

Choose which public Bluesky data to extract. The Actor never switches operations or infers intent from other fields.

## `handle` (type: `string`):

Used by profile, posts, and connections only. A non-default handle conflicts with search or feed and is rejected. Runtime maximum: 253 characters.

## `query` (type: `string`):

Required for search only. A non-empty query with another operation is rejected. Search requires Bluesky authentication. Runtime maximum: 512 characters.

## `limit` (type: `integer`):

Maximum billable useful-result rows to save. Evaluation mode caps this at 100; Scale mode caps it at 10,000. A lower output is possible when the upstream result set ends, filters skip records, maxPages is reached, or the run charge limit is reached.

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

Hard request-safety cap. Evaluation mode caps this at 3 pages; Scale mode caps it at 100 pages.

## `runMode` (type: `string`):

Controls result and page safety caps only. Both modes are billed at the configured useful-result price for each saved useful row. Evaluation allows up to 100 useful results and 3 pages; Scale allows up to 10,000 useful results and 100 pages.

## `cursor` (type: `string`):

Optional for posts, search, feed, and connections only. A cursor conflicts with profile and is rejected. Use a cursor from a previous run\_summary.nextCursor. Page-level resumes can repeat already saved rows after a partial-page stop; check run\_summary.resumeCursorStatus before resuming. Runtime maximum: 2,048 characters.

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

Optional inclusive timestamp filter for posts, search, and feed only. It conflicts with profile or connections. Include date, time, and an explicit timezone, for example 2026-07-04T00:00:00Z. Runtime maximum: 64 characters.

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

Optional inclusive timestamp filter for posts, search, and feed only. It conflicts with profile or connections. Include date, time, and an explicit timezone, for example 2026-07-05T00:00:00Z. Runtime maximum: 64 characters.

## `feedAlias` (type: `string`):

Used by feed only when feedUrl is not provided. The default What's Hot value is harmless for other operations; a non-default value is rejected outside feed or when feedUrl is also provided.

## `feedUrl` (type: `string`):

Optional for feed only. A non-empty feedUrl with another operation is rejected. Accepts an exact at:// feed generator URI or https://bsky.app/profile/<actor>/feed/<name> URL without query or fragment data. Runtime maximum: 2,048 characters.

## `connectionType` (type: `string`):

Used by connections only. The default followers value is harmless for other operations; choosing following with another operation is rejected.

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

Used by posts only. The default false value is harmless elsewhere; enabling it with another operation is rejected.

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

Used by posts only. The default false value is harmless elsewhere; enabling it with another operation is rejected.

## `includeQuotes` (type: `boolean`):

Used by posts only. The default true value is harmless elsewhere; disabling it with another operation is rejected.

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

Optional for search only, for example en, th, ja, or my. A non-empty language with another operation is rejected. Leave blank to avoid unintentionally filtering results. Runtime maximum: 35 characters.

## `sort` (type: `string`):

Used by search only. latest requests the newest matching posts first. top requests Bluesky's relevance-ranked results; it is not guaranteed to mean the most-liked posts. The default latest value is harmless for other operations, while top with another operation is rejected.

## `deduplicate` (type: `boolean`):

Skip duplicate records encountered during this run. Skipped duplicates are not billed.

## `blueskyIdentifier` (type: `string`):

Optional Bluesky handle or email for authenticated requests. Required for search and must be supplied together with blueskyAppPassword. This secret field is encrypted by Apify before the run input is stored and is decrypted only inside the Actor run. Runtime maximum: 253 characters.

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

Optional dedicated Bluesky app password; never use your main account password. Required for search and must be supplied together with blueskyIdentifier. Apify encrypts this secret field before storing run input; the Actor uses the decrypted value only in memory to authenticate with Bluesky and excludes it from datasets, statuses, and sanitized errors. Runtime maximum: 2,048 characters.

## Actor input object example

```json
{
  "operation": "profile",
  "handle": "bsky.app",
  "limit": 1,
  "maxPages": 3,
  "runMode": "evaluation",
  "feedAlias": "whats-hot",
  "connectionType": "followers",
  "includeReplies": false,
  "includeReposts": false,
  "includeQuotes": true,
  "sort": "latest",
  "deduplicate": true
}
```

# Actor output Schema

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

All normalized Bluesky result records, feed metadata records, run summaries with billing/status/resume-cursor diagnostics, and error records stored in the default dataset. Useful-result rows have data.isBillable=true and data.billingCategory=billable\_useful\_result, which means the row is eligible for the useful-result billing event; confirmed charge counts are reported in run\_summary. feed\_metadata, run\_summary, and error rows have data.isBillable=false and data.billingCategory=non\_billable\_control\_record. Post records include sortAtSource so customers can tell whether date filtering used createdAt or indexedAt.

# 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("xcalibur/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 = {}

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

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Bluesky Scraper",
        "description": "Extract public Bluesky profiles, posts, search results, feeds, followers, and following through official AT Protocol APIs.",
        "version": "0.1",
        "x-build-id": "IiYknKxnPWR2pl7zb"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/xcalibur~bluesky-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-xcalibur-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/xcalibur~bluesky-scraper/runs": {
            "post": {
                "operationId": "runs-sync-xcalibur-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/xcalibur~bluesky-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-xcalibur-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",
                "properties": {
                    "operation": {
                        "title": "Operation",
                        "enum": [
                            "profile",
                            "posts",
                            "search",
                            "feed",
                            "connections"
                        ],
                        "type": "string",
                        "description": "Choose which public Bluesky data to extract. The Actor never switches operations or infers intent from other fields.",
                        "default": "profile"
                    },
                    "handle": {
                        "title": "Bluesky handle or DID",
                        "type": "string",
                        "description": "Used by profile, posts, and connections only. A non-default handle conflicts with search or feed and is rejected. Runtime maximum: 253 characters.",
                        "default": "bsky.app"
                    },
                    "query": {
                        "title": "Search query",
                        "type": "string",
                        "description": "Required for search only. A non-empty query with another operation is rejected. Search requires Bluesky authentication. Runtime maximum: 512 characters."
                    },
                    "limit": {
                        "title": "Maximum saved results",
                        "minimum": 1,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "Maximum billable useful-result rows to save. Evaluation mode caps this at 100; Scale mode caps it at 10,000. A lower output is possible when the upstream result set ends, filters skip records, maxPages is reached, or the run charge limit is reached.",
                        "default": 1
                    },
                    "maxPages": {
                        "title": "Maximum API pages",
                        "minimum": 1,
                        "maximum": 100,
                        "type": "integer",
                        "description": "Hard request-safety cap. Evaluation mode caps this at 3 pages; Scale mode caps it at 100 pages.",
                        "default": 3
                    },
                    "runMode": {
                        "title": "Run scale",
                        "enum": [
                            "evaluation",
                            "scale"
                        ],
                        "type": "string",
                        "description": "Controls result and page safety caps only. Both modes are billed at the configured useful-result price for each saved useful row. Evaluation allows up to 100 useful results and 3 pages; Scale allows up to 10,000 useful results and 100 pages.",
                        "default": "evaluation"
                    },
                    "cursor": {
                        "title": "Resume cursor",
                        "type": "string",
                        "description": "Optional for posts, search, feed, and connections only. A cursor conflicts with profile and is rejected. Use a cursor from a previous run_summary.nextCursor. Page-level resumes can repeat already saved rows after a partial-page stop; check run_summary.resumeCursorStatus before resuming. Runtime maximum: 2,048 characters."
                    },
                    "since": {
                        "title": "Since timestamp",
                        "type": "string",
                        "description": "Optional inclusive timestamp filter for posts, search, and feed only. It conflicts with profile or connections. Include date, time, and an explicit timezone, for example 2026-07-04T00:00:00Z. Runtime maximum: 64 characters."
                    },
                    "until": {
                        "title": "Until timestamp",
                        "type": "string",
                        "description": "Optional inclusive timestamp filter for posts, search, and feed only. It conflicts with profile or connections. Include date, time, and an explicit timezone, for example 2026-07-05T00:00:00Z. Runtime maximum: 64 characters."
                    },
                    "feedAlias": {
                        "title": "Feed alias",
                        "enum": [
                            "whats-hot"
                        ],
                        "type": "string",
                        "description": "Used by feed only when feedUrl is not provided. The default What's Hot value is harmless for other operations; a non-default value is rejected outside feed or when feedUrl is also provided.",
                        "default": "whats-hot"
                    },
                    "feedUrl": {
                        "title": "Feed URL or AT URI",
                        "type": "string",
                        "description": "Optional for feed only. A non-empty feedUrl with another operation is rejected. Accepts an exact at:// feed generator URI or https://bsky.app/profile/<actor>/feed/<name> URL without query or fragment data. Runtime maximum: 2,048 characters."
                    },
                    "connectionType": {
                        "title": "Connection type",
                        "enum": [
                            "followers",
                            "following"
                        ],
                        "type": "string",
                        "description": "Used by connections only. The default followers value is harmless for other operations; choosing following with another operation is rejected.",
                        "default": "followers"
                    },
                    "includeReplies": {
                        "title": "Include replies",
                        "type": "boolean",
                        "description": "Used by posts only. The default false value is harmless elsewhere; enabling it with another operation is rejected.",
                        "default": false
                    },
                    "includeReposts": {
                        "title": "Include reposts",
                        "type": "boolean",
                        "description": "Used by posts only. The default false value is harmless elsewhere; enabling it with another operation is rejected.",
                        "default": false
                    },
                    "includeQuotes": {
                        "title": "Include quote posts",
                        "type": "boolean",
                        "description": "Used by posts only. The default true value is harmless elsewhere; disabling it with another operation is rejected.",
                        "default": true
                    },
                    "language": {
                        "title": "Search language filter",
                        "type": "string",
                        "description": "Optional for search only, for example en, th, ja, or my. A non-empty language with another operation is rejected. Leave blank to avoid unintentionally filtering results. Runtime maximum: 35 characters."
                    },
                    "sort": {
                        "title": "Search result order",
                        "enum": [
                            "latest",
                            "top"
                        ],
                        "type": "string",
                        "description": "Used by search only. latest requests the newest matching posts first. top requests Bluesky's relevance-ranked results; it is not guaranteed to mean the most-liked posts. The default latest value is harmless for other operations, while top with another operation is rejected.",
                        "default": "latest"
                    },
                    "deduplicate": {
                        "title": "Deduplicate within run",
                        "type": "boolean",
                        "description": "Skip duplicate records encountered during this run. Skipped duplicates are not billed.",
                        "default": true
                    },
                    "blueskyIdentifier": {
                        "title": "Bluesky identifier",
                        "type": "string",
                        "description": "Optional Bluesky handle or email for authenticated requests. Required for search and must be supplied together with blueskyAppPassword. This secret field is encrypted by Apify before the run input is stored and is decrypted only inside the Actor run. Runtime maximum: 253 characters."
                    },
                    "blueskyAppPassword": {
                        "title": "Bluesky app password",
                        "type": "string",
                        "description": "Optional dedicated Bluesky app password; never use your main account password. Required for search and must be supplied together with blueskyIdentifier. Apify encrypts this secret field before storing run input; the Actor uses the decrypted value only in memory to authenticate with Bluesky and excludes it from datasets, statuses, and sanitized errors. Runtime maximum: 2,048 characters."
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
