Bluesky Posts, Profile & Followers Scraper (Apify Actor)

Scrape Bluesky user posts, profiles, followers and follows from the public API. No login. Flat rows, $0.001 per result, failed requests free. Runs as an Apify Actor, callable from MCP clients via the Apify MCP server (https://mcp.apify.com/?actors=pennydata/bluesky-posts-profile-scraper).

Hosted MCP Server

npx add-mcp 'https://mcp.apify.com/?actors=pennydata/bluesky-posts-profile-scraper'

Installs into Claude Code, Codex, Cursor and more

Documentation

Bluesky Posts, Profile & Followers Scraper (pennydata/bluesky-posts-profile-scraper) Actor

Scrape Bluesky user posts, profiles, followers and follows from the public API. No login. Flat rows, $0.001 per result, failed requests free.

Pricing

$1.00 / 1,000 result (post, profile, follower or follow)s

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 section below.

Each client library has reference documentation the quickstart does not restate: JavaScript/TypeScript (npm install apify-client) and Python (pip install apify-client).

README

Bluesky Posts, Profile & Followers Scraper

Scrape public Bluesky data without a login: a user's posts, profile details, followers and follows, as flat JSON rows. It calls Bluesky's public AT Protocol API (public.api.bsky.app), so there are no cookies, no browser and no API key. You are charged only for result rows that contain data; failed handles and empty feeds are free.

Built with AI assistance (Claude). Not affiliated with or endorsed by Bluesky Social PBC.

What you get

ModeOutput rows (recordType)Typical use
postspost: text, createdAt, like/repost/reply/quote counts, hashtags, mentions, links, image URLs, embed type, reply and repost flags, bsky.app URLMonitor a brand, journalist or competitor account; archive posts; sentiment datasets
profileprofile: handle, DID, display name, bio, avatar, banner, followers/follows/posts counts, createdAtEnrich a list of handles, influencer lists, account research
followersfollower: handle, DID, display name, bio, avatar, createdAtAudience analysis, lead lists of public accounts
followsfollow: same fields as followersMap who an account follows
starterPackstarterPackMember: handle, DID, display name, bio, avatar, plus starter pack name and URL; one row per memberExport a starter pack's member list to CSV, curation, outreach research
searchPostspost: same fields as posts mode, for any public post matching a keyword, hashtag or phraseBrand and keyword monitoring, topic research, sentiment datasets

Input examples

Search all public posts (no handles needed; sort is latest or top, since optional):

{ "mode": "searchPosts", "query": "bitcoin", "sort": "latest", "maxItems": 100 }

Latest 100 posts from three accounts:

{ "handles": ["bsky.app", "https://bsky.app/profile/jay.bsky.team", "@atproto.com"], "mode": "posts", "maxItems": 100 }

Only posts since a date (paging stops at the first older post):

{ "handles": ["bsky.app"], "mode": "posts", "maxItems": 5000, "since": "2026-10-01" }

One profile row per handle:

{ "handles": ["bsky.app", "jay.bsky.team"], "mode": "profile" }

Export every member of a starter pack:

{ "mode": "starterPack", "starterPacks": ["https://bsky.app/starter-pack/bsky.app/3lg3wkwlwef2z"], "maxItems": 150 }

First 1,000 followers of an account:

{ "handles": ["bsky.app"], "mode": "followers", "maxItems": 1000 }

Handles can be written as name.bsky.social, @name, a custom domain handle, a did:plc:... id or a https://bsky.app/profile/... URL. maxItems applies per handle. Posts mode skips reposts unless includeReposts is on, and replies unless postFilter is posts_with_replies.

Output example (posts mode)

{
  "recordType": "post", "source": "bsky.app", "handle": "bsky.app",
  "url": "https://bsky.app/profile/bsky.app/post/3mycyypdrxc2s",
  "text": "STREAMING LIVE NOW: ...", "createdAt": "2026-10-20T16:01:12.410Z",
  "likeCount": 298, "repostCount": 67, "replyCount": 17, "quoteCount": 7,
  "isReply": false, "isRepost": false, "hashtags": [], "links": [], "images": []
}

Results download as JSON, CSV or Excel from the Apify dataset, or via the Apify API.

Pricing

Pay per event, one event type:

EventPrice
result: one post, profile, follower or follow row$0.001

The cost guard is maxItems (per handle). You can also set a maximum total charge on the run in Apify; the actor stops when it is reached. Rows with an error (handle not found, account suspended) are written as recordType: "error" and not charged. Apify's standard platform usage rules apply on top.

Limits and notes

  • Public data only: private or deleted accounts, and content hidden by the account owner's settings, are not available.
  • Keyword search of all posts is not included; it needs authentication on Bluesky's side.
  • The actor paces itself at about 4 requests per second and backs off on HTTP 429, in line with Bluesky's published rate limits. Very large follower lists take proportionally longer.
  • Data comes from Bluesky's public API; you are responsible for using it in line with Bluesky's terms and privacy law, including GDPR for personal data.

Related

Run it from the Apify API, schedule it, or connect it to Make, Zapier or n8n through Apify integrations. Use one saved Apify task per account list for daily monitoring.


Other languages

Español: Scraper de publicaciones y perfiles de Bluesky

Obtiene publicaciones, perfiles, seguidores y cuentas seguidas de Bluesky en JSON, por usuario o por búsqueda de texto. Sin inicio de sesión y sin clave de API. Precio: 0,001 USD por resultado con datos reales; los usuarios no encontrados y los feeds vacíos no se cobran.

Ejemplo de entrada:

{"handles":["bsky.app"],"mode":"posts","maxItems":25}

Português: Scraper de posts e perfis do Bluesky

Coleta posts, perfis, seguidores e contas seguidas do Bluesky em JSON, por usuário ou por busca de texto. Sem login e sem chave de API. Preço: US$ 0,001 por resultado com dados reais; usuários não encontrados e feeds vazios não são cobrados.

Exemplo de entrada:

{"handles":["bsky.app"],"mode":"posts","maxItems":25}

Deutsch: Bluesky-Beiträge und Profile abrufen

Ruft Beiträge, Profile, Follower und gefolgte Konten von Bluesky als JSON ab, nach Nutzer oder per Textsuche. Ohne Login und ohne API-Schlüssel. Preis: 0,001 USD pro Ergebnis mit echten Daten; nicht gefundene Nutzer und leere Feeds kosten nichts.

Beispieleingabe:

{"handles":["bsky.app"],"mode":"posts","maxItems":25}

I built this and earn from its runs. Written with AI assistance (Claude).

Actor input Schema

handles (type: array):

Bluesky handles (bsky.app, @jay.bsky.team), DIDs (did:plc:...) or profile URLs (https://bsky.app/profile/bsky.app). One or many.

mode (type: string):

posts = author feed, profile = one profile row per handle, followers = accounts following the handle, follows = accounts the handle follows. searchPosts = keyword search across all public posts (uses query, sort, since, maxItems; handles not needed). starterPack = export every member of starter pack(s) listed in starterPacks.

query (type: string):

searchPosts mode only. Keywords, #hashtag or phrase, e.g. bitcoin. Supports Bluesky search operators such as from:handle.

starterPacks (type: array):

starterPack mode only. Starter pack URLs like https://bsky.app/starter-pack/bsky.app/3lg3wkwlwef2z. One row per member.

sort (type: string):

latest = newest first, top = most engaged first.

maxItems (type: integer):

Maximum result rows per handle, or in total for searchPosts (cost guard: each row is charged). Ignored for profile mode.

since (type: string):

Posts and searchPosts modes. ISO date or datetime (e.g. 2026-10-01 or 2026-10-01T12:00:00Z). Older posts are skipped and paging stops. Leave empty for no limit.

postFilter (type: string):

posts_no_replies = original posts and quotes only; posts_with_replies = include the author's replies; posts_and_author_threads = posts plus the author's own threads.

includeReposts (type: boolean):

Also return posts the user reposted (marked isRepost = true). Off by default.

Actor input object example

{
  "handles": [
    "bsky.app",
    "jay.bsky.team",
    "atproto.com"
  ],
  "mode": "posts",
  "sort": "latest",
  "maxItems": 25,
  "postFilter": "posts_no_replies",
  "includeReposts": false
}

Actor output Schema

results (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

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 = {
    "handles": [
        "bsky.app",
        "jay.bsky.team",
        "atproto.com"
    ],
    "mode": "posts",
    "maxItems": 25,
    "postFilter": "posts_no_replies"
};

// Run the Actor and wait for it to finish
const run = await client.actor("pennydata/bluesky-posts-profile-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

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 = {
    "handles": [
        "bsky.app",
        "jay.bsky.team",
        "atproto.com",
    ],
    "mode": "posts",
    "maxItems": 25,
    "postFilter": "posts_no_replies",
}

# Run the Actor and wait for it to finish
run = client.actor("pennydata/bluesky-posts-profile-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

echo '{
  "handles": [
    "bsky.app",
    "jay.bsky.team",
    "atproto.com"
  ],
  "mode": "posts",
  "maxItems": 25,
  "postFilter": "posts_no_replies"
}' |
apify call pennydata/bluesky-posts-profile-scraper --silent --output-dataset

MCP server setup

{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,pennydata/bluesky-posts-profile-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/CP9y9ocW3sqsb1nsE/builds/An9sZpcg6nNv45Cts/openapi.json