# Bluesky Author Feed Scraper (`apt_marble/bluesky-author-feed-scraper`) Actor

Collect public posts and reposts from a Bluesky author feed with engagement counts, text and reply context.

- **URL**: https://apify.com/apt_marble/bluesky-author-feed-scraper.md
- **Developed by:** [Hamza](https://apify.com/apt_marble) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.40 / 1,000 result records

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 Author Feed Scraper

Collect public posts and reposts from a Bluesky profile and export their text, engagement, author information and media in a clean dataset. Feed collection is cookieless. Images, videos, quoted posts and link previews are included whenever they are returned with the feed results. There are no individual-post detail requests. Repost reason, reply context and additional feed metadata are also retained.

### What you get

- Post text, publication and indexing timestamps, languages and content labels.
- Likes, reposts, replies, quotes and bookmarks when available.
- Author handle, display name, avatar, account identifier and account creation date.
- Structured images with thumbnails, full-size URLs, alt text and aspect ratios.
- Available video playlists, thumbnails, captions, external previews and quoted-post content.
- Original content metadata including facets, mentions, hashtags, links, reply references and attachment metadata.
- Additional author and post information returned with feed results, without an extra enrichment fee.

No media files are downloaded. Media metadata and links stay structured in JSON. CSV and Excel exports may represent these nested values as JSON strings. Missing fields are omitted, not guessed or filled with null placeholders. Zero engagement counts are kept.

### Start a run

1. Enter a **Bluesky profile**: `bsky.app`, `@bsky.app`, a DID, or `https://bsky.app/profile/bsky.app`.
2. Set **Maximum results** and start the run.

The actor requests additional feed pages automatically until it reaches the result limit or available posts end. No Maximum pages input is needed. Old `maxPages` values are ignored. This actor has no date filters.

```json
{
  "actor": "bsky.app",
  "maxItems": 105
}
```

| Input | Meaning |
| --- | --- |
| Bluesky profile | Public handle, @handle, DID or Bluesky profile link. Post links and links to other websites are rejected. |
| Maximum results | Maximum unique posts to save. Default 100; allowed range 1 to 10,000. |

Invalid inputs finish with a helpful message and examples. No posts are requested when input validation fails.

### Clean result fields

| Field | Contents |
| --- | --- |
| `text` | Full returned post text. |
| `createdAt`, `indexedAt`, `scrapedAt` | Publication, indexing and collection times. |
| `authorHandle`, `authorName`, `authorAvatar` | Readable author details. |
| `authorId`, `authorCreatedAt` | Stable author identifier and account creation date. |
| `likes`, `reposts`, `replies`, `quotes`, `bookmarks` | Returned engagement counts. |
| `languages`, `labels` | Language and moderation metadata. |
| `media` | Complete rendered media: image URLs, videos, external cards and quoted posts. |
| `contentDetails` | Other original content fields, including facets, attachments, reply references and record type. |
| `authorDetails` | Other author fields such as associated account information and author labels. |
| `postDetails` | Additional post fields not already included elsewhere. |
| `viewer`, `threadGate` | Viewer metadata and reply permissions, when available. |
| `feedReason` | Complete repost information, including the account that reposted and timestamp. |
| `replyContext` | Complete parent/root reply context returned with a feed entry. |
| `feedDetails` | Other feed-entry metadata, including new fields. |
| `postUri`, `contentId` | Unique post and content-version identifiers. |

The extra-information objects preserve new fields without creating duplicate raw-post columns. Original attachment metadata and rendered media are both retained because they contain different information. Post identifiers and media links are content, not internal request addresses. Internal retrieval URLs are not written to results, summaries or logs.

### Progress and run summary

Each accepted unique post is saved immediately. Short progress lines show results increasing page by page. The run summary reports saved posts, completed pages, request count, available-hit estimate when returned, result-limit status and a plain-language outcome.

An empty feed is a successful run with an explanation. If a later page becomes unavailable or repeats its pagination cursor, already-saved results remain available and the run finishes successfully with a partial-result message. A service outage before any results, or a dataset/storage failure, is an infrastructure error and may fail the run.

### Limits

Maximum results is a ceiling, not a promise. Feed availability, visibility restrictions, pagination availability and rate limits can return fewer posts. Later pages can become unavailable; those runs retain their results and explain the partial outcome. The actor does not unlock private, deleted, restricted or paid-only content. No full-history or high-volume guarantee is made.

Only information returned with the feed results is included. There are no profile-detail or individual-post lookups, invented metrics, private data or downloaded media files. Reuse must comply with applicable terms, copyright and privacy rules. This actor is independent and is not endorsed by Bluesky.

# Actor input Schema

## `actor` (type: `string`):

Public handle, @handle, DID or https://bsky.app/profile/... link. Example: bsky.app.

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

Maximum unique posts to save. Pagination continues automatically until this limit or available results are exhausted.

## Actor input object example

```json
{
  "actor": "joycomes.bsky.social",
  "maxItems": 100
}
```

# Actor output Schema

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

No description

## `summary` (type: `string`):

No description

# API

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

## JavaScript example

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

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

// Prepare Actor input
const input = {
    "actor": "joycomes.bsky.social"
};

// Run the Actor and wait for it to finish
const run = await client.actor("apt_marble/bluesky-author-feed-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 = { "actor": "joycomes.bsky.social" }

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

```

## MCP server setup

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

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/2MaO262v7i4JAUIzP/builds/Gg0G5PnmFbPBuss7q/openapi.json
