# Bluesky Engagement Analytics (`lowlanddata/bluesky-engagement-analytics`) Actor

One row of engagement KPIs per requested Bluesky account: median and p75 likes, reposts, replies, total engagement, posting cadence and the top post - computed from the open AppView, no login, no keys. Aggregates only: no follower lists, no feeds, no identifiers beyond the handles you asked for.

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

## Pricing

from $17.91 / 1,000 results

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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 Engagement Analytics — account KPIs as one clean row

Get the engagement numbers for any **Bluesky** account — median and p75 likes, median reposts and replies, posting cadence, top post — computed for you, one row per handle. Not a feed dump: the actor samples the account's recent posts from Bluesky's open AppView, runs the statistics, and delivers the answer.

**Analyzes only what you ask for, and returns numbers, not people.** You name the handles; the output is aggregate statistics plus one top-post link. No follower lists, no DIDs, no avatars, no per-post dumps of other users' feeds — public engagement counts on public posts, summarized.

### Quick start (30 seconds)

1. Put one or more handles into **authorHandles** — e.g. `bsky.app` or `nasa.gov, bbc.com`.
2. Click **Start**. That's the whole minimum setup — no login, no API keys.
3. When the run finishes, open the dataset's **Overview** tab: one row per account with its KPIs, exportable as CSV/Excel/JSON.

Optional knobs: sample size per account, include replies, and any input works on a weekly Schedule.

### What you can build with it

- **Benchmark your account.** Run your handle next to accounts you compare yourself to — one table, same metrics, computed the same way.
- **Report weekly social KPIs.** Social managers: put the client handles on a weekly Schedule and the KPI row lands in the dataset every Monday, ready to paste into the report.
- **Size an account before writing about it.** Researchers and journalists get cadence and typical engagement in seconds, without scrolling a profile.
- **Check real engagement before a sponsorship.** Median numbers expose accounts whose one viral post hides a quiet feed — the scout's question, answered with medians.

### What you get

Each analyzed account is one dataset row. A live run on `bsky.app` over its last 100 posts:

```json
{
  "handle": "bsky.app",
  "postsSampled": 100,
  "periodDays": 412,
  "postsPerWeek": 1.7,
  "medianLikes": 3481,
  "p75Likes": 8250,
  "medianReposts": 421,
  "medianReplies": 187,
  "medianEngagement": 5045,
  "topPostUri": "at://did:plc:example/app.bsky.feed.post/3kexample01",
  "topPostUrl": "https://bsky.app/profile/bsky.app/post/3kexample01",
  "topPostLikes": 55995,
  "topPostReposts": 6120
}
```

Field notes, so you know exactly what you are buying:

- Medians are nearest-rank over the sampled posts — one viral outlier does not distort them. `p75Likes` is what a good post gets; `medianEngagement` is the median of likes + reposts + replies per post.
- `postsPerWeek` = posts sampled ÷ days spanned × 7 — the cadence over the sampled period.
- The top post is the sampled post with the most likes + reposts, delivered with its link and counts.
- Honest limits: the row reflects the sampled recent posts, not the account's full history; reposts *by* the account are not counted (author posts only); like counts are the AppView's public numbers at run time.

### How much does a Bluesky engagement report cost?

$1.99 per 1,000 rows delivered, pay-as-you-go — and one account is one row. In plain dollars:

- **A 10-account report ≈ $0.02.** Two cents.
- **A weekly 25-account KPI run ≈ $0.05.** A year of weekly reports stays under $3.

The price is all-inclusive — platform usage is covered, no separate compute or proxy charges. Datacenter proxies are sufficient, and analysis takes seconds per account. Failed and empty runs are not charged.

### Not technical? Let your AI assistant set it up

Copy this into ChatGPT, Claude or any AI assistant, fill in the one line, and follow the conversation:

```text
Help me set up the "Bluesky Engagement Analytics" actor on Apify
(https://apify.com/lowlanddata/bluesky-engagement-analytics). Guide me one step at a time.

What I want to measure: [E.G. "my account myname.bsky.social against nasa.gov and bbc.com"]

Guide me to:
1. Propose my input values: authorHandles (comma-separated Bluesky handles, up to 25),
   maxPostsPerHandle (200 is a good default), and includeReplies if my accounts
   reply a lot.
2. Create a free Apify account (apify.com), open the actor page, paste the values
   into the Input form, and start a run.
3. Set up a weekly Schedule in the Apify Console with the same input, plus an email
   or Slack integration, so the KPI row arrives every week without me touching anything.
4. Show me how to export the rows as CSV/Excel for my report, or read them from the
   API if I code.
5. If the numbers are what I wanted, remind me at the end to leave a quick rating on
   the actor page, and to report anything broken or missing on its Issues tab.
```

### Input

| Field                | Description                                                                                                  |
| -------------------- | ------------------------------------------------------------------------------------------------------------ |
| `authorHandles`      | Comma-separated Bluesky handles, e.g. `"bsky.app, nasa.gov"`. The @ is optional. Up to 25 per run. Required. |
| `maxPostsPerHandle`  | Posts sampled per account, 20–1000 (default 200 — statistics stabilize well before that).                    |
| `includeReplies`     | Count the account's replies in the statistics too (default false).                                           |
| `maxItems`           | Upper bound on account rows.                                                                                 |
| `proxyConfiguration` | Proxy settings; keep Apify proxy enabled.                                                                    |

An unreadable or empty handle costs one row, not the run: it is skipped with a warning, named in the run status, and the rest are delivered.

### Use it from your code

Run the actor and get the KPI rows straight back with one HTTP call:

```bash
curl "https://api.apify.com/v2/acts/lowlanddata~bluesky-engagement-analytics/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>" \
  -X POST -H "Content-Type: application/json" \
  -d '{"authorHandles": "bsky.app, nasa.gov"}'
```

Node.js:

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

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('lowlanddata/bluesky-engagement-analytics').call({
  authorHandles: 'bsky.app, nasa.gov',
  maxPostsPerHandle: 200,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("lowlanddata/bluesky-engagement-analytics").call(
    run_input={"authorHandles": "bsky.app, nasa.gov"})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

Schedules, webhooks and the Make/Zapier/n8n integrations all work out of the box — this is a standard Apify actor.

### Use it with AI agents (MCP)

Claude, Cursor and other MCP-capable agents can run this analyzer as a tool through Apify's hosted MCP server: the agent picks the handles, starts the run and reads the KPI rows itself — no glue code.

Claude Code:

```bash
claude mcp add apify --transport http "https://mcp.apify.com?actors=lowlanddata/bluesky-engagement-analytics"
```

Cursor or Claude Desktop (add a custom connector / MCP server with this URL):

```text
https://mcp.apify.com?actors=lowlanddata/bluesky-engagement-analytics
```

Sign in with your Apify account when prompted — runs are billed to it. Setup details per client: [Apify MCP docs](https://docs.apify.com/platform/integrations/mcp).

Prompts that work once connected:

- "Compare the Bluesky engagement of bsky.app and nasa.gov and tell me who performs better per post."
- "Get the engagement KPIs for these five accounts and rank them by median engagement."
- "Is this account's typical engagement consistent with its top post, or is that post an outlier?"

### Is it legal to analyze Bluesky accounts?

Bluesky is an open network by design: public posts and their engagement counts are served openly by its AppView, without login. This actor reads exactly that public surface, and only for the handles you explicitly request. What leaves the run is smaller still: aggregate statistics per account plus one top-post link — no follower lists, no avatars, no DIDs beyond the top post's own identifier, no per-post dump of anyone's feed. Requests are paced and no rate limits are evaded.

### The AppView is open — why not aggregate it myself?

You can — Bluesky's AppView answers without keys, and this actor never pretends otherwise. What you are buying is the aggregation, not the access: handle resolution, cursor pagination, reply and repost filtering, nearest-rank percentiles, cadence math, per-handle error isolation, and a scheduled row that lands in the same dataset every week. If writing and maintaining that code is a good use of your time, do it; if you want the number in seconds for a fraction of a cent, that is this actor.

### Does Bluesky block this?

There is no bot-wall to fight: the AppView serves public feeds openly, requests are paced with delays between pages, and datacenter proxies are all it takes. If a request is rejected anyway, the actor retries with a rotated session; a handle that stays unreadable is skipped and named in the run status instead of sinking the run.

### How do I track my Bluesky engagement weekly?

Put your handle (and the accounts you benchmark against) in `authorHandles`, run once to check the numbers, then add a weekly Schedule in the Apify Console with an email or Slack integration on the runs. Every week the same metrics arrive computed the same way — diff `medianEngagement` and `postsPerWeek` across weeks and you have your trend line without a spreadsheet formula. The AI-assistant prompt above walks a non-technical user through exactly this setup.

### FAQ

**How do I see my Bluesky engagement rate?** Run the actor on your handle: you get median and p75 likes, median reposts and replies, and median total engagement per post. Note it is engagement *per post*, not engagement divided by followers — this actor does not collect follower counts, by design. If you need a follower-relative rate, divide the medians by your own follower number.

**What is a good number of likes on Bluesky?** It depends entirely on the account's size and niche — which is why the honest answer is a benchmark, not a number. Run your handle next to comparable accounts and read `medianLikes` (typical post) and `p75Likes` (good post) side by side. For scale: `bsky.app` itself runs a median of about 3,500 likes.

**How is posts per week calculated?** Posts sampled ÷ days between the oldest and newest sampled post × 7. An account whose last 100 posts span 412 days posts 1.7 times per week — cadence over the sampled period, not a lifetime average.

**Why medians instead of averages?** One viral post can double an average and tell you nothing about the account's typical performance. Medians (nearest-rank) ignore outliers: `medianLikes` is what the middle post actually got. The outlier is still reported — as the top post, labeled as such.

**What exactly is median engagement?** Likes + reposts + replies are summed per post, and the row carries the median of those sums. It is not the sum of the three separate medians.

**How many posts should I sample?** The default of 200 is enough — the statistics stabilize well before that. Go lower (minimum 20) for a quick check of very active accounts, higher (up to 1,000) if you want the sample to reach further back in time.

**Are the account's replies counted?** Not by default — the statistics cover original posts. Switch on `includeReplies` to count replies too; for accounts that mostly converse, that changes the numbers a lot.

**Are reposts by the account counted?** No. The sample is what the account itself wrote (its author feed posts); reposting someone else's post does not enter the statistics. The `medianReposts` metric is how often *others* repost the account.

**Does one row cover the account's whole history?** No — it reflects the sampled recent posts, up to `maxPostsPerHandle`. That is the useful window for KPIs; it is not an all-time archive.

**Are the like counts exact?** They are the AppView's public numbers at run time — the same counts you see on bsky.app at that moment. Run again later and they may have moved.

**Can I compare several accounts in one run?** Yes — list up to 25 handles comma-separated in `authorHandles`. Each becomes one row in the same table, computed identically, which is the whole point of a benchmark.

**Can I schedule a weekly KPI report?** Yes — add a weekly Schedule in the Apify Console with your handle list, plus an email or Slack integration. The recipe section above spells it out.

**Can I export to Excel or CSV?** Yes — every dataset exports as CSV, Excel, JSON or XML from the Apify Console or API. One row per account pastes cleanly into a report.

**Does it collect followers, avatars or personal data?** No. It analyzes only the handles you explicitly request, and the output is aggregate statistics plus one top-post link — no follower lists, no DIDs, no avatars, no dump of anyone's feed.

**Do I need a Bluesky account or API key?** Neither. The AppView serves public posts without login, and that is the only surface this actor reads.

**What counts as the top post?** The sampled post with the most likes + reposts, delivered with its web link, `topPostLikes` and `topPostReposts` — so you can see the outlier the medians deliberately ignore.

**What if a handle is misspelled or empty?** It is skipped with a warning and named in the run status; the other accounts are delivered normally. If no handle at all could be analyzed, the run fails with a readable message telling you to check the handles.

**How much does it cost?** $1.99 per 1,000 rows, and one account is one row — a 10-account report costs about two cents. All-inclusive; failed and empty runs are not charged.

**Can an AI agent run this analysis?** Yes — connect Apify's hosted MCP server and agents like Claude or Cursor can pick the handles, run the actor and read the KPI rows themselves. Setup is in the MCP section above.

### Related scrapers

This is the social-analytics answer-product of the fleet — it computes the numbers; when you want the underlying posts themselves, use its parent:

- [Bluesky Scraper](https://apify.com/lowlanddata/bluesky-scraper) — the raw posts behind these statistics: text, timestamps, engagement counts, images and links as clean JSON.

More clean-output data sources from the same maker:

- [Kleinanzeigen.de Scraper](https://apify.com/lowlanddata/kleinanzeigen-scraper) — Germany's biggest classifieds site.
- [Vinted Scraper](https://apify.com/lowlanddata/vinted-scraper) — Europe's largest fashion resale marketplace.
- [Rightmove Scraper](https://apify.com/lowlanddata/rightmove-scraper) — the UK's largest property portal.

### Troubleshooting

The actor fails fast with the reason in the run's status message:

- **"None of the requested profiles could be analyzed."** — check the handles; they look like `name.bsky.social` or a custom domain like `nasa.gov`, with or without the @.
- **Some handles noted as unreadable in the status** — those handles are wrong, empty or gone; the remaining rows are delivered normally.
- **`postsPerWeek` or `periodDays` is null** — the sample had fewer than two dated posts, so no period can be measured; the engagement medians are still computed.

### Support

Found an issue or missing a metric you need? Open an issue on the actor's **Issues tab** — reports get fixed, this actor is actively maintained.

Working well for you? A **rating on this page** takes ten seconds and helps other users find a reliable option — it is also the clearest signal of what we should build next.

# Actor input Schema

## `authorHandles` (type: `string`):

One or more Bluesky handles to analyze, comma-separated, e.g. "bsky.app" or "nasa.gov, bbc.com". The @ is optional. Up to 25 per run.

## `maxPostsPerHandle` (type: `integer`):

Posts sampled per account (20-1000). Statistics stabilize well before 200.

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

Count the account's replies in the statistics too.

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

Upper bound on account rows.

## `proxyConfiguration` (type: `object`):

Proxy settings. Keep Apify proxy enabled.

## Actor input object example

```json
{
  "authorHandles": "bsky.app",
  "maxPostsPerHandle": 200,
  "includeReplies": false,
  "maxItems": 25,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `rows` (type: `string`):

One engagement-statistics row per account.

# 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 = {
    "authorHandles": "bsky.app",
    "maxPostsPerHandle": 200,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("lowlanddata/bluesky-engagement-analytics").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 = {
    "authorHandles": "bsky.app",
    "maxPostsPerHandle": 200,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("lowlanddata/bluesky-engagement-analytics").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 '{
  "authorHandles": "bsky.app",
  "maxPostsPerHandle": 200,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call lowlanddata/bluesky-engagement-analytics --silent --output-dataset

```

## MCP server setup

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

```

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/B7rIRb7BMov1mvIjB/builds/PHWYcsooiK3ellFri/openapi.json
