# Bluesky Scraper - Posts, Profiles & Search (`liver0914/bluesky-scraper-lite`) Actor

Scrape Bluesky posts by keyword search and by user handle, with full author profiles, engagement stats, images and hashtags.

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

## Pricing

from $2.00 / 1,000 post scrapeds

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/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Bluesky Scraper Lite 🦋

**Scrape Bluesky posts and profiles — keyword search, user timelines and full author stats in one Actor.** Search any keyword, or list handles like `@apify.com`, and get clean JSON with post text, hashtags, engagement counts, images, link cards and complete author info (followers, following, post counts). No login required — built on Bluesky's open AT Protocol, so it's fast, reliable and cheap.

The all-in-one alternative to buying separate post and user scrapers: **search + profiles + author feeds in a single run.**

### 🔎 What you can scrape

- **Keyword search** — all posts matching a query, newest (`latest`) or most engaging (`top`) first, with optional date range (`since`/`until`) and language filters
- **Profile timelines** — every post by any handle, with or without replies
- **Full profiles** — follower/following/post counts, display name, description, avatar
- **Per-post extras** — hashtags (extracted), images with alt text, embedded link cards, reply/repost/like/quote counts, web URL for every post

### 📥 Input

| Field | Type | Default | Description |
|---|---|---|---|
| `searchQueries` | Array | — | Keywords to search posts for. |
| `profileHandles` | Array | — | Handles to scrape (with or without `@`), e.g. `apify.com`. Saves the profile + their posts. |
| `postsPerQuery` | Integer | `25` | Max posts per query/handle. |
| `sort` | Select | `latest` | `latest` or `top` (search only). |
| `since` / `until` | Date | — | Only posts in this date range, `YYYY-MM-DD` (search only). |
| `lang` | String | — | Language filter like `en`, `de` (search only). |
| `includeAuthorInfo` | Boolean | `true` | Attach follower/following/post counts to every post. |
| `includeReplies` | Boolean | `false` | Include replies when scraping profiles. |
| `maxConcurrency` | Integer | `5` | Parallel API requests. |
| `proxyConfig` | Object | — | Optional; Bluesky's API is open so usually not needed. |

At least one of `searchQueries` / `profileHandles` is required.

#### Example input

```json
{
    "searchQueries": ["web scraping"],
    "profileHandles": ["@bsky.app"],
    "postsPerQuery": 25,
    "sort": "top"
}
```

### 📤 Output

One item per post (and one per profile) in the default dataset — export to JSON, CSV, Excel, HTML, XML:

```json
{
    "itemType": "post",
    "id": "3l7vlkxhqxs2c",
    "uri": "at://did:plc:.../app.bsky.feed.post/3l7vlkxhqxs2c",
    "url": "https://bsky.app/profile/bsky.app/post/3l7vlkxhqxs2c",
    "text": "We just shipped something #bluesky",
    "createdAt": "2026-10-01T12:00:00.000Z",
    "hashtags": ["bluesky"],
    "langs": ["en"],
    "authorDid": "did:plc:...",
    "authorHandle": "bsky.app",
    "authorName": "Bluesky",
    "authorAvatar": "https://...",
    "authorFollowers": 250000,
    "authorFollows": 100,
    "authorPosts": 5000,
    "images": [{ "fullsize": "https://...", "thumb": "https://...", "alt": "..." }],
    "link": { "uri": "https://...", "title": "...", "description": "..." },
    "replyCount": 12,
    "repostCount": 45,
    "likeCount": 300,
    "quoteCount": 8,
    "query": "web scraping"
}
```

Profile items have `itemType: "profile"` with the same author fields plus `text` = bio.

### ⚙️ How it works

Built directly on Bluesky's public AT Protocol endpoints (`app.bsky.feed.searchPosts`, `app.bsky.feed.getAuthorFeed`, `app.bsky.actor.getProfile`) — the same API the official app uses. No browser, no login, no blocked accounts. Handles cursor pagination automatically until your `postsPerQuery` limit, deduplicates posts across queries, and caches author lookups so popular authors cost one request, not hundreds.

### ❓ FAQ

#### How do I scrape Bluesky without an API key?

Just enter a keyword and run — no key, no login. Bluesky's AT Protocol exposes post search, author feeds and profiles publicly. One caveat this Actor handles for you: the `public.api.bsky.app` host returns 403 for unauthenticated keyword search (known upstream issue), so it calls `api.bsky.app`, where the same endpoint works freely. An optional app password only raises rate limits.

#### How do I scrape Bluesky posts for free?

Enter a keyword in `searchQueries` (or a handle in `profileHandles`) and click Start. Your Apify account includes free monthly platform credits — because this Actor uses Bluesky's open API instead of a browser, each run costs only fractions of a credit.

#### Can I scrape posts from a specific Bluesky user?

Yes — put their handle (e.g. `@bsky.app` or `bsky.app`) into `profileHandles`. You get their profile with follower counts plus their latest posts. Enable `includeReplies` to also capture replies.

#### Can I search Bluesky posts by keyword with a date range?

Yes — fill `searchQueries`, set `sort` (`latest` or `top`), and optionally `since`/`until` (YYYY-MM-DD) and `lang` to filter by language.

#### Does it need my Bluesky login or password?

No. All data comes from Bluesky's public API — no account, cookies or credentials required. You only see public data.

#### Can I get the data as Excel or CSV?

Yes — every run produces a dataset exportable to JSON, JSONL, CSV, XLSX, HTML, XML and RSS from the Console, or via `GET /v2/datasets/{id}/items?format=xlsx`.

#### Can I run it via API from my app?

Yes: `POST https://api.apify.com/v2/acts/liver0914~bluesky-scraper-lite/run-sync-get-dataset-items` with your input and token returns the scraped data directly in the response.

### 💡 Tips

- **Trend monitoring:** run on a schedule with `sort: "top"` and `since` set to yesterday.
- **Influencer research:** list up to 1000 handles in `profileHandles` — profiles include follower counts for ranking.
- **Cheapest runs:** keep `postsPerQuery` tight; every item is one API page or less.

### 🛠️ Local development & testing

```bash
npm install
npm test   # boots a local mock of the Bluesky XRPC API and runs 16 end-to-end assertions
```

### 📚 Related

Built by the same developer as [Contact Info Scraper Lite](https://apify.com/liver0914/contact-info-scraper-lite), [Rumble Scraper Lite](https://apify.com/liver0914/rumble-scraper-lite), [Mastodon Scraper Lite](https://apify.com/liver0914/mastodon-scraper-lite), [Cloudflare Bypasser Lite](https://apify.com/liver0914/cloudflare-bypasser-lite) and [GitHub Email Scraper Lite](https://apify.com/liver0914/github-email-scraper-lite) — a full open-web scraping toolkit.

# Actor input Schema

## `searchQueries` (type: `array`):

Keywords to search Bluesky posts for. Each query is scraped separately up to postsPerQuery.

## `profileHandles` (type: `array`):

Bluesky handles to scrape, e.g. apify.com or @apify.com. The Actor saves the profile and their latest posts.

## `postsPerQuery` (type: `integer`):

Maximum number of posts saved per search query and per profile handle.

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

How to sort search results. 'latest' = newest first, 'top' = most engaging first. Only affects search queries.

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

Only scrape posts published after this date (YYYY-MM-DD).

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

Only scrape posts published before this date (YYYY-MM-DD).

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

Only scrape posts in this language, e.g. en, de, ja (optional, only affects search).

## `includeAuthorInfo` (type: `boolean`):

Every post gets author follower/following/post counts attached.

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

When scraping profile handles, also include their replies (off by default).

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

Number of parallel API requests.

## `blueskyUsername` (type: `string`):

Your Bluesky handle, e.g. yourname.bsky.social. Optional: with an app password, keyword search becomes authenticated and more reliable. Not needed for profile scraping.

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

Create one at bsky.app -> Settings -> App passwords. Only needed together with the handle above for keyword search.

## `proxyConfig` (type: `object`):

Apify Proxy or custom proxies. Usually not needed - Bluesky's API is open and friendly to scrapers.

## Actor input object example

```json
{
  "searchQueries": [
    "bluesky"
  ],
  "postsPerQuery": 25,
  "sort": "latest",
  "includeAuthorInfo": true,
  "includeReplies": false,
  "maxConcurrency": 5,
  "proxyConfig": {}
}
```

# Actor output Schema

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

All scraped posts and profiles in the default dataset.

# 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 = {
    "searchQueries": [
        "bluesky"
    ],
    "proxyConfig": {}
};

// Run the Actor and wait for it to finish
const run = await client.actor("liver0914/bluesky-scraper-lite").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 = {
    "searchQueries": ["bluesky"],
    "proxyConfig": {},
}

# Run the Actor and wait for it to finish
run = client.actor("liver0914/bluesky-scraper-lite").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "bluesky"
  ],
  "proxyConfig": {}
}' |
apify call liver0914/bluesky-scraper-lite --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,liver0914/bluesky-scraper-lite"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/ySqVe1VGqSapTdxIT/builds/PebVY0M4uYRwZHcln/openapi.json
