# Bluesky Scraper — Profiles, Posts & Search API (`sian.agency/bluesky-scraper`) Actor

Scrape Bluesky (bsky.app) profiles & posts into clean structured data — followers, bio, engagement counts, media, links. Search by keyword or pull full profiles + post feeds. JSON/CSV/Excel. No login or API key needed.

- **URL**: https://apify.com/sian.agency/bluesky-scraper.md
- **Developed by:** [SIÁN OÜ](https://apify.com/sian.agency) (community)
- **Categories:** Social media, Automation, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.30 / 1,000 search record extracteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/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.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 — Profiles, Posts & Search Data 🦋

[![SIÁN Agency Store](https://img.shields.io/badge/Store-SI%C3%81N%20Agency-1AE392)](https://apify.com/sian.agency?fpr=sian) [![Xiaohongshu Scraper](https://img.shields.io/badge/Store-Xiaohongshu%20RedNote-FF2442)](https://apify.com/sian.agency/xiaohongshu-rednote-scraper?fpr=sian) [![Weibo Scraper](https://img.shields.io/badge/Store-Weibo-E6162D)](https://apify.com/sian.agency/weibo-scraper?fpr=sian) [![Instagram AI Transcript](https://img.shields.io/badge/Store-Instagram%20Transcript-E4405F)](https://apify.com/sian.agency/instagram-ai-transcript-extractor?fpr=sian)

#### 🎉 Turn the AT Protocol's open social graph into a clean, structured dataset — profiles, posts, search and full author feeds in one run.
##### For social listeners, growth marketers, researchers and lead-gen teams who need Bluesky data without writing code.

---

### 📋 Overview

**Bluesky Scraper pulls public Bluesky (bsky.app) data into ready-to-use datasets** — search the network by keyword, or hand it specific accounts and get the full picture: followers, bio, post counts, engagement metrics, media and links.

**Why thousands of professionals choose us:**
- ✅ **Two modes, one tool**: cheap keyword **Search** (many profiles or posts) + full **Detail** (complete profiles + post feeds)
- ⚡ **Fast & clean**: up to 100 records per request, cursor-paginated, returned as tidy JSON/CSV/Excel
- 🎯 **40+ structured fields**: handles, bios, follower/following/post counts, likes, reposts, replies, quotes, bookmarks, embeds, media and language tags
- 💰 **Best price on the market**: transparent pay-per-result — only pay for records you actually receive
- 💎 **Native filters**: sort, language, date range, author, mentions, link domain and hashtag — Bluesky's own search filters exposed
- ✨ **No login, no API key**: works entirely on public data, zero setup

---

### ✨ Features

- 🔎 **Keyword Search**: find profiles or posts matching any term, across the whole network
- 👤 **Full Profile Detail**: follower / following / post counts, verification status, avatar & banner
- 📝 **Author Feeds**: pull a profile's recent posts with full engagement metrics and embeds
- 🎚️ **Post Filters**: top/latest sort, language, since/until dates, author, mentions, domain, hashtag
- 🔗 **Search-URL Input**: paste a Bluesky search URL and keep all its filters
- 📊 **Engagement Metrics**: likes, reposts, replies, quotes and bookmarks on every post
- 🖼️ **Media Extraction**: avatar, banner, post images, video thumbnails and external link cards
- 🚀 **Bulk Mode**: many search terms or many profiles in a single run
- 📤 **Clean Exports**: JSON, CSV and Excel straight from the Apify dataset

---

### 🎬 Quick Start

Pick a mode, give it a term or a profile, hit **Start**. Results stream into the dataset as they're found. Export to JSON/CSV/Excel when done.

```bash
curl -X POST https://api.apify.com/v2/acts/sian.agency~bluesky-scraper/runs?token=YOUR_TOKEN \
-H 'Content-Type: application/json' \
-d '{"scrapeMode": "search", "recordType": "profiles", "searchTerm": "los angeles"}'
````

***

### 🚀 Getting Started (3 Simple Steps)

#### Step 1: Choose a mode

**Search** to discover many records by keyword, or **Detail** to fully profile specific accounts.

#### Step 2: Enter your target

A search term (or several), or one or more profiles (handle, DID, or `bsky.app/profile/...` URL).

#### Step 3: Run & export

Click **Start**, then download your dataset as JSON, CSV or Excel.

**That's it! In under a minute, you'll have:**

- Structured profile or post records
- Full engagement and follower metrics (Detail mode)
- A clean dataset ready for analysis or import

***

### 📥 Input Configuration

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| scrapeMode | string | No | `search` (keyword → many) or `detail` (profiles → full) |
| recordType | string | No | In search mode: `profiles` or `posts` |
| searchTerm | string | No | A keyword/phrase to search |
| searchTerms | array | No | Multiple keywords (bulk search) |
| searchUrl | string | No | Paste a Bluesky search URL (filters preserved) |
| profile | string | No | A single profile (handle / DID / URL) for Detail mode |
| profiles | array | No | Multiple profiles for bulk Detail |
| includeFeed | boolean | No | Detail mode: also pull each profile's post feed |
| feedPages | integer | No | Feed pages per profile (100 posts each) |
| sort, lang, since, until, author, mentions, domain, tag | string | No | Post-search filters |
| maxResults | integer | No | Cap on records per run (FREE: 25, PAID: unlimited) |
| maxPages | integer | No | Cursor pages per search term |

**Search example:**

```json
{
  "scrapeMode": "search",
  "recordType": "posts",
  "searchTerm": "wildfire",
  "sort": "latest",
  "lang": "en",
  "maxPages": 3
}
```

**Detail example (profiles + feed):**

```json
{
  "scrapeMode": "detail",
  "profiles": ["laist.com", "https://bsky.app/profile/bsky.app"],
  "includeFeed": true,
  "feedPages": 2
}
```

***

### 📤 Output

Results are saved to the Apify dataset with **40+ fields** including:

| Field | Type | Description |
|-------|------|-------------|
| url | string | Public bsky.app URL |
| handle | string | Account handle |
| displayName | string | Profile display name |
| description | string | Profile bio |
| followers\_count | number | Follower count (Detail) |
| posts\_count | number | Total posts (Detail) |
| verified | boolean | Verification status |
| text | string | Post text |
| author\_handle | string | Post author |
| like\_count / repost\_count / reply\_count | number | Engagement metrics |
| embed\_type | string | images / video / external / record |
| images | array | Media URLs |
| created\_at | string | Creation timestamp |

**Example (profile):**

```json
{
  "id": "did:plc:kosvedukjcyvdfv64zltdauy",
  "url": "https://bsky.app/profile/laist.com",
  "handle": "laist.com",
  "displayName": "LAist",
  "followers_count": 9901,
  "follows_count": 41,
  "posts_count": 296,
  "verified": true
}
```

**Example (post):**

```json
{
  "url": "https://bsky.app/profile/laist.com/post/3moxztpaf4x27",
  "text": "Today in L.A. ...",
  "author_handle": "laist.com",
  "like_count": 42,
  "repost_count": 7,
  "reply_count": 3,
  "embed_type": "images",
  "langs": ["en"]
}
```

***

### 💼 Use Cases & Examples

#### 1. Social Listening & Brand Monitoring

**Marketing teams tracking what's said about a brand, topic or campaign on Bluesky.**
**Input:** keyword(s) in posts mode · **Output:** posts with engagement · **Use:** spot trends and sentiment early.

#### 2. Influencer & Creator Discovery

**Agencies finding accounts in a niche, ranked by reach.**
**Input:** keyword in profiles mode, then Detail for follower counts · **Output:** profiles with audience size · **Use:** build outreach lists.

#### 3. Lead Generation

**B2B teams collecting public handles, bios and links from a community.**
**Input:** keyword search → profile detail · **Output:** structured profile records · **Use:** enrich a prospect list.

#### 4. Academic & Trend Research

**Researchers studying conversations, hashtags or news diffusion on the AT Protocol.**
**Input:** posts with date/lang/hashtag filters · **Output:** dated, language-tagged posts · **Use:** time-series analysis.

#### 5. Competitor & Audience Analysis

**Growth teams benchmarking accounts and their content.**
**Input:** profiles + feed · **Output:** follower counts + post performance · **Use:** compare engagement.

#### 6. Newsroom & Journalism

**Reporters monitoring official accounts and breaking-news posts.**
**Input:** author/domain filters · **Output:** posts linking a source · **Use:** verify and source stories.

***

### 🔗 Integration Examples

#### JavaScript/Node.js

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });

const run = await client.actor('sian.agency/bluesky-scraper').call({
  scrapeMode: 'search', recordType: 'profiles', searchTerm: 'los angeles'
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0]);
```

#### Python

```python
from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')

run = client.actor('sian.agency/bluesky-scraper').call(
    run_input={'scrapeMode': 'detail', 'profiles': ['laist.com'], 'includeFeed': True}
)

for item in client.dataset(run['defaultDatasetId']).iterate_items():
    print(item)
```

#### cURL

```bash
curl -X POST 'https://api.apify.com/v2/acts/sian.agency~bluesky-scraper/runs?token=YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"scrapeMode": "search", "recordType": "posts", "searchTerm": "nba", "sort": "top"}'
```

#### Automation Workflows (N8N / Zapier / Make)

1. **Trigger**: Schedule or webhook
2. **HTTP Request**: Call the actor API
3. **Process**: Handle JSON results
4. **Action**: Save, notify, or transform

***

### 📊 Performance & Pricing

#### FREE Tier (Try It Now)

- **25 records** per run — full feature access, same quality
- No credit card required
- Perfect for testing and small projects

#### PAID Tier (Production Ready)

- **Unlimited** records per run
- Faster, uninterrupted runs
- Pay-per-result: only charged for records you actually receive

💰 **Best price on the market** — transparent, low per-record pricing with no monthly minimum.

🔗 [View current pricing](https://apify.com/sian.agency/bluesky-scraper?fpr=sian)

***

### ❓ Frequently Asked Questions

**Q: How many records can I get?**
A: FREE tier: 25 per run. PAID tier: unlimited.

**Q: Do I need a Bluesky account or API key?**
A: No. The actor only reads publicly available data — no login, no key, no setup.

**Q: Can I get follower counts?**
A: Yes — use Detail mode. Keyword search returns lightweight profile cards; Detail mode fills in follower/following/post counts.

**Q: What output formats are available?**
A: JSON, CSV and Excel — export directly from the Apify dataset.

**Q: Can I filter posts by date, language or hashtag?**
A: Yes — posts search supports sort, language, since/until dates, author, mentions, link domain and hashtag.

**Q: Is this legal?**
A: We only extract publicly available data. See the legal note below.

***

### 🐛 Troubleshooting

**No results in search mode**

- Check your term isn't too narrow; try `top` sort for posts.
- Increase `maxPages` to fetch more cursor pages.

**Profile not found in Detail mode**

- Verify the handle/DID is correct; pasted profile URLs and `@handle` are both accepted.

**Follower counts are empty**

- Keyword search doesn't include counts by design — switch to **Detail** mode for full counts.

***

### ⚖️ Is it legal to scrape data?

Our actors are ethical and do not extract any private user data, such as email addresses, gender, or location. They only extract what the user has chosen to share publicly. We therefore believe that our actors, when used for ethical purposes by Apify users, are safe.

However, you should be aware that your results could contain personal data. Personal data is protected by the **GDPR** in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers.

You can also read Apify's blog post on the [legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

***

### ⚠️ Disclaimer

This is an independent tool for extracting publicly available data. It is not affiliated with, endorsed by, or sponsored by Bluesky Social, PBC, or the Bluesky/AT Protocol project. "Bluesky" and related marks are the property of their respective owners and are used here for descriptive purposes only.

***

### 🤝 Support

[![Telegram Support](https://img.shields.io/badge/Telegram-Support%20Group-0088cc?logo=telegram)](https://t.me/+vyh1sRE08sAxMGRi)

**Join our active support community**

- For issues or questions, open an issue in the actor's repository
- Check [SIÁN Agency Store](https://apify.com/sian.agency?fpr=sian) for more automation tools
- 📧 <apify@sian-agency.online>

***

**Built by [SIÁN Agency](https://www.sian-agency.online)** | **[More Tools](https://apify.com/sian.agency?fpr=sian)**

# Actor input Schema

## `scrapeMode` (type: `string`):

**SEARCH** = cheap list mode. Search Bluesky by keyword and get many profiles or posts, cursor-paginated.

**DETAIL** = full mode. Give specific profiles (handles / DIDs / profile URLs) and get the complete record — follower/following/post counts — plus, optionally, each profile's recent post feed with engagement metrics.

## `recordType` (type: `string`):

In **Search** mode, choose what to return:

- **Profiles** — accounts matching your term (handle, display name, bio, avatar)
- **Posts** — posts matching your query (text, author, engagement, media)

Ignored in Detail mode (which always returns profiles, plus posts if you enable the author feed).

## `searchTerm` (type: `string`):

**SINGLE SEARCH:** A keyword or phrase to search Bluesky for. Returns profiles or posts depending on Record Type.

**Examples:** `los angeles`, `wildfire`, `nba`, `climate science`

💡 **TIP:** For posts, add filters below (sort, language, date range, hashtag) to narrow results.

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

**BULK SEARCH:** Run several searches in one go — each term is searched separately and all results land in the same dataset.

**TIER-BASED LIMITS:**

- **FREE users:** results capped per run
- **PAID users:** unlimited

💡 Click **Bulk edit** to paste one term per line. Use the single Search Term field for one keyword.

## `searchUrl` (type: `string`):

Paste a Bluesky search API URL instead of a term — filters in the query string are preserved.

**Example:** `https://api.bsky.app/xrpc/app.bsky.feed.searchPosts?q=nba&sort=top&lang=en`

When provided, this overrides the Search Term fields.

## `profile` (type: `string`):

**DETAIL MODE:** A Bluesky profile to fetch in full. Accepts a handle, a DID, or a profile URL.

**Examples:**

- `laist.com`
- `@laist.com`
- `https://bsky.app/profile/laist.com`
- `did:plc:kosvedukjcyvdfv64zltdauy`

## `profiles` (type: `array`):

**BULK DETAIL:** A list of profiles (handles / DIDs / profile URLs) to fetch in full.

**TIER-BASED LIMITS:**

- **FREE users:** results capped per run
- **PAID users:** unlimited

💡 Click **Bulk edit** to paste one profile per line.

## `includeFeed` (type: `boolean`):

In **Detail** mode, also fetch each profile's recent posts (with engagement metrics, embeds and media). Adds post rows to the dataset alongside the profile rows.

## `feedPages` (type: `integer`):

How many pages (up to 100 posts each) of the author feed to fetch per profile when **Also Pull Feed** is on.

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

Order for **post** searches: `top` (most relevant/engaged) or `latest` (newest first).

## `lang` (type: `string`):

Restrict posts to a BCP-47 language code, e.g. `en`, `es`, `pt`, `ja`.

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

Only posts on/after this date. ISO datetime or `yyyy-mm-dd`, e.g. `2025-01-01`.

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

Only posts on/before this date. ISO datetime or `yyyy-mm-dd`.

## `author` (type: `string`):

Restrict posts to a specific author (handle or DID).

## `mentions` (type: `string`):

Only posts mentioning this handle.

## `domain` (type: `string`):

Only posts linking to this domain, e.g. `nytimes.com`.

## `tag` (type: `string`):

Only posts with this hashtag (omit the `#`).

## `maxResults` (type: `integer`):

Hard cap on the total records saved this run. **FREE** runs are capped at 25 regardless of this value; **PAID** runs are unlimited.

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

How many cursor pages to fetch per search term (up to 100 records each). Higher = more results, more cost.

## Actor input object example

```json
{
  "scrapeMode": "search",
  "recordType": "profiles",
  "searchTerm": "los angeles",
  "searchUrl": "https://api.bsky.app/xrpc/app.bsky.feed.searchPosts?q=nba&sort=top",
  "profile": "laist.com",
  "includeFeed": false,
  "feedPages": 1,
  "sort": "latest",
  "lang": "en",
  "since": "2025-01-01",
  "until": "2025-12-31",
  "author": "laist.com",
  "mentions": "bsky.app",
  "domain": "nytimes.com",
  "tag": "wildfire",
  "maxResults": 100,
  "maxPages": 3
}
```

# Actor output Schema

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

Profiles and posts extracted from Bluesky — handles, bios, follower counts, engagement metrics, media and links.

## `scrapingSummary` (type: `string`):

HTML summary showing extracted and failed records with key run metrics.

# 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("sian.agency/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("sian.agency/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 sian.agency/bluesky-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Bluesky Scraper — Profiles, Posts & Search API",
        "description": "Scrape Bluesky (bsky.app) profiles & posts into clean structured data — followers, bio, engagement counts, media, links. Search by keyword or pull full profiles + post feeds. JSON/CSV/Excel. No login or API key needed.",
        "version": "1.0",
        "x-build-id": "4bidqcYpUnEMmo96C"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/sian.agency~bluesky-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-sian.agency-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/sian.agency~bluesky-scraper/runs": {
            "post": {
                "operationId": "runs-sync-sian.agency-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/sian.agency~bluesky-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-sian.agency-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": {
                    "scrapeMode": {
                        "title": "🧭 Scrape Mode",
                        "enum": [
                            "search",
                            "detail"
                        ],
                        "type": "string",
                        "description": "**SEARCH** = cheap list mode. Search Bluesky by keyword and get many profiles or posts, cursor-paginated.\n\n**DETAIL** = full mode. Give specific profiles (handles / DIDs / profile URLs) and get the complete record — follower/following/post counts — plus, optionally, each profile's recent post feed with engagement metrics.",
                        "default": "search"
                    },
                    "recordType": {
                        "title": "📁 Record Type (Search mode)",
                        "enum": [
                            "profiles",
                            "posts"
                        ],
                        "type": "string",
                        "description": "In **Search** mode, choose what to return:\n- **Profiles** — accounts matching your term (handle, display name, bio, avatar)\n- **Posts** — posts matching your query (text, author, engagement, media)\n\nIgnored in Detail mode (which always returns profiles, plus posts if you enable the author feed).",
                        "default": "profiles"
                    },
                    "searchTerm": {
                        "title": "🔎 Search Term (Search mode)",
                        "type": "string",
                        "description": "**SINGLE SEARCH:** A keyword or phrase to search Bluesky for. Returns profiles or posts depending on Record Type.\n\n**Examples:** `los angeles`, `wildfire`, `nba`, `climate science`\n\n💡 **TIP:** For posts, add filters below (sort, language, date range, hashtag) to narrow results.",
                        "default": "los angeles"
                    },
                    "searchTerms": {
                        "title": "🚀 Bulk Search Terms (Search mode)",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "**BULK SEARCH:** Run several searches in one go — each term is searched separately and all results land in the same dataset.\n\n**TIER-BASED LIMITS:**\n- **FREE users:** results capped per run\n- **PAID users:** unlimited\n\n💡 Click **Bulk edit** to paste one term per line. Use the single Search Term field for one keyword.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "searchUrl": {
                        "title": "🔗 Search URL (Search mode, optional)",
                        "type": "string",
                        "description": "Paste a Bluesky search API URL instead of a term — filters in the query string are preserved.\n\n**Example:** `https://api.bsky.app/xrpc/app.bsky.feed.searchPosts?q=nba&sort=top&lang=en`\n\nWhen provided, this overrides the Search Term fields."
                    },
                    "profile": {
                        "title": "👤 Single Profile (Detail mode)",
                        "type": "string",
                        "description": "**DETAIL MODE:** A Bluesky profile to fetch in full. Accepts a handle, a DID, or a profile URL.\n\n**Examples:**\n- `laist.com`\n- `@laist.com`\n- `https://bsky.app/profile/laist.com`\n- `did:plc:kosvedukjcyvdfv64zltdauy`"
                    },
                    "profiles": {
                        "title": "🚀 Bulk Profiles (Detail mode)",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "**BULK DETAIL:** A list of profiles (handles / DIDs / profile URLs) to fetch in full.\n\n**TIER-BASED LIMITS:**\n- **FREE users:** results capped per run\n- **PAID users:** unlimited\n\n💡 Click **Bulk edit** to paste one profile per line.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "includeFeed": {
                        "title": "📝 Also Pull Each Profile's Post Feed",
                        "type": "boolean",
                        "description": "In **Detail** mode, also fetch each profile's recent posts (with engagement metrics, embeds and media). Adds post rows to the dataset alongside the profile rows.",
                        "default": false
                    },
                    "feedPages": {
                        "title": "🔢 Feed Pages Per Profile",
                        "minimum": 1,
                        "maximum": 50,
                        "type": "integer",
                        "description": "How many pages (up to 100 posts each) of the author feed to fetch per profile when **Also Pull Feed** is on.",
                        "default": 1
                    },
                    "sort": {
                        "title": "↕️ Sort (Posts search)",
                        "enum": [
                            "top",
                            "latest"
                        ],
                        "type": "string",
                        "description": "Order for **post** searches: `top` (most relevant/engaged) or `latest` (newest first).",
                        "default": "latest"
                    },
                    "lang": {
                        "title": "🌐 Language (Posts search)",
                        "type": "string",
                        "description": "Restrict posts to a BCP-47 language code, e.g. `en`, `es`, `pt`, `ja`."
                    },
                    "since": {
                        "title": "📅 Since (Posts search)",
                        "type": "string",
                        "description": "Only posts on/after this date. ISO datetime or `yyyy-mm-dd`, e.g. `2025-01-01`."
                    },
                    "until": {
                        "title": "📅 Until (Posts search)",
                        "type": "string",
                        "description": "Only posts on/before this date. ISO datetime or `yyyy-mm-dd`."
                    },
                    "author": {
                        "title": "✍️ Author (Posts search)",
                        "type": "string",
                        "description": "Restrict posts to a specific author (handle or DID)."
                    },
                    "mentions": {
                        "title": "@ Mentions (Posts search)",
                        "type": "string",
                        "description": "Only posts mentioning this handle."
                    },
                    "domain": {
                        "title": "🔗 Link Domain (Posts search)",
                        "type": "string",
                        "description": "Only posts linking to this domain, e.g. `nytimes.com`."
                    },
                    "tag": {
                        "title": "#️⃣ Hashtag (Posts search)",
                        "type": "string",
                        "description": "Only posts with this hashtag (omit the `#`)."
                    },
                    "maxResults": {
                        "title": "🔢 Max Records Per Run",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Hard cap on the total records saved this run. **FREE** runs are capped at 25 regardless of this value; **PAID** runs are unlimited.",
                        "default": 100
                    },
                    "maxPages": {
                        "title": "📄 Max Search Pages",
                        "minimum": 1,
                        "maximum": 100,
                        "type": "integer",
                        "description": "How many cursor pages to fetch per search term (up to 100 records each). Higher = more results, more cost.",
                        "default": 3
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
