# Lemmy Mastodon Posts Scraper (`axiomworks/lemmy-mastodon-posts-scraper`) Actor

Collect public posts from Lemmy communities, search results and front pages, or Mastodon hashtags and local timelines. Records include text, author, community or hashtag, score, reply count, publication time and links. Uses each instance’s public JSON API without logging in.

- **URL**: https://apify.com/axiomworks/lemmy-mastodon-posts-scraper.md
- **Developed by:** [Axiom Works](https://apify.com/axiomworks) (community)
- **Categories:** Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.19 / 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

## Lemmy Mastodon Posts Scraper

**Returns:** one row per post with platform, title, text, author, community, score, commentsCount and url.
**Input:** `{"platform":"lemmy","instance":"lemmy.world","communities":["technology"],"sort":"Hot","maxItems":50}`
**Best for:** community monitoring, hashtag tracking, content research across fediverse servers.

```json
{
  "id": "53584067",
  "platform": "lemmy",
  "title": "Chinese manufacturers dominate Latin America's bus fleet",
  "author": "yogthos",
  "community": "technology",
  "score": 21,
  "upvotes": 21,
  "url": "https://lemmy.ml/post/53584067"
}
```

### What does Lemmy Mastodon Posts Scraper do?

Lemmy Mastodon Posts Scraper is a Lemmy scraper and Mastodon scraper in one Actor. It reads the public JSON APIs that every Lemmy and Mastodon server exposes and returns posts as clean, flat records. You choose the platform, name the server (the instance), and say what to read: one or more Lemmy communities, a Lemmy keyword search, one or more Mastodon hashtags, public account handles, or the local public timeline of a Mastodon server.

Both platforms are part of the fediverse, so the same fields are returned for both. That makes it easy to compare discussions across servers, feed one dashboard, or build one dataset from many sources. You can use it as a Lemmy API alternative when you do not want to write pagination, rate limiting and retry code yourself, and as a Mastodon API alternative for hashtag collection.

The Actor does not log in and never reads private or follower-only content. It only collects what a server shows publicly without an account. Some Mastodon servers turn off their public timelines; for those the Actor logs a clear message and moves on.

You can run it from the Apify Console, on a schedule, through the API, or from an AI agent over MCP.

### What data can you get?

Every record is one post. Fields that a platform does not have are returned as `null`.

| Field | Type | Description |
|---|---|---|
| `id` | string | Post ID on the instance, unique within a run |
| `platform` | string | `lemmy` or `mastodon` |
| `instance` | string | Hostname of the server the post came from |
| `title` | string | Lemmy post title; `null` on Mastodon, which has no titles |
| `text` | string | Post body. Mastodon HTML is converted to plain text |
| `author` | string | Username of the poster; Mastodon returns the full account address |
| `community` | string | Lemmy community name, the Mastodon hashtag you searched, or `public` for the timeline |
| `score` | number | Lemmy: upvotes minus downvotes. Mastodon: number of favourites |
| `upvotes`, `downvotes` | number | Lemmy vote counts; `null` for Mastodon |
| `thumbnailUrl` | string | Lemmy thumbnail URL when present |
| `nsfw` | boolean | Lemmy post flag when present |
| `reblogsCount` | number | Mastodon boost count; `null` for Lemmy |
| `language` | string | Mastodon language code when present |
| `tags` | array | Mastodon hashtags on the post |
| `mediaUrls` | array | Mastodon media attachment URLs |
| `authorDisplayName` | string | Mastodon author display name |
| `commentsCount` | number | Lemmy comments or Mastodon replies |
| `publishedAt` | string | ISO timestamp of publication |
| `url` | string | Link to the post on the instance |
| `externalUrl` | string | Link the post points to, when there is one. Mastodon uses the preview card first, then the first body link excluding hashtags and mentions |
| `scrapedAt` | string | ISO timestamp of the run |
| `sentiment` | string | `positive`, `neutral` or `negative`; only present when sentiment is switched on and succeeded |
| `sourceUrl` | string | API endpoint the record was fetched from |

### How to use

1. Open the Actor in Apify Console and pick the platform: `lemmy` or `mastodon`.
2. Enter the instance, for example `lemmy.world` or `mastodon.social`.
3. For Lemmy, list communities (for example `technology`), set a search query, or leave both empty to read the instance front page.
4. For Mastodon, list hashtags without the `#`, account handles or profile URLs, or leave both empty to read the local public timeline.
5. Set `maxItems` and press Start. Results appear in the dataset as they are collected, and you can export them as JSON, CSV, Excel or XML.

Account handles are looked up through the selected instance’s public API. A profile URL such as `https://mastodon.social/@Gargron` also works when it matches the selected instance. If you provide handles and hashtags together, the Actor collects the account timelines first, then the hashtag timelines until `maxItems` is reached. Each output row is still a post; the Actor does not emit separate profile records.

The Actor requests about one page per second from each instance, which is polite to community-run servers. Lemmy pages hold up to 50 posts and Mastodon pages up to 40, and the run stops as soon as `maxItems` posts are saved.

#### Practical tips

Start small. Run with `maxItems` set to 10 to confirm that the instance, community or hashtag is spelled correctly, then raise the limit. Community names on Lemmy are the short name that appears in the community address, for example `technology` for the technology community on the instance you chose. Hashtags on Mastodon are matched without case, so `Caturday` and `caturday` return the same posts.

If you want a broad sample of a Lemmy server, leave the community list empty and pick a sort order. `Hot` shows what is active now, `New` shows the latest posts, and `TopDay` or `TopWeek` show the best-scoring posts of the period. For monitoring, schedule a daily run with `New` and a modest `maxItems`, then compare the `id` values with the previous day to find fresh posts.

To follow one topic across the fediverse, run the Actor once per instance with the same hashtag or search query, then merge the datasets. Each record carries the `instance` field, so you can always tell where a post came from.

Mastodon posts keep line breaks from the original, HTML entities are decoded, and links and mentions are reduced to plain text. Lemmy bodies are returned as the Markdown the author wrote.

### Input

| Field | Type | Description |
|---|---|---|
| `instance` | string, required | Hostname of the server, for example `lemmy.world` |
| `platform` | string | `lemmy` (default) or `mastodon` |
| `communities` | array | Lemmy community names, one per line |
| `hashtags` | array | Mastodon hashtags without `#` |
| `handles` | array | Mastodon account handles or profile URLs on the selected instance |
| `searchQuery` | string | Lemmy keyword search; combined with communities if both are set |
| `sort` | string | Lemmy ordering: `Hot` (default), `New`, `TopDay`, `TopWeek` |
| `minScore` | integer | Skip posts below this score (Lemmy score or Mastodon favourites); default 0 keeps all. Skipped posts are not charged |
| `enrichSentiment` | boolean | Adds a `sentiment` field using a third-party AI processor |
| `maxItems` | integer | Maximum posts to return, 1-10000, default 50 |
| `proxyConfiguration` | object | Apify Proxy settings; off by default, enable it if an instance blocks you |

Example Lemmy input:

```json
{
  "platform": "lemmy",
  "instance": "lemmy.world",
  "communities": ["technology"],
  "sort": "Hot",
  "maxItems": 30
}
```

Example Mastodon input:

```json
{
  "platform": "mastodon",
  "instance": "mastodon.social",
  "hashtags": ["caturday"],
  "maxItems": 30
}
```

### Output

The dataset holds one item per post. A Mastodon example from a real run:

```json
{
  "id": "117379741313064696",
  "platform": "mastodon",
  "instance": "mastodon.social",
  "title": null,
  "text": "We took our Landlady (cat) to the vet yesterday and she's still pouting ...",
  "author": "todays_wander@pixelfed.social",
  "community": "caturday",
  "score": 0,
  "commentsCount": 0,
  "publishedAt": "2026-10-04T00:11:43.000Z",
  "url": "https://pixelfed.social/p/todays_wander/1012152259384724103",
  "externalUrl": null,
  "scrapedAt": "2026-10-04T00:13:08.670Z",
  "sourceUrl": "https://mastodon.social/api/v1/timelines/tag/caturday?limit=5"
}
```

Items are unique by `id` within a run. When you read several communities or hashtags, a post that appears twice is saved once.

Sentiment is an optional extra. When `enrichSentiment` is on, the title and text of each post are sent to a third-party AI processor, which returns one of three labels. If the AI service is unavailable the post is still saved without the field and the enrichment is not charged.

### How much does it cost?

The Actor is charged per result: you pay for each post saved to the dataset, and the optional sentiment field is charged only for posts where it succeeded. Current rates are on the Pricing tab of the Actor page. Because the run stops exactly at `maxItems`, you control the cost with that one number.

### Use with AI agents (MCP)

Add the Actor to any MCP client through the Apify MCP server:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=axiomworks/lemmy-mastodon-posts-scraper"
    }
  }
}
```

Example prompts:

- "Get the 30 hottest posts from the technology community on lemmy.world and summarise the main themes."
- "Collect 50 recent mastodon.social posts tagged caturday and list the most favourited ones."
- "Search lemmy.world for posts about linux and return titles with their scores."

### Integrations and API

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("axiomworks/lemmy-mastodon-posts-scraper").call(run_input={
    "platform": "lemmy",
    "instance": "lemmy.world",
    "communities": ["technology"],
    "maxItems": 50,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["title"], item["score"])
```

JavaScript:

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<APIFY_TOKEN>' });
const run = await client.actor('axiomworks/lemmy-mastodon-posts-scraper').call({
    platform: 'mastodon',
    instance: 'mastodon.social',
    hashtags: ['caturday'],
    maxItems: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
process.stdout.write(`${items.length} posts\n`);
```

cURL:

```bash
curl -X POST "https://api.apify.com/v2/acts/axiomworks~lemmy-mastodon-posts-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"platform":"lemmy","instance":"lemmy.world","communities":["technology"],"maxItems":20}'
```

You can also connect the dataset to Google Sheets, Slack, Zapier, Make or webhooks from the Integrations tab, and schedule runs to track a community or hashtag over time.

### FAQ

**Which servers work?** Any Lemmy or Mastodon server that answers its public API. Pick the matching platform; a Mastodon hostname used with `lemmy` returns nothing.

**Why is `title` empty for Mastodon?** Mastodon posts have no title, so the field is `null`. The post is in `text`.

**What does `score` mean?** On Lemmy it is upvotes minus downvotes. On Mastodon it is the favourites count, which is the closest equivalent.

**A Mastodon server returned nothing. Why?** Some servers disable the public timeline or hashtag timeline for visitors without an account. The run ends successfully with zero items and a status message. Try another instance.

**Does it need a proxy?** Normally not. If an instance blocks the request, enable Apify Proxy in the input; blocked requests are retried on a new IP.

**Can I get comments?** This version returns posts. Comment-level data is not included.

**What happens with a wrong community or hashtag?** The run finishes with zero items and a message that says what to change. It never saves placeholder rows.

### Is it legal to scrape Lemmy and Mastodon?

The Actor reads only public data that the servers publish through their open APIs, with no login and at a modest request rate. Posts can still contain personal data, so use them in line with the privacy laws that apply to you, such as GDPR, and respect the rules of each instance. Do not use the data for harassment, spam or to re-identify people. This Actor is an independent tool and is not affiliated with or endorsed by Lemmy, Mastodon or any instance. If in doubt, ask a legal adviser about your use case.

### Feedback

Found a bug or need another field? Open an issue from the Actor page in Apify Console. Include the input you used and the instance, and we will look into it.

# Actor input Schema

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

Required. Bare hostname of the Lemmy or Mastodon server, no https:// and no path, e.g. 'lemmy.world' or 'mastodon.social'. Must run the software chosen in 'platform'. A wrong or unreachable host ends SUCCEEDED with 0 results and a message saying what to change.

## `platform` (type: `string`):

Software the instance runs: 'lemmy' (use communities or searchQuery) or 'mastodon' (use hashtags, handles, or nothing for the public timeline). Default 'lemmy'. Fields for the other platform are ignored.

## `communities` (type: `array`):

Lemmy only. Community names, e.g. \['technology'] or \['news@lemmy.world'] (a leading ! is accepted). Posts are read per community, sharing the maxItems budget. Empty = instance front page, or search results when searchQuery is set. Unknown communities are skipped.

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

Mastodon only. Hashtags, e.g. \['caturday','python'] (a leading # is accepted). All share the maxItems budget. Leave empty (and handles empty) to read the instance's local public timeline; some servers disable that and return 0 results.

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

Lemmy only. Keyword search over post titles and bodies, e.g. 'linux'. Combined with communities when both are given. Empty = plain listings sorted by 'sort'.

## `sort` (type: `string`):

Lemmy only. Post ordering, one of Hot, New, TopDay, TopWeek. Default 'Hot'. Use 'New' for monitoring. Ignored for Mastodon, which is always newest first.

## `minScore` (type: `integer`):

Skip posts with a score (Lemmy score, or Mastodon favourites) below this number, e.g. 10. Skipped posts are not returned or charged and do not count toward maxItems. Default 0 keeps everything.

## `enrichSentiment` (type: `boolean`):

If true, adds a 'sentiment' field (positive, neutral or negative) per post using a third-party AI processor, billed as an extra event only where it succeeds. Default false: no sentiment, no AI calls.

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

Total posts to return across ALL communities, hashtags and handles combined, 1-10000, default 50. The run stops once this many are saved; you are charged only for posts returned. Use a small value like 20 for quick tests.

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

Proxy for requests, e.g. {"useApifyProxy": true}. Default is no proxy because public Lemmy/Mastodon APIs answer directly. Enable Apify Proxy if an instance rate-limits or blocks (blocked requests retry on a new IP).

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

Mastodon only. Public account handles or profile URLs, e.g. \['Gargron'] or \['https://mastodon.social/@Gargron']. Resolved on the selected instance and sharing the maxItems budget. Empty = use hashtags or the public timeline.

## Actor input object example

```json
{
  "instance": "lemmy.world",
  "platform": "lemmy",
  "communities": [
    "technology"
  ],
  "sort": "Hot",
  "minScore": 0,
  "enrichSentiment": false,
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Dataset with one item per result, in the order found.

# 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 = {
    "instance": "lemmy.world",
    "platform": "lemmy",
    "communities": [
        "technology"
    ],
    "sort": "Hot",
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiomworks/lemmy-mastodon-posts-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 = {
    "instance": "lemmy.world",
    "platform": "lemmy",
    "communities": ["technology"],
    "sort": "Hot",
    "maxItems": 20,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("axiomworks/lemmy-mastodon-posts-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 '{
  "instance": "lemmy.world",
  "platform": "lemmy",
  "communities": [
    "technology"
  ],
  "sort": "Hot",
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call axiomworks/lemmy-mastodon-posts-scraper --silent --output-dataset

```

## MCP server setup

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