# Mastodon Scraper (`anyxsolutions/mastodon-scraper`) Actor

Scrape Mastodon from any server: hashtag timelines, profiles, single posts with their replies, and trending posts, hashtags and news links. Post text, media, engagement counts, authors, polls and boosts as clean JSON. No login, no API key, no proxy.

- **URL**: https://apify.com/anyxsolutions/mastodon-scraper.md
- **Developed by:** [Anyx Solutions](https://apify.com/anyxsolutions) (community)
- **Categories:** Social media, News
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 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?

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

![banner](https://anyx.solutions/banners/mastodon-scraper.png)

## Mastodon Scraper

**Scrape Mastodon posts from any server — hashtags, profiles, threads and trends — as clean JSON, with no login.**

Scrape Mastodon from any server: hashtag timelines, profiles, single posts with their replies, and
trending posts, hashtags and news links. Paste a page from mastodon.social, fosstodon.org,
hachyderm.io or any other Mastodon server, or just type hashtags. Each post comes with its text as
HTML and plain text, content warning, language, replies, boosts and favourites, the author's handle
and follower counts, images and videos with their alt text, hashtags, mentions, link preview, poll
results, and the original post when it is a boost. There is no login, no API key, and no proxy to
configure. Built for social-listening and brand teams, researchers studying the fediverse, journalists
and community managers.

### ⚡ Quick start

```json
{
  "startUrls": [
    { "url": "https://mastodon.social/tags/photography" },
    { "url": "https://mastodon.social/@Mastodon" }
  ],
  "hashtags": ["opensource"],
  "maxItems": 5
}
```

### 🧩 Input

| Field                | Type    | Required | Default                      | Description                                                                                                                                                                                                                                                                                                                                                                                                                                |
| -------------------- | ------- | -------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `startUrls`          | array   | no       | —                            | Public pages from any Mastodon server: a hashtag (`https://mastodon.social/tags/photography`), a profile (`https://mastodon.social/@Mastodon`, or a remote one such as `https://mastodon.social/@kev@fosstodon.org`), a single post (`https://mastodon.social/@Mastodon/117411420916699261`), trending posts, hashtags or links (`/explore`, `/explore/tags`, `/explore/links`), or a server's live timeline (`/public/local`, `/public`). |
| `hashtags`           | array   | no       | —                            | Hashtags to scrape on the server below, one per line, with or without the `#`, for example `opensource` or `#photography`.                                                                                                                                                                                                                                                                                                                 |
| `instance`           | string  | no       | `mastodon.social`            | Server for hashtags: the Mastodon server whose hashtag timelines the hashtags are read from, for example `fosstodon.org` or `hachyderm.io`.                                                                                                                                                                                                                                                                                                |
| `includeReplies`     | boolean | no       | `false`                      | Include replies: for a single post URL, also return the replies under it; for a profile URL, also return the account's replies to other people.                                                                                                                                                                                                                                                                                            |
| `maxItems`           | integer | no       | —                            | Maximum number of items per start URL or hashtag. The input form starts at 5; leave it empty to get everything the server shares.                                                                                                                                                                                                                                                                                                          |
| `proxyConfiguration` | object  | no       | `{ "useApifyProxy": false }` | Proxy settings. Mastodon needs no proxy.                                                                                                                                                                                                                                                                                                                                                                                                   |

Add URLs, hashtags, or both. A profile on another server, such as `https://mastodon.social/@kev@fosstodon.org`,
is read from the account's own server, which holds its full history. Hashtags, `/explore` and `/public` pages
show what the server in the URL knows about, so the same hashtag can return different posts on different servers.

### 📤 Output

Every row carries an `itemType`. Hashtag, profile, post and timeline URLs, and `/explore`, return `post` rows,
newest first (trending posts in trending order). `/explore/tags` returns trending hashtags as `tag` rows and
`/explore/links` returns trending news stories as `link` rows.

#### Fields

| Field              | Type    | Description                                                                                                                                                                        |
| ------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `itemType`         | string  | `post`, `tag` or `link`.                                                                                                                                                           |
| `id`               | string  | Post rows: post ID on the server it was read from. Tag rows: hashtag ID.                                                                                                           |
| `url`              | string  | Post rows: the post's page on its origin server. Tag rows: the hashtag page. Link rows: the news story.                                                                            |
| `uri`              | string  | Post rows: the post's permanent fediverse identifier.                                                                                                                              |
| `createdAt`        | string  | Post rows: ISO time the post was published.                                                                                                                                        |
| `editedAt`         | string  | Post rows: ISO time of the last edit, or `null`.                                                                                                                                   |
| `language`         | string  | Language code of the post or story, e.g. `en`, or `null`.                                                                                                                          |
| `contentHtml`      | string  | Post rows: post body as HTML, or `null` (boosts carry it in `reblog`).                                                                                                             |
| `contentText`      | string  | Post rows: post body as plain text, with full links and paragraph breaks.                                                                                                          |
| `spoilerText`      | string  | Post rows: the content warning shown before the post, or `null`.                                                                                                                   |
| `sensitive`        | boolean | Post rows: `true` when the media is marked sensitive.                                                                                                                              |
| `visibility`       | string  | Post rows: `public` or `unlisted`.                                                                                                                                                 |
| `inReplyToId`      | string  | Post rows: ID of the post this one replies to, or `null`.                                                                                                                          |
| `repliesCount`     | integer | Post rows: number of replies.                                                                                                                                                      |
| `reblogsCount`     | integer | Post rows: number of boosts.                                                                                                                                                       |
| `favouritesCount`  | integer | Post rows: number of favourites.                                                                                                                                                   |
| `account`          | object  | Post rows: the author as `{ id, acct, displayName, url, followersCount, followingCount, statusesCount, bot, avatar }`; `acct` is the full handle, e.g. `Mastodon@mastodon.social`. |
| `mediaAttachments` | array   | Post rows: images, videos and audio as `{ type, url, previewUrl, description }`; `description` is the alt text.                                                                    |
| `tags`             | array   | Post rows: hashtags used in the post, lower-case, without `#`.                                                                                                                     |
| `mentions`         | array   | Post rows: mentioned accounts as `{ acct, url }`.                                                                                                                                  |
| `card`             | object  | Post rows: link preview as `{ url, title, description, image }`, or `null`.                                                                                                        |
| `poll`             | object  | Post rows: `{ id, expiresAt, expired, multiple, votesCount, votersCount, options: [{ title, votesCount }] }`, or `null`.                                                           |
| `reblog`           | object  | Post rows: when the row is a boost, the original post with the same fields; otherwise `null`.                                                                                      |
| `instance`         | string  | The server the row was read from, e.g. `mastodon.social`.                                                                                                                          |
| `name`             | string  | Tag rows: the hashtag, without `#`.                                                                                                                                                |
| `usesLastWeek`     | integer | Tag and link rows: posts using the hashtag or sharing the link over the last 7 days.                                                                                               |
| `accountsLastWeek` | integer | Tag and link rows: accounts using the hashtag or sharing the link over the last 7 days.                                                                                            |
| `history`          | array   | Tag and link rows: daily `{ date, uses, accounts }`, newest first.                                                                                                                 |
| `title`            | string  | Link rows: the story's headline.                                                                                                                                                   |
| `description`      | string  | Link rows: the story's summary.                                                                                                                                                    |
| `providerName`     | string  | Link rows: the publisher, e.g. `The Guardian`.                                                                                                                                     |
| `authorName`       | string  | Link rows: the story's author, or `null`.                                                                                                                                          |
| `image`            | string  | Link rows: the story's preview image.                                                                                                                                              |
| `publishedAt`      | string  | Link rows: ISO time the story was published, or `null`.                                                                                                                            |

<details><summary>Example output</summary>

```json
[
  {
    "itemType": "post",
    "id": "117411420916699261",
    "url": "https://mastodon.social/@Mastodon/117411420916699261",
    "uri": "https://mastodon.social/users/Mastodon/statuses/117411420916699261",
    "createdAt": "2026-10-09T14:28:25.298Z",
    "editedAt": null,
    "language": "en",
    "contentHtml": "<p>New <a href=\"https://mastodon.social/tags/Plushtodon\" class=\"mention hashtag\" rel=\"tag\">#<span>Plushtodon</span></a> colours now available for pre-orders on our shop! This is a way to support our work and get a squishy friend at the same time.</p><p><a href=\"https://blog.joinmastodon.org/2026/10/plushtodon-pre-orders-now-open/\" target=\"_blank\" rel=\"nofollow noopener\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"ellipsis\">blog.joinmastodon.org/2026/10/</span><span class=\"invisible\">plushtodon-pre-orders-now-open/</span></a></p><p><a href=\"https://mastodon.social/tags/Merchtodon\" class=\"mention hashtag\" rel=\"tag\">#<span>Merchtodon</span></a></p>",
    "contentText": "New #Plushtodon colours now available for pre-orders on our shop! This is a way to support our work and get a squishy friend at the same time.\n\nhttps://blog.joinmastodon.org/2026/10/plushtodon-pre-orders-now-open/\n\n#Merchtodon",
    "spoilerText": null,
    "sensitive": false,
    "visibility": "public",
    "inReplyToId": null,
    "repliesCount": 15,
    "reblogsCount": 126,
    "favouritesCount": 156,
    "account": {
      "id": "13179",
      "acct": "Mastodon@mastodon.social",
      "displayName": "Mastodon",
      "url": "https://mastodon.social/@Mastodon",
      "followersCount": 878925,
      "followingCount": 51,
      "statusesCount": 565,
      "bot": false,
      "avatar": "https://files.mastodon.social/accounts/avatars/000/013/179/original/b4ceb19c9c54ec7e.png"
    },
    "mediaAttachments": [],
    "tags": ["plushtodon", "merchtodon"],
    "mentions": [],
    "card": {
      "url": "https://blog.joinmastodon.org/2026/10/plushtodon-pre-orders-now-open/",
      "title": "Plushtodon pre-orders now open",
      "description": "They're small, they're soft, they're squishy, and they are your friend! If you missed out on our stuffed toys before, now is your chance to pre-order our latest series in Matcha Baku and Hitori Pink.",
      "image": "https://files.mastodon.social/cache/preview_cards/images/210/210/286/original/30d703e6eed07ce8.jpg"
    },
    "poll": null,
    "reblog": null,
    "instance": "mastodon.social"
  },
  {
    "itemType": "tag",
    "id": "21533570",
    "name": "DontAskASong",
    "url": "https://mastodon.social/tags/dontaskasong",
    "usesLastWeek": 234,
    "accountsLastWeek": 67,
    "history": [
      {
        "date": "2026-10-13",
        "uses": 0,
        "accounts": 0
      },
      {
        "date": "2026-10-12",
        "uses": 234,
        "accounts": 67
      },
      {
        "date": "2026-10-11",
        "uses": 0,
        "accounts": 0
      },
      {
        "date": "2026-10-10",
        "uses": 0,
        "accounts": 0
      },
      {
        "date": "2026-10-09",
        "uses": 0,
        "accounts": 0
      },
      {
        "date": "2026-10-08",
        "uses": 0,
        "accounts": 0
      },
      {
        "date": "2026-10-07",
        "uses": 0,
        "accounts": 0
      }
    ],
    "instance": "mastodon.social"
  }
]
```

</details>

### 💡 Use cases

- **Social listening** — follow a brand, product or campaign hashtag across the fediverse.
- **Account monitoring** — track what an organisation, journalist or developer posts, with engagement over time.
- **Trend research** — snapshot a server's trending posts, hashtags and news stories on a schedule.
- **Thread analysis** — capture a post together with its replies for sentiment analysis or moderation review.
- **Datasets** — build multilingual, alt-text-rich post collections for research and training.

### ❓ FAQ

- **Do I need a Mastodon account or an API key?** No. The Actor only reads what each server shows to logged-out visitors.
- **Which servers work?** Any Mastodon server, and most fediverse servers that speak the Mastodon API. Paste the page URL from that server.
- **Can I search posts by keyword?** Mastodon only offers full-text post search to logged-in users, so keyword search is not available. Use hashtags instead: they are how Mastodon users tag topics.
- **Why did a `/public` URL return nothing?** Many servers, mastodon.social among them, keep their live timeline for logged-in users. The run log says so in plain words. Hashtags, profiles, posts and `/explore` pages still work on those servers.
- **How many replies does a post return?** Up to about 60 replies for logged-out visitors, which is the limit Mastodon itself applies.
- **Are boosts included?** Yes. A boost is a row of the booster's account whose `reblog` field holds the original post with its author, text and counts.
- **Is the Actor gentle on servers?** Yes. Mastodon servers are community-run and allow 300 requests per 5 minutes; the Actor reads the server's own limit and pauses before reaching it.
- **Why did a run return fewer items than expected?** A small server may know few posts for a hashtag, an account may have few public posts, or the server may keep a list private. Check the run log, then open an issue if something looks off.

### 🔗 More scrapers by Anyx

- [Bluesky Scraper](https://apify.com/anyxsolutions/bluesky-scraper)
- [Threads Scraper](https://apify.com/anyxsolutions/threads-scraper)
- [X (Twitter) Scraper](https://apify.com/anyxsolutions/x-twitter-scraper)
- [Reddit Scraper](https://apify.com/anyxsolutions/reddit-scraper)

### 🤝 Anyx Solutions

We build custom scrapers and data-extraction pipelines.

- Email: tantosthor@gmail.com

### 🖼 Image credit

Image credit: [mastodon.social](https://mastodon.social/)

# Actor input Schema

## `startUrls` (type: `array`):

Public pages from any Mastodon server: a hashtag (https://mastodon.social/tags/photography), a profile (https://mastodon.social/@Mastodon, or a remote one such as https://mastodon.social/@kev@fosstodon.org), a single post (https://mastodon.social/@Mastodon/117411420916699261), trending posts, hashtags or links (/explore, /explore/tags, /explore/links), or a server's live timeline (/public/local, /public).

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

Hashtags to scrape on the server below, one per line, with or without the #, for example "opensource" or "#photography". Each one returns up to Maximum items of the newest posts.

## `instance` (type: `string`):

The Mastodon server whose hashtag timelines the Hashtags above are read from, for example mastodon.social, fosstodon.org or hachyderm.io. Each server shows the posts it knows about, so results differ between servers.

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

For a single post URL, also return the replies under it. For a profile URL, also return the account's replies to other people, not only its own posts and boosts.

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

Maximum number of items to return per start URL or hashtag. Leave empty for everything the server shares.

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

Proxy settings. Mastodon data is public and needs no proxy.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://mastodon.social/tags/photography"
    },
    {
      "url": "https://mastodon.social/@Mastodon"
    }
  ],
  "hashtags": [
    "opensource"
  ],
  "instance": "mastodon.social",
  "includeReplies": false,
  "maxItems": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `overview` (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 = {
    "startUrls": [
        {
            "url": "https://mastodon.social/tags/photography"
        },
        {
            "url": "https://mastodon.social/@Mastodon"
        }
    ],
    "hashtags": [
        "opensource"
    ],
    "maxItems": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("anyxsolutions/mastodon-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 = {
    "startUrls": [
        { "url": "https://mastodon.social/tags/photography" },
        { "url": "https://mastodon.social/@Mastodon" },
    ],
    "hashtags": ["opensource"],
    "maxItems": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("anyxsolutions/mastodon-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 '{
  "startUrls": [
    {
      "url": "https://mastodon.social/tags/photography"
    },
    {
      "url": "https://mastodon.social/@Mastodon"
    }
  ],
  "hashtags": [
    "opensource"
  ],
  "maxItems": 5
}' |
apify call anyxsolutions/mastodon-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,anyxsolutions/mastodon-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/3nhTTN0XrqUe73sNo/builds/fIjDi70GiXTjVDtcf/openapi.json
