# Mastodon Posts & Hashtags Scraper: Hashtag Timeline Export (`transparent_meteorite/mastodon-posts-hashtags-scraper`) Actor

Scrape Mastodon posts by hashtag, account timelines, profiles and trending posts and tags from the official public API of any instance. Engagement counts, media, links. No login.

- **URL**: https://apify.com/transparent_meteorite/mastodon-posts-hashtags-scraper.md
- **Developed by:** [Detroit Web Agent - Open Data](https://apify.com/transparent_meteorite) (community)
- **Categories:** Social media, News
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.37 / 1,000 record returneds

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

## Mastodon Hashtag Timeline Exporter: Posts, Accounts & Trends

Use this to scrape Mastodon posts by hashtag, export any account's timeline, look up profiles in bulk, and pull trending posts and hashtags from any Mastodon instance, with full engagement counts, media, link cards and timestamps. It reads the official public Mastodon REST API that every instance exposes. No login, no cookies, no API key, no proxy.

Every post row carries 46 fields: the full text (plain text and original HTML), author handle, display name, follower count, following count and post count, replies / boosts / favourites counts, language, hashtags, mentions, media attachments with URLs and alt text, the link preview card, poll options, reply and boost flags, timestamps and a ready-to-open URL. Every profile row carries followers, following, post counts, bio, join date, last post date and profile fields. Hashtag rows carry daily and seven-day usage numbers.

### Run in 30 seconds

1. Open the **Input** tab. The prefilled values (mode **Posts for hashtags**, hashtag `python`, instance `mastodon.social`, 25 results) are a ready-to-run test.
2. Click **Start**. The first dataset is normally ready in about 10 seconds.
3. Open the **Posts** table in the Output tab, or download the dataset as JSON, CSV, Excel or HTML.
4. Change **What to scrape** to switch between hashtags, an account's timeline, profile lookups, trending posts, trending hashtags and search.

### What does this Actor do?

Mastodon is a federated social network: thousands of independent servers (instances), each with its own public API. This Actor wraps the public endpoints of that API into one pay-per-result tool with nine modes:

| Mode | Input | Returns |
|---|---|---|
| **Posts for hashtags** | Hashtags, one or many instances | Recent public posts that use the tag |
| **An account's posts** | Usernames, full handles or profile URLs | The account's timeline (optionally without replies or boosts) |
| **Account profiles** | Usernames, handles or profile URLs | One enriched profile row per account |
| **Trending posts** | Instances | The instance's trending posts |
| **Trending hashtags** | Instances | Trending tags with daily and 7-day usage |
| **Search accounts** | Keywords | Accounts matching the keywords |
| **Search hashtags** | Keywords | Hashtags matching the keywords, with usage |
| **Public timeline** | Instances | The local or federated public timeline, where the instance allows it |
| **Search posts** | Keywords | Post search, where the instance allows it |

Public timeline and post search are switched off for anonymous callers on many large instances (mastodon.social answers with "This method requires an authenticated user"). When that happens the Actor does not fail: it ends cleanly and tells you in the run status that the instance requires a login for that endpoint, and charges nothing. Hashtag timelines, account timelines, profiles, trends and account and hashtag search work without login on mastodon.social and most other instances.

### Why use it

- **46 fields per post**, including the original HTML, plain text, spoiler text, sensitivity, visibility, edit time, application name, all media attachments (type, URL, preview URL, alt text), the link preview card (URL, title, description, image, provider), poll options with vote counts, mentions, and the author's follower, following and post counts on every row.
- **Many instances in one run.** List `mastodon.social`, `fosstodon.org`, `infosec.exchange` and any other server in one input. Each is queried through its own public API and every row records its `instance`.
- **Proper pagination.** Pages follow the `Link` header the API returns, so large pulls walk the full timeline rather than stopping after the first page.
- **Polite by design.** Requests are serial and spaced, the Actor reads `X-RateLimit-Remaining` and waits for the window to reset when an instance is nearly out of requests, and it honours `Retry-After` on HTTP 429 and backs off on server errors.
- **Boosts handled correctly.** A boost row reports the original post's content and counts, flags `isBoost` and names the booster in `boostedBy`, so engagement numbers are not blank.
- **Filters that save money.** Date range, language, minimum favourites, replies, boosts and media filters are applied before charging. Skipped rows and duplicates are never billed.
- **Predictable cost.** One flat price per row. The Actor respects your "Maximum cost per run" setting exactly and stops cleanly when it is reached.

### Input

- **What to scrape**: the mode above.
- **Mastodon instances**: server hostnames such as `mastodon.social`, `fosstodon.org`, `mas.to`. Default `mastodon.social`.
- **Hashtags**: with or without the `#`.
- **Accounts**: `Gargron`, `@Mastodon@mastodon.social` or `https://fosstodon.org/@nixCraft`. A bare username is looked up on the first instance in the list.
- **Search terms**: keywords for the search modes.
- **Max results**: total rows to return (1 to 100,000), shared evenly across hashtags, accounts and instances.
- **Posted since / until**, **Language**, **Minimum favourites**, **Only posts with media**, **Local posts only**, **Exclude replies**, **Exclude boosts**.

### Example input

Hashtag monitoring across instances:

```json
{
  "mode": "hashtagPosts",
  "hashtags": ["opensource", "infosec"],
  "instances": ["mastodon.social", "fosstodon.org", "infosec.exchange"],
  "language": "en",
  "since": "2026-10-01",
  "maxItems": 500
}
```

An account's original posts only:

```json
{
  "mode": "accountPosts",
  "accounts": ["Gargron", "@Mastodon@mastodon.social"],
  "excludeReblogs": true,
  "maxItems": 200
}
```

What is trending today:

```json
{
  "mode": "trendingTags",
  "instances": ["mastodon.social", "mas.to"],
  "maxItems": 40
}
```

### Output sample

A post row (shortened):

```json
{
  "recordType": "post",
  "instance": "mastodon.social",
  "id": "117527140766746513",
  "url": "https://post.lurk.org/@IllestPreacha/117527140633626529",
  "createdAt": "2026-10-30T00:57:28.000Z",
  "text": "RangeOfQuintain ... coded in #Python ...",
  "language": "en",
  "authorHandle": "IllestPreacha@post.lurk.org",
  "authorFollowers": 1234,
  "repliesCount": 0,
  "reblogsCount": 2,
  "favouritesCount": 5,
  "hashtags": ["mathober", "python", "poetry"],
  "mediaType": null,
  "cardTitle": null,
  "isReply": false,
  "isBoost": false,
  "query": "#python",
  "source": "hashtag"
}
```

Profile rows carry `authorHandle`, `authorDisplayName`, `text` (bio), `authorFollowers`, `authorFollowing`, `authorPostsCount`, `createdAt`, `lastPostAt`, `locked`, `discoverable` and `profileFields`. Hashtag rows carry `hashtag`, `usesToday`, `accountsToday`, `uses7d`, `accounts7d` and a daily `history`. Fields that do not apply to a row type are `null`.

### Use cases

- **Brand and topic monitoring.** Schedule a daily run on your brand hashtags with a start date of yesterday, and send new posts to Slack or a sheet.
- **Trend research.** Pull trending hashtags and posts from several instances every day and compare what each community cares about.
- **Community and academic datasets.** Collect public posts on a topic with language and date filters, with engagement counts to separate signal from noise.
- **Influencer and account analysis.** Look up profiles in bulk with follower counts, join dates and last-post dates, then export timelines to check engagement per post.
- **Link and news tracking.** The link preview card on each row shows which articles and sites are being shared under a hashtag.
- **Fediverse growth tracking.** Run Profiles on a schedule and compare follower counts over time.

### Tips for good results

- Start with a small **Max results** (25 to 50) to confirm the hashtag returns what you expect, then scale up.
- Hashtag timelines are time-ordered, newest first. Set **Posted since** and the Actor stops paging as soon as it passes that date.
- Use several instances for more coverage: each instance only sees posts that federated to it.
- Across runs, deduplicate on `url` or on `instance` plus `id`. Inside one run duplicates are removed automatically.
- The Actor runs fine with 256 MB of memory.

### Field reference

**Post rows.** `id`, `url` and `uri` identify the post; `createdAt` and `editedAt` give the times; `text` is plain text and `html` the original markup; `spoilerText`, `sensitive`, `visibility` and `language` describe it. `authorHandle` (always `user@instance`), `authorUsername`, `authorDisplayName`, `authorUrl`, `authorFollowers`, `authorFollowing`, `authorPostsCount`, `authorBot`, `authorCreatedAt` and `authorAvatar` describe the author. `repliesCount`, `reblogsCount` and `favouritesCount` are the engagement counters. `isReply`, `inReplyToId`, `isBoost` and `boostedBy` describe the thread position. `hashtags`, `mentions`, `mediaType`, `media`, `cardUrl`, `cardTitle`, `cardDescription`, `cardImage`, `cardProvider`, `pollOptions`, `pollVotes` and `application` carry the content details. `query`, `source`, `instance` and `scrapedAt` record where the row came from.

**Profile and hashtag rows.** See the Output sample above; the dataset tables in the Output tab show the main columns for each type.

### Pricing and cost control

Pay per result: **$0.000428 per row on the free plan, falling to $0.000372 on the Gold plan** (Bronze $0.000409, Silver $0.000391), plus a $0.00005 start fee per run. There are no subscriptions, proxy fees or compute add-ons. Set "Maximum cost per run" to cap spend.

**How this compares with the other Mastodon scrapers (live Store prices read through the Apify API on 2026-10-29, free-plan rate, 1,000-row run including start fees):**

| Actor | Users | Per row | Start fee | Cost for 1,000 rows |
|---|---|---|---|---|
| This Actor | new | $0.000428 | $0.00005 | $0.43 |
| goat255/mastodon-scraper | 23 | $0.00046 | $0.00115 | $0.46 |
| newpo/mastodon-scraper | 195 | $0.001 | $0.01 | $1.01 |

We are cheaper than both at the free-plan rate and at every paid plan level (the 7% margin holds against the other Actor's own Bronze, Silver and Gold rates). Our run of 25 rows on the Apify platform completed in about 4 seconds of run time.

### Limits

- Up to 100,000 rows per run (the **Max results** setting).
- Public API endpoints only. Public timeline and post search are refused for anonymous callers on many large instances; then the run ends with a status message and charges nothing.
- Requests are serial and spaced, and the Actor waits when an instance reports it is nearly out of requests. A run stops starting new work after about 4.5 minutes and keeps what it has delivered.
- Each instance only holds posts that federated to it, so one instance never shows everything on a hashtag; list several instances for wider coverage.
- Private, followers-only and direct posts are never returned.

### Integrations and scheduling

Schedule the Actor from the Schedules tab (hourly, daily, weekly) to build a monitoring feed. Send results onward with the Apify integrations for Slack, email, Google Sheets, Make, Zapier or n8n, or call the Actor from your own code through the REST API. The Open API tab has ready-to-copy snippets.

### Fair use and data

The Actor reads the official public Mastodon REST API of the instances you name, using only endpoints that are open to anonymous clients, and returns data that is already publicly visible. It does not log in, does not read private or followers-only posts, and spaces its requests politely, backing off when the server asks it to slow down. Each instance sets its own terms and rate limits; you remain responsible for using the data lawfully and in line with the rules of the instances you query and with privacy law such as the GDPR when you process personal data.

### Use with the API, n8n, Make, Zapier or AI agents

**API** (one call, returns the rows as JSON):

```bash
curl -X POST "https://api.apify.com/v2/acts/transparent_meteorite~mastodon-posts-hashtags-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode":"hashtagPosts","hashtags":["python"],"instances":["mastodon.social"],"maxItems":25}'
```

The call waits up to 5 minutes. For bigger inputs, start the run with `/runs` instead and read the dataset when it finishes.

**Python**

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("transparent_meteorite/mastodon-posts-hashtags-scraper").call(run_input={"mode": "hashtagPosts", "hashtags": ["python"], "instances": ["mastodon.social"], "maxItems": 25})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row)
```

- **n8n, Make, Zapier:** use the Apify app's "Run Actor" step with actor `transparent_meteorite/mastodon-posts-hashtags-scraper`, paste the input JSON, then map the dataset items to your sheet or CRM.
- **Clay:** add an HTTP API column that calls the run-sync endpoint above.
- **Schedules:** in Apify Console, Schedules, run it daily or weekly with the same input for a steady feed.
- **AI agents (MCP):** connect the Apify MCP server at `https://mcp.apify.com?tools=transparent_meteorite/mastodon-posts-hashtags-scraper` to Claude, Cursor or any MCP client, and your agent can run Mastodon Hashtag Timeline Exporter on request.

### FAQ

**Do I need a Mastodon account or API token?** No. Everything comes from public endpoints.

**Why did Public timeline or Search posts return nothing on mastodon.social?** That instance requires a login for those two endpoints. The run ends cleanly with a clear status message and charges nothing. Use Posts for hashtags, which is open, or name an instance that allows anonymous access.

**Can it read posts from any instance?** Yes, any instance whose public API is reachable. An instance can restrict or disable endpoints; you get a clear message in the run status in that case.

**Does it return private or followers-only posts?** No. Only public posts that the API serves to anonymous callers.

**What happens when an account does not exist?** It is skipped, a warning is logged and noted in the run output, and nothing is charged for it.

**What happens if I hit my maximum cost per run?** The Actor stops cleanly, keeps what it already delivered and shows a clear message in the run status.

**Why did my run return fewer rows than Max results?** The hashtag, date range or filters matched fewer posts than you asked for. The final status message says so.

**Can I run it from code or no-code tools?** Yes: the Apify API and client libraries, plus Make, Zapier, n8n and Google Sheets integrations all work with any Actor.

### Related actors

- [Bluesky Scraper: Posts, Profiles, Followers & Feeds](https://apify.com/transparent_meteorite/bluesky-posts-profiles-scraper) for Bluesky posts and profiles.
- [Hacker News Scraper](https://apify.com/transparent_meteorite/hacker-news-search-scraper) for Hacker News stories, comments and Who is hiring threads.
- [Lemmy Scraper: Communities, Posts & Comments](https://apify.com/transparent_meteorite/lemmy-communities-posts-scraper) for Lemmy communities and posts.
- [Threads Profile Scraper](https://apify.com/transparent_meteorite/threads-profile-scraper) for Meta Threads accounts.
- [TikTok Public Profile Scraper](https://apify.com/transparent_meteorite/tiktok-public-profile-scraper) for TikTok creators.
- [YouTube Channel Scraper](https://apify.com/transparent_meteorite/youtube-channel-scraper) for channels and subscriber counts.

### Support

Found a bug or need a field? Open an issue on the Issues tab with the run URL and you will get a reply there. Feature requests are welcome.

### Changelog

- **0.2**: Nine modes, multi-instance runs, Link-header pagination, rate-limit and Retry-After handling, clear message when an instance requires login, charge-limit and soft-timeout handling.

# Actor input Schema

## `mode` (type: `string`):

Hashtag posts uses Hashtags. Account posts and Profiles use Accounts. The search modes use Search terms. Trending modes need no input.

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

Servers to read from, e.g. mastodon.social, fosstodon.org, infosec.exchange. Each is queried through its own public API.

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

Hashtags without or with the # sign, e.g. python, opensource. Used by Posts for hashtags.

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

Usernames (Gargron), full handles (@user@fosstodon.org) or profile URLs. A bare username is looked up on the first instance. Used by Account posts and Profiles.

## `searchTerms` (type: `array`):

Keywords for the search modes.

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

Total rows to return across all hashtags, accounts and instances (shared evenly). You are charged per row returned.

## `since` (type: `string`):

Only posts at or after this date/time, e.g. 2026-10-01 or 2026-10-01T12:00:00Z.

## `until` (type: `string`):

Only posts before this date/time.

## `language` (type: `string`):

Two-letter language code such as en, de or ja. Posts in other languages are skipped and never charged.

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

Skip posts with fewer favourites than this (skipped posts are never charged).

## `onlyMedia` (type: `boolean`):

Only posts that have images, video or audio attached.

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

Only posts made by accounts on the instance itself (hashtag and public timeline modes).

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

Skip replies (account posts and hashtag modes).

## `excludeReblogs` (type: `boolean`):

Skip boosts (reblogs); keep only original posts.

## Actor input object example

```json
{
  "mode": "hashtagPosts",
  "instances": [
    "mastodon.social"
  ],
  "hashtags": [
    "python"
  ],
  "maxItems": 25,
  "onlyMedia": false,
  "localOnly": false,
  "excludeReplies": false,
  "excludeReblogs": false
}
```

# Actor output Schema

## `posts` (type: `string`):

No description

## `profiles` (type: `string`):

No description

## `hashtags` (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 = {
    "mode": "hashtagPosts",
    "instances": [
        "mastodon.social"
    ],
    "hashtags": [
        "python"
    ],
    "maxItems": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("transparent_meteorite/mastodon-posts-hashtags-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 = {
    "mode": "hashtagPosts",
    "instances": ["mastodon.social"],
    "hashtags": ["python"],
    "maxItems": 25,
}

# Run the Actor and wait for it to finish
run = client.actor("transparent_meteorite/mastodon-posts-hashtags-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 '{
  "mode": "hashtagPosts",
  "instances": [
    "mastodon.social"
  ],
  "hashtags": [
    "python"
  ],
  "maxItems": 25
}' |
apify call transparent_meteorite/mastodon-posts-hashtags-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,transparent_meteorite/mastodon-posts-hashtags-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/b0teHzhjAkQmrT8SS/builds/Gb92HKfFjcdvo8IjJ/openapi.json
