# Bluesky & Mastodon Keyword Monitor: Mentions & Alerts (`prime619/bluesky-mastodon-keyword-monitor`) Actor

Find new public Bluesky and Mastodon posts that mention your brand, product or topic, in any language. Only new posts on a schedule, Excel/CSV and a text digest. Read-only, respects opt-outs, no login or API key.

- **URL**: https://apify.com/prime619/bluesky-mastodon-keyword-monitor.md
- **Developed by:** [Philipp Primisser](https://apify.com/prime619) (community)
- **Categories:** Social media, Marketing, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 mention delivereds

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 & Mastodon Keyword Monitor: Mentions & Alerts

> **Try it free:** Apify's free plan includes monthly platform credit, no credit card needed. One example run with the input below costs about **$0.02** ($0.002 per run + up to 20 mentions at $0.001 each (at most $0.022)).

```json
{
  "keywords": [
    "apify"
  ],
  "platforms": [
    "bluesky",
    "mastodon"
  ],
  "lookbackHours": 24,
  "maxResults": 20
}
```

Paste this into the **JSON** tab of the input form and click **Start**.

Find new public Bluesky and Mastodon posts that mention your brand, product, project, name or topic. Put it on a schedule and every run returns only the posts you have not seen yet. Results come as a table, an Excel file, a CSV and a short text digest you can forward by email or Slack.

No login, no API key and no account on Bluesky or Mastodon needed. The Actor only reads public posts and respects the opt-outs people have set.

### Who it is for

- **Marketing and PR teams** who want to see what people say about their brand
- **Founders and indie developers** watching mentions of their product or open-source project
- **DevRel and community managers** who need to answer questions quickly
- **Journalists and researchers** following a topic, a company or a public debate

### What you get for each post

| Field | Example |
|---|---|
| platform | bluesky or mastodon |
| postedAt | 2026-10-09T10:12:00Z |
| matchedKeywords | \["apify"] |
| text | "New tutorial: Apify, step by step..." |
| url | link to the original post |
| authorName / authorHandle / authorProfileUrl | who posted it, as shown publicly on the post |
| likes / reposts / replies | counts at the time of the run |
| isReply | true if the post is a reply |
| language | language tag set by the author, if any |
| links / hashtags | links and hashtags in the post |
| foundBy | which search found it, for example `bluesky search: apify` or `mastodon mastodon.social: #apify` |
| firstSeenAt | when this Actor first delivered the post |

Every run also writes these files to the run's key-value store:

- `mentions.xlsx`: Excel with filters, frozen header and clickable links
- `mentions.csv`: UTF-8 with BOM, comma or semicolon (semicolon for Excel in Germany, Austria and Switzerland)
- `digest.txt`: a plain-text list, ready to send with an Apify email or Slack integration
- `RUN_SUMMARY`: what was searched, how many posts were scanned, skipped as duplicates, filtered out (and why) and delivered, plus any Mastodon servers that were skipped

### Quick start

1. Enter your keywords, for example `apify`, `"web scraping"`, `#opensource`, `example.com`.
2. Keep both platforms selected and click **Start**.
3. To get alerts: create a **Schedule** (for example every hour with *Look back* = 3 hours, or daily with 30 hours) and add an email or Slack integration that sends `digest.txt`. With **Only new mentions** on (the default), each run delivers only posts that earlier runs have not delivered.

Example input:

```json
{
  "keywords": ["apify", "\"web scraping\"", "#opensource"],
  "excludeKeywords": ["job ad"],
  "platforms": ["bluesky", "mastodon"],
  "languages": ["en", "de"],
  "lookbackHours": 24,
  "onlyNew": true,
  "monitorName": "my-brand"
}
```

### How keywords match

- Words and phrases are case-insensitive and match whole words: `open source` finds "Open Source" but not "opensourced".
- Any language and script works: Latin with accents, Cyrillic, Greek, Arabic, Japanese, Chinese, Korean, Thai. Text is Unicode-normalised first, so full-width letters (`Ａｐｉｆｙ`) and `straße`/`STRASSE` match too.
- Japanese, Chinese, Korean, Thai and similar scripts have no spaces between words, so keywords in those scripts match anywhere in the text (`東京` finds "東京で"). Latin keywords also match next to those scripts: `ChatGPT` finds "ChatGPTで翻訳".
- **Ignore accents** (on by default): `eleicao` finds "eleição", `cafe` finds "café", `Muller` finds "Müller". Japanese voiced marks are not touched. Turn it off if accents change the meaning of your keywords.
- Start with `#` to look for a hashtag: `#python` matches the hashtag, not the plain word.
- Anything with other characters, like `example.com` or `@handle`, matches anywhere in the text or in the post's links.
- A post is only returned if a keyword appears in its **text** (or links/hashtags). Search engines sometimes return posts because a keyword appears only in the author's handle or in a link preview. Those posts are dropped and counted as `noKeywordInText` in `RUN_SUMMARY`.
- **Exclude keywords** drop a post if any of them appear.

### Where the data comes from

- **Bluesky:** the public search endpoint of the Bluesky AppView (`app.bsky.feed.searchPosts` on `api.bsky.app`), sorted by newest. Bluesky allows logged-out search for the **first page only (up to 100 posts per keyword and run)**, and this Actor does not try to page beyond that. If a keyword gets more than 100 posts in your look-back window, run more often with a shorter window.
- **Mastodon:** public hashtag timelines (`/api/v1/timelines/tag/<tag>`) of the servers you choose (default: mastodon.social, fosstodon.org, hachyderm.io). Mastodon has no public full-text search for logged-out visitors, so the Actor reads the hashtag timelines that belong to your keywords (or the hashtags you list) and then checks the post text for your keywords. A server sees its own users' posts plus the posts it has received from other servers, so no list of servers covers the whole fediverse.
- Post content belongs to its authors. Please link to the original post when you quote it.

### Respect for opt-outs and server rules

- **Bluesky:** posts are skipped if the author or the post carries the label `!no-unauthenticated` (the author asked not to be shown to logged-out viewers), or the moderation labels `!hide` or `!takedown`.
- **Mastodon:** only posts with visibility `public`. The author must have opted in to search (`indexable`, or `discoverable` on older servers). Posts are skipped if the account is marked `noindex` or has `#nobot`, `#noindex`, `#nosearch` or `#noarchive` in its bio. Boosts are skipped.
- Before reading a Mastodon server, the Actor reads that server's rules and, where available, its terms of service. If they forbid scraping, crawling, harvesting, data mining or archiving, the server is skipped and named in `RUN_SUMMARY`. Servers that close hashtag timelines to logged-out visitors are skipped too.
- Read-only: the Actor never posts, likes, follows or sends messages. It identifies itself with an honest user agent, spaces its requests and waits when a server asks it to slow down (HTTP 429 / Retry-After).
- Skipped posts are counted as `optedOut` in `RUN_SUMMARY`.

### Pricing

Pay per event. See the **Pricing** tab for current prices. You pay a small fee per run plus a fee per delivered mention. With **Only new mentions** on, runs that find nothing new only cost the run fee. **Maximum results** and Apify's *Maximum cost per run* cap what a run can cost. The run stops cleanly when your limit is reached.

### Limits

- Bluesky: up to 100 newest posts per keyword per run (logged-out search has no paging). Very busy keywords need frequent runs.
- Mastodon: only hashtag timelines, up to 120 posts per hashtag and server per run, at most 5 servers and 10 hashtags. Posts that mention your keyword without the hashtag are only found on Bluesky.
- Up to 20 keywords per run and a look-back of at most 7 days. For more keywords, use several tasks.
- Like, repost and reply counts are a snapshot at run time.
- Edited or deleted posts are not updated or removed from earlier results. If you keep results, delete posts that their authors have deleted.
- Bluesky or a Mastodon server can change or restrict their public APIs at any time. If a source cannot be read, the run says so in its status and in `RUN_SUMMARY` instead of silently returning less.

### Data protection

The results contain public posts and the public name and handle of their authors, nothing more (no follower lists, bios, e-mail addresses or profile pictures). If you are in the EU, you are the controller for what you do with them under the GDPR: use them for a legitimate purpose like brand or media monitoring, keep them only as long as you need them and honour deletion requests.

### Integrations and API

Use the Apify API, scheduled tasks, webhooks or integrations (Slack, email, Google Sheets, Make, Zapier, n8n) to send new mentions where you work. The dataset view "Mentions" shows the most useful columns. The full items contain every field listed above.

### FAQ

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

**Why did a post I can see in the Bluesky app not show up?** It may be older than your look-back window, beyond the first 100 search results, from an author who opted out of logged-out visibility, or the keyword appears only in the handle or link preview.

**Can I monitor a person?** The Actor matches keywords in post text. It is not built for tracking individuals, and you must have a legitimate reason under data-protection law for whatever you monitor.

**Does it work in languages other than English?** Yes. We tested it with Japanese (`ChatGPT`, `東京`) and Brazilian Portuguese (`eleicao`, `Lula`) keywords. Use the **Languages** filter with two-letter codes like `ja`, `pt`, `es`, `de` (`pt-BR` also works). The language tag comes from the author's app and is sometimes missing or wrong. Posts without one are kept. For Mastodon, add servers where your language is spoken, for example `mstdn.jp` or `fedibird.com` (Japanese), `mastodon.com.br` (Portuguese), `masto.es` (Spanish), `mastodon.uno` (Italian), `piaille.fr` (French), `social.tchncs.de` or `norden.social` (German).

**Why does Bluesky return more than Mastodon?** Bluesky has a public full-text search. Mastodon only lets logged-out visitors read hashtag timelines, so posts that contain your keyword without the hashtag are only found on Bluesky.

### Other languages

The English text above is the full documentation. These short summaries are for getting started in your language.

#### 日本語

このActorは、BlueskyとMastodonの公開投稿から、指定したキーワード（ブランド名、製品名、話題など）を含む新しい投稿を集めます。日本語のキーワードは単語の区切りがなくても文中で見つかり、「ChatGPTで」のように英字と日本語が続く場合も検出します。言語フィルターに `ja` を指定すると日本語の投稿だけに絞れます。Mastodonでは、日本語の利用者が多いサーバー（例: mstdn.jp、fedibird.com）を追加してください。ログインやAPIキーは不要で、公開範囲を制限した投稿や検索を拒否しているユーザーの投稿は取得しません。

```json
{
  "keywords": ["ChatGPT", "東京"],
  "languages": ["ja"],
  "mastodonInstances": ["mstdn.jp", "fedibird.com", "mastodon.social"],
  "lookbackHours": 24
}
```

#### Em português (Brasil)

Este Actor encontra posts públicos novos no Bluesky e no Mastodon que mencionam a sua marca, produto ou tema. As palavras-chave funcionam com ou sem acento: "eleicao" também encontra "eleição". Use o filtro de idioma `pt` para receber só posts em português e adicione servidores brasileiros do Mastodon, como mastodon.com.br. Não é preciso login nem chave de API, e posts de autores que pediram para não aparecer em buscas são ignorados.

```json
{
  "keywords": ["eleicao", "sua marca"],
  "languages": ["pt"],
  "mastodonInstances": ["mastodon.com.br", "mastodon.social"],
  "lookbackHours": 24
}
```

#### En español

Este Actor busca publicaciones públicas nuevas en Bluesky y Mastodon que mencionan tu marca, producto o tema. Las palabras clave funcionan con o sin tildes: "cafe" también encuentra "café". Usa el filtro de idioma `es` para recibir solo publicaciones en español y añade servidores de Mastodon en español, como masto.es. No necesitas iniciar sesión ni clave de API, y se omiten las publicaciones de autores que no quieren aparecer en búsquedas.

```json
{
  "keywords": ["cafe", "tu marca"],
  "languages": ["es"],
  "mastodonInstances": ["masto.es", "mastodon.social"],
  "lookbackHours": 24
}
```

#### Auf Deutsch

Dieser Actor findet neue öffentliche Beiträge auf Bluesky und Mastodon, die Ihre Marke, Ihr Produkt oder Ihr Thema erwähnen. Stichwörter funktionieren mit und ohne Umlaute und Akzente: „Muller“ findet auch „Müller“. Mit dem Sprachfilter `de` erhalten Sie nur deutschsprachige Beiträge; für Mastodon können Sie deutschsprachige Server wie social.tchncs.de oder norden.social ergänzen. Mit „Only new mentions“ liefert ein geplanter Lauf nur Beiträge, die seit dem letzten Lauf neu sind. Sie brauchen kein Konto und keinen API-Schlüssel; Beiträge von Personen, die der Suche widersprochen haben, werden übersprungen.

```json
{
  "keywords": ["Ihre Marke", "Muller"],
  "languages": ["de"],
  "mastodonInstances": ["social.tchncs.de", "norden.social", "mastodon.social"],
  "lookbackHours": 24,
  "onlyNew": true
}
```

### Related Actors by the same developer

- [Journalist Request Monitor](https://apify.com/prime619/media-request-monitor): journalist source requests (#journorequest), calls for pitches and podcast guest requests from Bluesky and Mastodon.

# Changelog

This Actor's version history is a separate document: https://apify.com/prime619/bluesky-mastodon-keyword-monitor/changelog.md

# Actor input Schema

## `keywords` (type: `array`):

Brand, product, project or topic names to watch (up to 20), in any language and script. A post must contain at least one of them in its text. Matching is case-insensitive. Words and phrases match whole words ("open source" will not match "opensourced"); in Japanese, Chinese, Korean, Thai and similar scripts, which have no spaces between words, the keyword matches anywhere in the text. Start with # to match a hashtag. Domains like example.com match anywhere in the text or links.

## `excludeKeywords` (type: `array`):

Drop posts that contain any of these, for example job ad or giveaway.

## `ignoreAccents` (type: `boolean`):

Match keywords with or without accents: "eleicao" finds "eleição", "Muller" finds "Müller", "cafe" finds "café". Japanese, Chinese, Korean and other scripts are unaffected. Turn off if accents change the meaning of your keywords.

## `platforms` (type: `array`):

Where to look.

## `mastodonInstances` (type: `array`):

Up to 5 servers to read. Each server shows its own users' posts and the posts it has received from others. Servers whose rules forbid automated collection, or that close their hashtag timelines to logged-out visitors, are skipped and listed in RUN_SUMMARY.

## `mastodonHashtags` (type: `array`):

Mastodon has no public full-text search, so the Actor reads hashtag timelines. Leave empty to use your keywords as hashtags ("open source" becomes #opensource). Posts still need a keyword in the text.

## `languages` (type: `array`):

Two-letter language codes, for example en, pt, es, ja, de. Leave empty for all languages. Posts without a language tag are kept. With exactly one language, Bluesky filters on the server, so you get up to 100 posts in that language per keyword.

## `lookbackHours` (type: `integer`):

How far back to search. For an hourly schedule use 3, for a daily schedule 30.

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

Also return replies that mention your keywords.

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

Only keep posts with at least this many likes (favourites). 0 keeps everything.

## `onlyNew` (type: `boolean`):

Skip posts that an earlier run with the same settings already delivered. You only pay for new mentions.

## `monitorName` (type: `string`):

Optional. Runs with the same name share their memory of delivered posts, even if you change the keywords.

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

Upper limit of mentions per run (newest first).

## `csvDelimiter` (type: `string`):

Separator for mentions.csv.

## Actor input object example

```json
{
  "keywords": [
    "apify"
  ],
  "excludeKeywords": [],
  "ignoreAccents": true,
  "platforms": [
    "bluesky",
    "mastodon"
  ],
  "mastodonInstances": [
    "mastodon.social",
    "fosstodon.org",
    "hachyderm.io"
  ],
  "mastodonHashtags": [],
  "languages": [],
  "lookbackHours": 24,
  "includeReplies": true,
  "minLikes": 0,
  "onlyNew": true,
  "monitorName": "",
  "maxResults": 100,
  "csvDelimiter": "comma"
}
```

# Actor output Schema

## `mentions` (type: `string`):

One row per matching post.

## `excel` (type: `string`):

mentions.xlsx with filters and clickable links.

## `csv` (type: `string`):

mentions.csv (UTF-8 with BOM).

## `digest` (type: `string`):

digest.txt for email or Slack.

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

What was searched, skipped and delivered.

# 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 = {
    "keywords": [
        "apify"
    ],
    "platforms": [
        "bluesky",
        "mastodon"
    ],
    "mastodonInstances": [
        "mastodon.social",
        "fosstodon.org",
        "hachyderm.io"
    ],
    "lookbackHours": 24,
    "maxResults": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("prime619/bluesky-mastodon-keyword-monitor").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 = {
    "keywords": ["apify"],
    "platforms": [
        "bluesky",
        "mastodon",
    ],
    "mastodonInstances": [
        "mastodon.social",
        "fosstodon.org",
        "hachyderm.io",
    ],
    "lookbackHours": 24,
    "maxResults": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("prime619/bluesky-mastodon-keyword-monitor").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 '{
  "keywords": [
    "apify"
  ],
  "platforms": [
    "bluesky",
    "mastodon"
  ],
  "mastodonInstances": [
    "mastodon.social",
    "fosstodon.org",
    "hachyderm.io"
  ],
  "lookbackHours": 24,
  "maxResults": 100
}' |
apify call prime619/bluesky-mastodon-keyword-monitor --silent --output-dataset

```

## MCP server setup

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

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/CDjQALOGJxUN1UdSZ/builds/lHZ9Tk5OYfafm7LeE/openapi.json
