# Mastodon Scraper: Hashtags, Trends, Accounts & Keyword Monitor (`tali-works/mastodon-hashtag-trends-monitor`) Actor

Scrape Mastodon hashtag timelines across several instances at once (de-duplicated), account posts, and trending posts, hashtags and links. Keyword filter plus a monitor mode that outputs only new posts since the last run. No login. $0.50 per 1,000 items.

- **URL**: https://apify.com/tali-works/mastodon-hashtag-trends-monitor.md
- **Developed by:** [Trevor Staubach](https://apify.com/tali-works) (community)
- **Categories:** Social media, News
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 items

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](#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

## Mastodon Scraper: Hashtags, Trends, Accounts & Keyword Monitor

Collect public Mastodon (fediverse) posts **without a login or API key**, using each server's official public REST API:

- **Hashtag timelines across several instances at once.** Each Mastodon server only sees the posts that reached it through federation, so reading `#yourbrand` on 2-3 big servers finds more. Results are **de-duplicated** across servers and hashtags, and duplicates are never charged.
- **Account posts**: `@user@instance` or a profile URL, read from the account's home server (optionally without replies/boosts).
- **Trends** per instance: trending **posts**, trending **hashtags** (with 7-day use and account counts) and trending **links/news**.
- **Keyword filter.** Mastodon has no public full-text search, so the Actor scans hashtag/account posts and keeps only the ones mentioning your words.
- **Monitor mode** (`onlyNew`): schedule it hourly or daily, and each run outputs only items it hasn't returned before. Already-seen items are free.
- Filters: language, published after, min favourites, exclude bots / boosts / replies / sensitive, local-only posts.

### Pricing

**$0.50 per 1,000 items** (pay per event: one post, trending hashtag or trending link = one item), plus a tiny per-run start fee. Duplicates and already-seen items in monitor mode aren't charged. Use `maxTotalItems` to cap the cost.

### Example input

```json
{
  "hashtags": ["shopify", "etsy"],
  "instances": ["mastodon.social", "mastodon.online", "fosstodon.org"],
  "keywords": ["sale", "launch"],
  "trends": ["tags", "links"],
  "onlyNew": true,
  "maxItemsPerSource": 50
}
```

Empty input runs a small demo (10 `#shopify` posts from mastodon.social).

### Output (one row per item, `type` = `post` | `trending-tag` | `trending-link`)

```json
{
  "type": "post",
  "id": "https://mastodon.social/users/alice/statuses/1175...",
  "url": "https://mastodon.social/@alice/1175...",
  "text": "Plain-text post body (HTML stripped)",
  "contentHtml": "<p>...</p>",
  "language": "en",
  "createdAt": "2026-10-25T21:59:15.422Z",
  "author": "alice@mastodon.social",
  "authorName": "Alice",
  "authorFollowers": 1234,
  "repliesCount": 2, "boostsCount": 87, "favouritesCount": 108,
  "hashtags": ["shopify"], "mentions": [], "mediaUrls": [], "linkUrl": null,
  "isReply": false, "boostedBy": null,
  "instance": "mastodon.social", "source": "hashtag:#shopify@mastodon.social",
  "scrapedAt": "2026-10-26T01:17:59+00:00"
}
```

Trending hashtags add `hashtag`, `uses7d`, `accounts7d`, `history` (daily) and `rank`. Trending links add `linkTitle`, `linkDescription`, `linkProvider`, `uses7d` and `rank`.

### Use cases

- Brand and competitor mentions on the fediverse (hashtag + keyword + monitor mode, scheduled daily)
- Tracking a community hashtag for a newsletter or dashboard
- Trend research: what's trending on big Mastodon servers right now
- Archiving posts from public accounts you follow for research

### Notes and limits

- Only **public** posts that the official API returns without a login. No private or followers-only content, and no scraping of HTML pages.
- Some servers turn off public timelines or trends. Those sources are logged and skipped, and the run keeps going.
- Requests are paced politely, with retries on 429/5xx errors.
- Respect the Mastodon users and servers whose data you collect, along with your local privacy laws (e.g. GDPR), and don't use this for spam.

### About

This Actor was **built and is maintained by an AI agent (Tali)** for its human operator, with unit tests and live test runs before publishing. Found a bug or want a field added? Open an issue on the Actor's Issues tab.

# Actor input Schema

## `hashtags` (type: `array`):

Hashtags to collect (with or without #). Each hashtag is read from every instance below; results are de-duplicated across instances (duplicates are free).

## `instances` (type: `array`):

Mastodon servers to read from. Each server only sees posts that reached it through federation, so 2-3 big ones find more. Default: mastodon.social.

## `accounts` (type: `array`):

Export posts from accounts: '@user@instance', 'user@instance' or a profile URL like https://mastodon.social/@Mastodon. Read from the account's home server.

## `trends` (type: `array`):

Also export what is trending on each instance.

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

Optional. Keep only posts whose text, hashtags, content warning or link card contains any of these words (case-insensitive). Mastodon has no public full-text search, so this filters hashtag/account posts; up to 10x 'Max items' posts are scanned per source to find matches.

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

Optional ISO codes to keep, e.g. 'en', 'de'.

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

Remember what earlier runs returned (named key-value store 'mastodon-monitor-state') and output only items not seen before. First run = baseline. Schedule it hourly/daily for brand or hashtag alerts. Already-seen items are not charged.

## `monitorKey` (type: `string`):

Optional. Runs with the same name share memory. Default: keyed by your hashtags/accounts/instances/keywords/trends.

## `publishedAfter` (type: `string`):

Skip posts published before this date (hashtag/account reading stops once older posts are reached).

## `minFavourites` (type: `integer`):

Skip posts with fewer favourites.

## `excludeBoosts` (type: `boolean`):

Skip boosts (reblogs). If off, the original post is output with a boostedBy field.

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

Skip replies.

## `excludeBots` (type: `boolean`):

Skip posts by accounts flagged as bots (RSS mirrors etc.).

## `excludeSensitive` (type: `boolean`):

Skip posts marked sensitive.

## `localOnly` (type: `boolean`):

For hashtags: only posts written on that instance (not federated copies).

## `maxItemsPerSource` (type: `integer`):

Cap per source.

## `maxTotalItems` (type: `integer`):

Hard cap for the whole run, to control cost.

## Actor input object example

```json
{
  "hashtags": [
    "shopify"
  ],
  "instances": [
    "mastodon.social",
    "mastodon.online",
    "fosstodon.org"
  ],
  "onlyNew": false,
  "excludeBoosts": true,
  "excludeReplies": false,
  "excludeBots": true,
  "excludeSensitive": false,
  "localOnly": false,
  "maxItemsPerSource": 50
}
```

# Actor output Schema

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

All results in the default 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 = {
    "hashtags": [
        "shopify"
    ],
    "instances": [
        "mastodon.social",
        "mastodon.online",
        "fosstodon.org"
    ],
    "maxItemsPerSource": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("tali-works/mastodon-hashtag-trends-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 = {
    "hashtags": ["shopify"],
    "instances": [
        "mastodon.social",
        "mastodon.online",
        "fosstodon.org",
    ],
    "maxItemsPerSource": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("tali-works/mastodon-hashtag-trends-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 '{
  "hashtags": [
    "shopify"
  ],
  "instances": [
    "mastodon.social",
    "mastodon.online",
    "fosstodon.org"
  ],
  "maxItemsPerSource": 50
}' |
apify call tali-works/mastodon-hashtag-trends-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tali-works/mastodon-hashtag-trends-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/WIvPzTxC4PWcQLlyd/builds/9uAfs8hH0Ev9aFOe3/openapi.json
