# Mastodon Scraper - Profiles, Posts, Hashtags & Search (`hospitable_easel/mastodon-account-scraper`) Actor

Scrape public Mastodon accounts with no login: profile stats, recent posts with engagement (favourites/boosts/replies), and account discovery search across the fediverse.

- **URL**: https://apify.com/hospitable\_easel/mastodon-account-scraper.md
- **Developed by:** [aki ra](https://apify.com/hospitable_easel) (community)
- **Categories:** Social media, Lead generation, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-usage

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

## Mastodon Scraper — Profiles, Posts, Followers & Account Search (No Login)

**Scrape public Mastodon data without an access token, app, or login.** Get profile
stats, recent posts with engagement (favourites, boosts, replies), and discover accounts
by search query — across any instance in the fediverse. Export to **JSON, CSV, or Excel**.

> No OAuth. No app registration. No anti-bot challenges. Just pass `user@instance`
> handles (or a search term) and get clean, structured data.

### What you can scrape

- **Mastodon profile stats** — followers, following, posts count, bio, display name, avatar, bot flag, account created date
- **Recent posts (toots)** — text, timestamp, language, visibility, and per-post engagement (favourites, boosts/reblogs, replies), each with a direct post URL
- **Hashtag feeds** — scrape recent public posts for any hashtag on an instance, with engagement
- **Account discovery / search** — find Mastodon accounts matching a query (handle, display name, or bio)

### Common use cases

- **Lead generation** — build lists of Mastodon accounts in a niche and pull their bio + reach
- **Competitor & brand monitoring** — track what specific accounts post and how it performs
- **Influencer research** — rank fediverse accounts by followers and engagement before outreach
- **Social listening** — watch a fixed set of accounts for new posts
- **AI / LLM datasets** — feed clean Mastodon text + engagement into your models or agents

### How to use it

1. Enter one or more Mastodon **handles** as `user@instance` (e.g. `Gargron@mastodon.social`) — or a **search query** to discover accounts
2. Optionally set how many recent posts to fetch per account (0–1000)
3. Run the Actor and **download the results as JSON, CSV, or Excel**

At least one of `handles` or `searchQuery` is required.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `handles` | array | `["Gargron@mastodon.social"]` | Handles as `user@instance` (the `@` prefix is optional) |
| `maxPostsPerAccount` | integer | `50` | Recent posts per handle (0–1000) |
| `includeProfile` | boolean | `true` | Emit one profile record per handle |
| `searchQuery` | string | — | Optional: find accounts matching this text |
| `searchLimit` | integer | `25` | Max accounts from the search query |
| `searchInstance` | string | `mastodon.social` | Instance to run the account search against |
| `hashtags` | array | — | Optional: scrape recent public posts for these hashtags |
| `maxHashtagPosts` | integer | `50` | Recent posts per hashtag |
| `hashtagInstance` | string | `mastodon.social` | Instance to read hashtag timelines from |

### Output (dataset records)

Records are tagged by `type`: `profile`, `post`, `account_hit`, or `error`. Every dataset
can be exported to **JSON, CSV, Excel, XML, or HTML** from the Apify console or API. Post
and bio HTML is converted to clean plain text.

Example post record:

```json
{
  "type": "post",
  "account": "Gargron@mastodon.social",
  "authorHandle": "Gargron",
  "text": "Mastodon is decentralized social media.",
  "createdAt": "2026-06-26T20:36:12.000Z",
  "favouritesCount": 791, "reblogsCount": 993, "repliesCount": 42,
  "language": "en",
  "postUrl": "https://mastodon.social/@Gargron/116827981"
}
````

### Why it stays fast and low-maintenance

All data comes from Mastodon's **public REST API** (`/api/v1/accounts/lookup`,
`/api/v1/accounts/{id}/statuses`, `/api/v2/search`) — open, documented endpoints that need
**no access token, no app registration, and no anti-bot challenge**. There are no
credentials to rotate, so the Actor rarely breaks (unlike HTML scrapers fighting anti-bot
systems). It paces requests politely and retries on rate limits (HTTP 429) with backoff.

### Pricing

**Pay per result** — you only pay for the records you actually get. No monthly subscription.
See the live price on the Store page; a generous free tier lets you test before you commit.

### FAQ

**Do I need a Mastodon account, app, or access token?**
No. This Actor only reads Mastodon's public data, so there is nothing to log in to.

**Does it work across different Mastodon instances?**
Yes. Mastodon is federated — pass any handle as `user@instance` and the Actor queries that
account's home instance directly.

**What output formats are supported?**
Any Apify dataset can be exported to JSON, CSV, Excel, XML, or HTML, or pulled via the API.

**Can it scrape the global public timeline or full-text post search?**
No. Many instances require authentication for the public timeline (`/api/v1/timelines/public`
returns 422 unauthenticated), so this Actor is intentionally **account-centric** to stay
credential-free.

**How many posts can I get per account?**
Up to 1000 recent posts per handle (set with `maxPostsPerAccount`). Reblogs are excluded so
you get the account's own posts.

**Is it legal to scrape Mastodon?**
This Actor accesses only public data through Mastodon's official public API. You are
responsible for complying with each instance's terms and any applicable laws and privacy
regulations in your use.

### Local development

The core client (`mastodon_client.py`) uses only the Python standard library:

```bash
python3 -c "from mastodon_client import scrape; print(list(scrape(['Gargron@mastodon.social'], max_posts_per_account=3)))"
```

The Actor wrapper (`src/`) additionally needs the `apify` SDK and the Apify CLI to run via
`apify run` and to publish via `apify push`.

# Actor input Schema

## `handles` (type: `array`):

Mastodon handles to scrape, as user@instance (e.g. Gargron@mastodon.social). The @ prefix is optional.

## `maxPostsPerAccount` (type: `integer`):

How many recent posts to fetch per handle.

## `includeProfile` (type: `boolean`):

Also emit one profile record per handle (followers, statuses count, bio).

## `searchQuery` (type: `string`):

Optionally find accounts matching this text (handle / display name / bio).

## `searchLimit` (type: `integer`):

How many accounts to return for the search query.

## `searchInstance` (type: `string`):

Which Mastodon instance to run the account search against.

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

Optionally scrape recent public posts for these hashtags (without #).

## `maxHashtagPosts` (type: `integer`):

How many recent posts to fetch per hashtag.

## `hashtagInstance` (type: `string`):

Which Mastodon instance to read hashtag timelines from.

## Actor input object example

```json
{
  "handles": [
    "Gargron@mastodon.social"
  ],
  "maxPostsPerAccount": 50,
  "includeProfile": true,
  "searchLimit": 25,
  "searchInstance": "mastodon.social",
  "maxHashtagPosts": 50,
  "hashtagInstance": "mastodon.social"
}
```

# 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 = {
    "handles": [
        "Gargron@mastodon.social"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("hospitable_easel/mastodon-account-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 = { "handles": ["Gargron@mastodon.social"] }

# Run the Actor and wait for it to finish
run = client.actor("hospitable_easel/mastodon-account-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "handles": [
    "Gargron@mastodon.social"
  ]
}' |
apify call hospitable_easel/mastodon-account-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=hospitable_easel/mastodon-account-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Mastodon Scraper - Profiles, Posts, Hashtags & Search",
        "description": "Scrape public Mastodon accounts with no login: profile stats, recent posts with engagement (favourites/boosts/replies), and account discovery search across the fediverse.",
        "version": "0.1",
        "x-build-id": "clj4PoHP38fciilFk"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/hospitable_easel~mastodon-account-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-hospitable_easel-mastodon-account-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/hospitable_easel~mastodon-account-scraper/runs": {
            "post": {
                "operationId": "runs-sync-hospitable_easel-mastodon-account-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/hospitable_easel~mastodon-account-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-hospitable_easel-mastodon-account-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "handles": {
                        "title": "Account handles",
                        "type": "array",
                        "description": "Mastodon handles to scrape, as user@instance (e.g. Gargron@mastodon.social). The @ prefix is optional.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxPostsPerAccount": {
                        "title": "Max posts per account",
                        "minimum": 0,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "How many recent posts to fetch per handle.",
                        "default": 50
                    },
                    "includeProfile": {
                        "title": "Include profile stats",
                        "type": "boolean",
                        "description": "Also emit one profile record per handle (followers, statuses count, bio).",
                        "default": true
                    },
                    "searchQuery": {
                        "title": "Account search query (optional)",
                        "type": "string",
                        "description": "Optionally find accounts matching this text (handle / display name / bio)."
                    },
                    "searchLimit": {
                        "title": "Max accounts from search",
                        "minimum": 1,
                        "maximum": 40,
                        "type": "integer",
                        "description": "How many accounts to return for the search query.",
                        "default": 25
                    },
                    "searchInstance": {
                        "title": "Search instance",
                        "type": "string",
                        "description": "Which Mastodon instance to run the account search against.",
                        "default": "mastodon.social"
                    },
                    "hashtags": {
                        "title": "Hashtags",
                        "type": "array",
                        "description": "Optionally scrape recent public posts for these hashtags (without #).",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxHashtagPosts": {
                        "title": "Max posts per hashtag",
                        "minimum": 0,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "How many recent posts to fetch per hashtag.",
                        "default": 50
                    },
                    "hashtagInstance": {
                        "title": "Hashtag instance",
                        "type": "string",
                        "description": "Which Mastodon instance to read hashtag timelines from.",
                        "default": "mastodon.social"
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
