# Bluesky Posts Scraper: Search Posts, Hashtags & Profiles (`larkmoor/bluesky-posts`) Actor

Search Bluesky posts by keyword, phrase or hashtag, or get every post from any profile, via Bluesky's open public API: text, author, likes, reposts, replies, quotes, hashtags, links, images, language and post URL. Date, language and likes filters. $0.70 per 1,000 posts.

- **URL**: https://apify.com/larkmoor/bluesky-posts.md
- **Developed by:** [Larkmoor Data](https://apify.com/larkmoor) (community)
- **Categories:** Social media, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.60 / 1,000 posts

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

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

## What's an Apify Actor?

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 Posts Scraper: Search Posts, Hashtags & Profiles

Search **Bluesky** posts by keyword, phrase or hashtag, or read every post from any Bluesky profile, as one clean row per post: the text, author handle and name, created time, likes, reposts, replies, quotes, hashtags, mentions, links, image URLs, language, reply and repost flags, and the post URL.

It reads Bluesky's **open public API** (the AT Protocol AppView that powers the Bluesky app), which anyone can use without an account. No login, no cookies, no browser, no proxies.

### What you can use it for

- **Brand and keyword monitoring**: every new post mentioning your brand, product or competitor
- **Hashtag tracking**: collect #buildinpublic, #booksky, #nba or any tag for analysis or a content feed
- **Social listening and research**: sentiment, topics and reach on a fast-growing network, by language and date range
- **Influencer research**: read a creator's posts with engagement numbers to judge reach before you reach out
- **News and trend alerts**: a scheduled run with `sort: latest` and `since` sends fresh posts to Slack, email or a sheet
- **Datasets**: build clean text datasets of public posts for analytics dashboards

### Why this one

- **$0.70 per 1,000 posts**, $0.001 per run start — no init fee per query, cheaper than other Bluesky actors
- **Search and profiles in one run**: mix search queries and handles; duplicates are removed
- **Full search syntax**: phrases, hashtags, `from:`, `mentions:`, `domain:`, `lang:` operators work in queries
- **Useful columns ready to use**: hashtags, links, image URLs, quoted-post URL, reply/repost flags, engagement counts
- **Filters you don't pay for**: date range, language, minimum likes, no replies, no reposts — only rows that pass are charged
- **256 MB memory**, about 1,000 posts in under a minute

### Input

| Field | What it does |
|---|---|
| `searchQueries` | Keywords, "exact phrases", #hashtags or search operators — one search each |
| `profiles` | Handles (`bsky.app`, `@name.bsky.social`) or profile URLs |
| `sort` | Search order: `latest` or `top` |
| `since` / `until` | Date range (YYYY-MM-DD or ISO time) |
| `language` | Search language code (`en`, `de`, `ja`, ...) |
| `author` | Limit search results to one author |
| `minLikes` | Only posts with at least N likes |
| `excludeReplies` / `excludeReposts` | Skip replies / reposts |
| `maxPostsPerSource` / `maxResults` | Limits per query or profile, and for the run |

Example input:

```json
{
  "searchQueries": ["#webdev", "\"open source\" lang:en"],
  "profiles": ["bsky.app"],
  "sort": "latest",
  "since": "2026-10-01",
  "minLikes": 5,
  "excludeReplies": true,
  "maxResults": 500
}
```

### Output

One row per post (real example):

```json
{
  "url": "https://bsky.app/profile/digiwares.bsky.social/post/3myjtmmflzc2z",
  "text": "New domain, same mission. 🎙️\n\nTalking Links has a new home: tlk.so\n\nOne link. Voice or text replies. Organised responses.\n\nWe're getting closer to launch.\n\nTalk. Speak Out.\n\n#BuildInPublic #SaaS #AITools #IndieDev #webdev #startup #talkinglinks #talkinglinks",
  "createdAt": "2026-10-23T09:13:36.129Z",
  "authorHandle": "digiwares.bsky.social",
  "authorName": "DigiWares",
  "likeCount": 4,
  "repostCount": 3,
  "replyCount": 0,
  "quoteCount": 0,
  "langs": [
    "en"
  ],
  "hashtags": [
    "AITools",
    "BuildInPublic",
    "IndieDev",
    "SaaS",
    "startup",
    "talkinglinks",
    "webdev"
  ],
  "links": [
    "https://tlk.so"
  ],
  "images": [],
  "isReply": false,
  "isRepost": false,
  "source": "search:#webdev"
}
```

Also included: `uri`, `cid`, `indexedAt`, `authorDid`, `authorAvatar`, `mentions` (DIDs), `quotedPostUrl`, `replyToUri`, `repostedBy`, `labels`.

### How much does it cost?

Pay per event: **$0.0007 per post** ($0.70 per 1,000) and **$0.001 per run start**. Platform usage at 256 MB is a fraction of a cent per run.

- Daily brand monitor, ~200 new posts a day: about $0.14 a day
- A one-off study of 10,000 posts on a hashtag: about $7.00
- 20 creators' last 100 posts each (2,000 posts): about $1.40

Posts dropped by your filters are not charged.

### FAQ

**Is it legal?**
It reads public posts through Bluesky's own open API, which Bluesky provides for anyone to build on, and follows Bluesky's developer guidelines (read-only, polite rate, no automated interactions). Only public posts are read; nothing behind a login. As with any personal data, use it in line with privacy law where you work (for example GDPR) and honour deletion requests.

**Do I need a Bluesky account?**
No.

**How far back does search go?**
Bluesky search covers the network's history; use `since`/`until` for a range and `sort: top` for the most-engaged posts.

**Why are mentions DIDs rather than handles?**
Bluesky stores mentions by permanent account ID (DID), which never changes even if the handle does. Open `https://bsky.app/profile/<did>` to see the profile.

**Can it get replies to a post or followers?**
Not in this version; it focuses on posts from search and profiles.

### Tips

- Put a phrase in quotes for exact matches; add `lang:en` to a query or use the `language` field.
- For monitoring, schedule hourly with `sort: latest` and `since` set to yesterday.
- Use `minLikes` to keep only posts with real reach.

### Integrations

Works with Google Sheets, Slack, Zapier, Make, Airtable, webhooks, the Apify API and the Python and JavaScript clients. Download as JSON, CSV, Excel, XML or HTML.

### Changelog

- **2026-10-23** — First release: keyword/hashtag search (latest or top), profile posts, date, language, likes, reply and repost filters, hashtags, links, images and quoted posts.

# Actor input Schema

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

Keywords, phrases (in quotes), hashtags (#webdev) or Bluesky search operators (from:handle, domain:example.com, lang:en). One search per line.

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

Bluesky handles (bsky.app, @someone.bsky.social) or profile URLs. Reads each profile's posts, newest first.

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

Order of search results.

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

Only posts created on or after this date (YYYY-MM-DD or ISO timestamp).

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

Only posts created before this date (YYYY-MM-DD or ISO timestamp).

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

Search only: 2-letter language code, e.g. en, de, ja, pt.

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

Search only: limit search results to one author handle.

## `minLikes` (type: `integer`):

Keep only posts with at least this many likes.

## `excludeReplies` (type: `boolean`):

Skip posts that are replies to another post.

## `excludeReposts` (type: `boolean`):

Profiles only: skip posts the profile reposted from others.

## `maxPostsPerSource` (type: `integer`):

Upper limit per search query or profile.

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

Upper limit for the whole run. You pay only for posts returned.

## Actor input object example

```json
{
  "searchQueries": [
    "#webdev"
  ],
  "profiles": [
    "bsky.app"
  ],
  "sort": "latest",
  "minLikes": 0,
  "excludeReplies": false,
  "excludeReposts": false,
  "maxPostsPerSource": 1000,
  "maxResults": 20
}
```

# Actor output Schema

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

All results as JSON items in the run's default dataset (also downloadable as CSV/Excel from the 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": [
        "#webdev"
    ],
    "profiles": [
        "bsky.app"
    ],
    "maxResults": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("larkmoor/bluesky-posts").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": ["#webdev"],
    "profiles": ["bsky.app"],
    "maxResults": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("larkmoor/bluesky-posts").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": [
    "#webdev"
  ],
  "profiles": [
    "bsky.app"
  ],
  "maxResults": 20
}' |
apify call larkmoor/bluesky-posts --silent --output-dataset

```

## MCP server setup

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

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/FgXlbB1i2YtCSI86v/builds/2SMxWefCf8yW8NYNC/openapi.json
