# Developer Community Listening — Stack Exchange, Lemmy, Mastodon (`foxlabs/community-listening`) Actor

Track a brand, product or topic across developer communities in one run: Stack Exchange questions, Lemmy posts and Mastodon hashtag activity, merged into one schema with text, direct link, author, community and engagement numbers. Official/open APIs, no key needed.

- **URL**: https://apify.com/foxlabs/community-listening.md
- **Developed by:** [Berkan Kaplan](https://apify.com/foxlabs) (community)
- **Categories:** Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 mentions

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

## Developer Community Listening — Stack Exchange, Lemmy, Mastodon

Find out **where developers are talking about your product** — and go read it. One search term, three communities, **one flat schema**: every mention arrives with its text, a direct link, the author, the community it came from and that platform's engagement numbers.

- 🎧 **Three sources, one run** — Stack Exchange (any site in the network), Lemmy, and Mastodon hashtags
- 🔗 **Every row is actionable** — direct URL and author handle on every mention, so you can reply, not just count
- 📊 **Engagement attached** — votes, answers and views on Stack Exchange; score and comments on Lemmy; favourites, boosts and follower counts on Mastodon
- 🆓 **No key required** — official and open APIs; an optional free Stack Exchange key just raises the daily quota

### Quick start (API)

Everything said about "supabase" in the last 30 days, across all three:

```bash
curl -X POST "https://api.apify.com/v2/acts/foxlabs~community-listening/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "query": "supabase", "datePreset": "last_30_days", "maxResults": 300 }'
```

Prefer no code? Open the **Input** tab, type your brand, press **Start**.

### What you get

| Field | Type | Description |
|---|---|---|
| `source` | string | `stackexchange`, `lemmy` or `mastodon` |
| `community` | string | The site, Lemmy community or hashtag+instance the mention came from |
| `title` | string | Post/question title (Mastodon posts have none) |
| `text` | string | The body, HTML stripped, capped at 4,000 characters |
| `url` | string | Direct link to the mention |
| `linkUrl` | string | The external link a Lemmy post points at, when it has one |
| `author` / `authorUrl` | string | Who wrote it and their profile |
| `authorReputation` / `authorFollowers` | number | Stack Exchange reputation / Mastodon follower count |
| `score` | number | Votes (Stack Exchange), score (Lemmy), favourites (Mastodon) |
| `comments` | number | Answers (Stack Exchange), comments (Lemmy), replies (Mastodon) |
| `views` | number | Stack Exchange view count |
| `reblogs` | number | Mastodon boosts |
| `isAnswered` | bool | Whether the Stack Exchange question has an accepted answer |
| `tags` | array | Question tags / post hashtags |
| `createdAt` / `lastActivityAt` | string | When it was posted / last touched (ISO) |
| `matchedQuery` | string | The term this run was listening for |
| `license` | string | Attribution string on Stack Exchange rows (CC BY-SA 4.0) |

The run also writes a **per-source report** to the key-value store (`SOURCE_REPORT`) with the count from each source — so you always know whether "few results" means a quiet week or a source that failed.

#### Sample output

```json
{
  "source": "stackexchange",
  "community": "stackoverflow",
  "title": "Supabase RLS policy blocks insert from edge function",
  "text": "I have a policy that should allow inserts for authenticated users…",
  "url": "https://stackoverflow.com/questions/79000000/supabase-rls-policy-blocks-insert",
  "author": "Arnav Sharma",
  "authorReputation": 1,
  "score": 2,
  "comments": 1,
  "views": 61,
  "isAnswered": false,
  "tags": ["next.js", "supabase"],
  "createdAt": "2026-07-31T10:22:41.000Z",
  "matchedQuery": "supabase",
  "license": "Stack Exchange content, CC BY-SA 4.0"
}
```

Download as JSON, CSV, Excel or HTML, or read it from the API.

### Options

- **Search term** — the brand, product or topic. Required.
- **Sources** — any combination of Stack Exchange, Lemmy, Mastodon.
- **Time window** — 7 / 30 / 90 days, a year, or all time. **All time is the default**, combined with newest-first sorting: Stack Overflow's volume for a single product name can be as low as a couple of questions a month (measured: 2 for "supabase" in 30 days), so a narrow window can return almost nothing even though the term is discussed. You still get the newest mentions first.
- **Sort by** — newest (monitoring), most votes (what mattered), recent activity (still moving).
- **Stack Exchange sites** — search several sites in one run (`stackoverflow`, `serverfault`, `dba`, `security`, …).
- **Lemmy / Mastodon instance** — point at a niche server if your audience lives there.
- **Mastodon hashtags** — override the tag(s); defaults to the search term.
- **Stack Exchange key** — optional, raises the daily quota from ~300 to 10,000 requests.

### Example inputs (copy & paste)

```jsonc
// 1) Weekly brand monitor
{ "query": "clickhouse", "datePreset": "last_7_days" }

// 2) Where the pain is — unanswered questions about your product
{ "query": "supabase", "sources": ["stackexchange"], "sortBy": "newest", "maxResults": 1000 }

// 3) Ops-side chatter, not just app developers
{ "query": "kubernetes operator", "sources": ["stackexchange"], "stackExchangeSites": ["serverfault", "devops", "stackoverflow"] }

// 4) The fediverse view of a topic
{ "query": "selfhosted", "sources": ["lemmy", "mastodon"], "mastodonHashtags": ["selfhosted", "selfhosting"] }

// 5) Competitor watch, most-discussed first
{ "query": "planetscale", "sortBy": "votes", "datePreset": "last_90_days" }
```

### Use cases

- **Developer marketing / DevRel.** See every question, post and toot about your product this week, with a link to reply to. Unanswered Stack Exchange questions are the highest-value ones — they're a customer stuck in public.
- **Competitor monitoring.** Run the same query against a competitor's name and compare volume, sentimentally-loaded titles and which communities they show up in.
- **Product & docs feedback.** Recurring question tags tell you which part of your product the docs fail to explain.
- **Community discovery.** Find the Lemmy communities and Mastodon hashtags where your audience actually gathers, before you try to participate.
- **Weekly digests.** Schedule it, export to a sheet or Slack, and read the week's mentions in one place.

### Performance & cost

Plain HTTP against official/open APIs — no browser, no proxy, no third-party fees. Stack Exchange returns 100 results per page with deep paging; Lemmy pages 20 at a time; Mastodon hashtag timelines page by `max_id`. Quotas, honestly: **Stack Exchange allows ~300 requests/day per IP without a key** (a free key raises it to 10,000/day), and the Actor honours the API's own backoff requests. Lemmy and Mastodon are queried at a polite pace.

### Integrations

**JavaScript** (`apify-client`):

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('foxlabs/community-listening').call({
  query: 'clickhouse', datePreset: 'last_7_days',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

**Python** (`apify-client`):

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("foxlabs/community-listening").call(run_input={
    "query": "supabase", "sources": ["stackexchange"], "sortBy": "newest",
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["source"], item.get("score"), item["url"])
```

Also works with **Make / n8n / Zapier**, scheduled runs, webhooks and the **Apify MCP server**.

### Honest limits (please read)

- **Mastodon is hashtag-based here.** Its full-text search requires an account token, so this Actor reads hashtag timelines instead. A post that mentions your product *without* a hashtag will not appear. Set `mastodonHashtags` to the tags your community actually uses.
- **Lemmy is per-instance.** The Fediverse has no global index; searching `lemmy.world` sees that instance's view. Point at another instance to cover a different corner.
- **Stack Exchange covers questions, not comments** — and its volume per product is thinner than people expect. Measured on 2026-08-01: "supabase" returned 100 matching questions all-time but only **2 in the last 30 days**. That's the platform, not the Actor; keep the window wide and sort newest-first for monitoring.
- **Reddit is deliberately not a source.** Its robots.txt disallows crawling and its public-content policy requires a contract for commercial use, so including it would mean breaking those terms. This Actor stays on sources whose terms permit it.
- **Full-text search matches URLs too.** A product name that is also a hosting domain (`supabase.co`, `vercel.app`) will occasionally match a post that merely links to an asset there. Measured example in Data quality below.
- If a source fails mid-run, the others still return and `SOURCE_REPORT` records the failure — you never get a silently short list.

### Data quality (measured 2026-08-01)

A 300-mention run for "supabase" across all three sources, 100 from each:

| Check | Result |
|---|---|
| `url`, `text`, `author`, `community`, `createdAt`, `score`, `comments` | **100%** on all three sources |
| Unique mentions (by URL) | **300 / 300** |
| Term actually present in the row | **300 / 300** |
| Links verified against the source API (title + link match) | **10 / 10** |
| Stack Exchange attribution string | **100 / 100** rows |
| Columns that were empty for every row | none |

**One honest caveat about matching:** these are full-text searches, so a term can match inside a URL. One Lemmy post in the measured run was a biography of Mary "Mother" Jones — it matched because its image is hosted on `…supabase.co`. Technically a match, not a mention. Scan the `text` field before acting on results for brand names that double as hosting domains.

### Pricing

**$0.002 per mention ($2 per 1,000)** — pay only for results. You are charged per mention actually returned. A run that finds nothing costs nothing beyond a few seconds of compute.

**Pay per result** — billed per mention returned, with an Apify **free tier** to evaluate. The APIs behind it are free, so there are no proxy or third-party costs.

### FAQ

#### Which sources does it cover?

The Stack Exchange network (Stack Overflow, Server Fault, DBA, Security and 100+ others), Lemmy, and Mastodon hashtag timelines.

#### Do I need any API key?

No. A free Stack Exchange key is optional and only raises the daily quota.

#### Why isn't Reddit included?

Because Reddit's own rules don't allow it — see Honest limits. We'd rather ship three sources you can use than a fourth that puts your account at risk.

#### Can I track several brands?

Run it once per term (that keeps `matchedQuery` clean), or schedule several runs and merge the datasets.

#### How do I find unanswered questions?

Use Stack Exchange as the only source and filter the output on `isAnswered = false` — those are the customers stuck in public.

#### Is the data licensed for reuse?

Stack Exchange content is CC BY-SA 4.0 and each row carries the attribution string. Lemmy and Mastodon posts belong to their authors; treat them as you would any public post.

#### How fresh is it?

Live — all three APIs return current data at request time. Schedule the Actor to build a history.

### Troubleshooting

- **0 mentions** → widen the time window, try a broader term, or check `SOURCE_REPORT` to see whether a source returned nothing or failed.
- **Nothing from Mastodon** → your term may not be used as a hashtag; set `mastodonHashtags` explicitly.
- **Stack Exchange stops early** → you've hit the ~300/day keyless quota. Add a free key in Advanced.
- **Nothing from Lemmy** → that instance may not host communities discussing your topic; try another instance.

### Support

Questions, another source you'd like added, or a custom build? Open the **Issues** tab, or e-mail **info@foxlabs.com.tr**. We reply fast.

*If this Actor saves you time, a ⭐ review really helps.*

### Changelog

#### 0.1 — 2026-08-01

- Initial release: Stack Exchange + Lemmy + Mastodon in one schema, with per-source reporting, date windows, multi-site Stack Exchange search and configurable Lemmy/Mastodon instances.

***

Part of the **[foXLabs data platform](https://data.foxlabs.com.tr/)** — developer, company and market intelligence scrapers. See also **[Hacker News Search & Who-is-Hiring](https://apify.com/foxlabs/hackernews-intelligence)** and **[GitHub Trending & Rising Repos](https://apify.com/foxlabs/github-trending-scraper)** for the rest of the developer-community picture.

# Actor input Schema

## `query` (type: `string`):

The brand, product, competitor or topic to track — e.g. "supabase", "clickhouse", "self-hosted". Used as the search phrase on Stack Exchange and Lemmy, and as the hashtag on Mastodon unless you set one below.

## `sources` (type: `array`):

Which communities to listen to. Every source returns rows in the same shape, tagged with `source`, so you can filter afterwards.

## `datePreset` (type: `string`):

How far back to look. Default is all time WITH newest-first sorting, which gives you the most recent mentions without hiding a thin week — Stack Overflow question volume for a single product can be as low as a couple of posts a month (measured: 2 for "supabase" in 30 days). Narrow the window when you specifically want strict recency.

## `sortBy` (type: `string`):

Newest first for monitoring, most-voted for the discussions that mattered, activity for threads still moving.

## `stackExchangeSites` (type: `array`):

Which sites in the Stack Exchange network to search — e.g. \["stackoverflow", "serverfault", "dba", "security"]. Each site is searched separately. Leave empty for Stack Overflow only.

## `lemmyInstance` (type: `string`):

Which Lemmy server to search. Defaults to lemmy.world, the largest general instance; use a niche instance to target its communities.

## `mastodonInstance` (type: `string`):

Which Mastodon server's hashtag timeline to read. Defaults to mastodon.social; instances federate, so a large one sees most public posts.

## `mastodonHashtags` (type: `array`):

Hashtags to follow, without the #. Leave empty to use the search term itself. Note: Mastodon's full-text search needs an account token, so this Actor reads hashtag timelines — posts that mention your brand without a hashtag won't appear.

## `stackExchangeKey` (type: `string`):

Without a key Stack Exchange allows ~300 requests/day per IP; a free key raises it to 10,000/day and lets big sweeps run faster. Get one at stackapps.com — no approval needed.

## `maxResults` (type: `integer`):

Hard cap on mentions returned across all sources. The budget is shared evenly between the sources you selected — and whatever one source doesn't use passes to the others — so a busy source can't crowd out the rest. Set 0 for unlimited.

## Actor input object example

```json
{
  "query": "supabase",
  "sources": [
    "stackexchange",
    "lemmy",
    "mastodon"
  ],
  "datePreset": "all_time",
  "sortBy": "newest",
  "stackExchangeSites": [
    "stackoverflow"
  ],
  "lemmyInstance": "lemmy.world",
  "mastodonInstance": "mastodon.social",
  "mastodonHashtags": [],
  "maxResults": 500
}
```

# Actor output Schema

## `mentions` (type: `string`):

No description

## `sourceReport` (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 = {
    "query": "supabase",
    "sources": [
        "stackexchange",
        "lemmy",
        "mastodon"
    ],
    "datePreset": "all_time",
    "stackExchangeSites": [
        "stackoverflow"
    ],
    "lemmyInstance": "lemmy.world",
    "mastodonInstance": "mastodon.social",
    "mastodonHashtags": [],
    "maxResults": 500
};

// Run the Actor and wait for it to finish
const run = await client.actor("foxlabs/community-listening").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 = {
    "query": "supabase",
    "sources": [
        "stackexchange",
        "lemmy",
        "mastodon",
    ],
    "datePreset": "all_time",
    "stackExchangeSites": ["stackoverflow"],
    "lemmyInstance": "lemmy.world",
    "mastodonInstance": "mastodon.social",
    "mastodonHashtags": [],
    "maxResults": 500,
}

# Run the Actor and wait for it to finish
run = client.actor("foxlabs/community-listening").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 '{
  "query": "supabase",
  "sources": [
    "stackexchange",
    "lemmy",
    "mastodon"
  ],
  "datePreset": "all_time",
  "stackExchangeSites": [
    "stackoverflow"
  ],
  "lemmyInstance": "lemmy.world",
  "mastodonInstance": "mastodon.social",
  "mastodonHashtags": [],
  "maxResults": 500
}' |
apify call foxlabs/community-listening --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,foxlabs/community-listening"
        }
    }
}

```

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/aWIAxOLnP3xAjtS0l/builds/wuV3Z08VteHbF6FWf/openapi.json
