# Threads Monitor (`lergassy/threads-monitor`) Actor

Monitor Meta Threads accounts, brands, competitors and hashtags and get only the posts you were not given before: author, text, time, likes, replies, reposts, views, media, links, mentions. Schedule runs, export the data, or integrate with other tools or AI workflows.

- **URL**: https://apify.com/lergassy/threads-monitor.md
- **Developed by:** [Matvey](https://apify.com/lergassy) (community)
- **Categories:** Social media, Agents, AI
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.10 / 1,000 new posts

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?

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

**Threads Monitor** watches Meta Threads for you and returns **only what is new since the last check**. Give it accounts, brand names, competitors or hashtags, put it on a schedule, and every run hands you the posts you have not been given before — author, text, time, likes, replies, reposts, views, media, links and mentions, one row per post. **A run that finds nothing new costs nothing**, and error rows are never billed.

It reads the public pages Threads serves to any visitor: **no login, no cookies, no API key, no browser and no proxy of your own**.

### What is Threads Monitor?

Threads has an official API only for your own account, so there is no supported way to be told when a competitor posts or when someone mentions your brand. This Actor is that missing **Threads monitoring API**: a named watch that remembers every post it has already delivered and, on the next run, returns the difference.

That is the whole difference from a Threads scraper. A scraper answers *"what is on this page?"* and gives you the same 25 posts every time you ask. A monitor answers *"what changed?"* — which is what a schedule, an alert and an AI agent actually need, and what costs you money to figure out yourself with a scraper plus a deduplication table.

Typical uses: brand and crisis monitoring, competitor and creator tracking, keyword alerts into Slack or Telegram, feeding an AI agent only fresh material instead of the same archive, and keeping a database in sync without re-importing what is already in it.

### How the watch works

| | |
|---|---|
| **Watch name** | Any name you like — `brand-mentions`, `competitors`. Every run under that name compares against what that name has already delivered. Different names are independent watches and never see each other's memory. |
| **First run** | Nothing to compare against yet, so it returns the posts on the page right now and remembers them. Turn **Deliver what is already there on the first run** off to start silently instead and hear only about posts published from now on. |
| **Every run after** | Only posts the watch has never returned. Filtered-out posts are remembered too, so a post you asked to ignore does not come back tomorrow as new. |
| **No watch name** | A preview run: it returns the latest posts and remembers nothing. Useful to see what a watch would pick up before you schedule it. |
| **Nothing new** | An empty dataset and a status message saying so. That is the expected answer of a monitor, not a failure — and it is not billed. |

### What data does Threads Monitor return?

One row per new post, flat, ready for a spreadsheet, a database or an agent.

| Field | Example |
|---|---|
| `watchTarget`, `watchType` | `zuck`, `account` — or `my brand`, `keyword` |
| `username`, `fullName`, `isVerified`, `profileUrl` | who posted |
| `text`, `createdAt`, `timestamp`, `url` | the post itself |
| `likeCount`, `replyCount`, `repostCount`, `quoteCount`, `viewCount` | engagement at the moment of the check |
| `mediaType`, `images`, `videos`, `imageUrl`, `videoUrl` | attached media |
| `hashtags`, `mentions`, `urls`, `linkPreview` | what the post points at |
| `isReply`, `replyToUsername`, `isQuote`, `quotedPost`, `isRepost`, `repostedPost` | context |
| `isNew`, `isBaseline`, `firstSeenAt`, `checkedAt` | what this watch knew and when |

### How much does it cost to monitor Threads?

**$3 per 1,000 new posts** — you pay for delivered posts, nothing else.

- A run that finds nothing new: **$0**.
- Error rows: **$0**.
- Posts removed by your own filters: **$0**.
- Posts this watch already gave you: **$0** — they are never delivered twice, so they are never billed twice.

Watching ten accounts every hour and catching, say, 200 new posts a day costs about **$18 a month**. The same job done with a scraper means downloading 25 posts per account per check — 180,000 rows a month — and deduplicating them yourself.

There is no start fee and no monthly rent. Apify's free plan includes $5 of platform credit, which is roughly 1,600 new posts.

### How to monitor Threads in four steps

1. Put the accounts you care about in **👤 Accounts to watch** and the brand or product names in **🔎 Keywords and hashtags to watch**.
2. Give the watch a name in **🔔 Watch name** — anything, as long as you reuse the same one.
3. Click **Start**. The first run shows you what is being watched.
4. Open the **Schedules** tab and run it every hour, every morning, or whatever matches how fast you need to know. Connect Slack, Telegram, e-mail, Zapier, Make or a webhook in **Integrations** and the new posts arrive where you work.

### ⬇️ Input

```json
{
  "watchName": "brand-mentions",
  "usernames": ["zuck", "mosseri"],
  "keywords": ["my brand", "#mybrand"],
  "maxPostsPerCheck": 25,
  "maxAgeHours": 48,
  "deliverBaseline": true,
  "minLikes": 0
}
```

#### Watching accounts

Usernames with or without the `@`, or full profile URLs. Each account costs one request per check, so watching twenty accounts hourly is twenty requests an hour.

#### Watching keywords, brands and hashtags

Threads' logged-out search pages mix in posts that do not contain the query at all — measured on 16 September 2026, 20 of 22 results on the recent page contained the word, 17 of 22 on the top page and only 7 of 26 on the hashtag page. A monitor that passed those on would wake you for nothing and bill you for it, so by default a mention has to be a real mention: the phrase, or every word of it, present in the text or the hashtags. Turn **strict mention matching** off if you want everything the search page returns.

#### Not being woken up for the wrong things

**⏱️ Ignore posts older than** keeps an old post from arriving as breaking news after a pause. **🧹 Only tell me about posts containing**, **🌐 Languages**, **❤️ Minimum likes** and **💬 Minimum replies** narrow it further. Everything filtered out is still remembered, so it will not reappear later.

### ⬆️ Output

```json
{
  "type": "post",
  "watchName": "brand-mentions",
  "watchType": "keyword",
  "watchTarget": "my brand",
  "isNew": true,
  "username": "someone",
  "text": "just switched to my brand and the difference is real",
  "createdAt": "2026-09-16T07:01:15.000Z",
  "url": "https://www.threads.net/@someone/post/DAbC1dEfGh",
  "likeCount": 42,
  "replyCount": 7,
  "repostCount": 2,
  "hashtags": ["mybrand"],
  "mentions": [],
  "firstSeenAt": "2026-09-16T08:00:04.120Z",
  "checkedAt": "2026-09-16T08:00:04.120Z"
}
```

A failed check pushes one `type: "error"` row naming the target and the reason (`account not found, private, or renamed`) and never charges for it. The run summary — how many were new, how many were already delivered, how many were filtered out — is written to the key-value store as `SUMMARY`.

### Use cases

#### Brand and crisis monitoring

Watch your brand, your product names and the misspellings people actually use. Route the dataset to Slack or Telegram and the first angry thread reaches you in the hour it is written, not the week after.

#### Competitor tracking

Watch competitor accounts and be told what they announced, how it landed and which posts got traction — with engagement numbers attached to each row.

#### Creator and influencer monitoring

Watch the creators you work with and see every new post, including the ones that mention you.

#### AI agents and RAG

An agent that asks "what is new about X" should not re-read the same archive every hour. The delta is the answer, and this Actor is the tool that returns it — through the Apify API or the Apify MCP server.

#### Keeping a database in sync

`isNew` and `firstSeenAt` on every row mean an append is enough: no upserts, no deduplication table of your own.

### Integrations

Run it from the [Apify API](https://docs.apify.com/api/v2), the Python and JavaScript clients, n8n, Make, Zapier, Google Sheets, or as a tool for an AI agent through the [Apify MCP server](https://mcp.apify.com). Schedules and webhooks are built into the platform: point a webhook at your own endpoint and every check that finds something new calls you.

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("lergassy/threads-monitor").call(run_input={
    "watchName": "brand-mentions",
    "keywords": ["my brand"],
})
for post in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(post["username"], post["text"])
```

### ❓ FAQ

#### Is it legal to monitor Threads?

This Actor reads only public pages, the same ones any visitor sees without logging in, and it collects no private data. Public data collection is generally lawful in the EU and the US, but what you do with the data — especially personal data — is regulated. Consult a lawyer for your own case.

#### Does it need my Threads account?

No. No login, no cookies, no tokens, no browser. Nothing you own can be rate-limited or blocked because of it.

#### What happens when nothing new was posted?

You get an empty dataset, a status message saying so, and a bill of $0. That is the normal answer of a monitor.

#### Can I watch several things separately?

Yes. Use a different watch name per subject — `brand-mentions`, `competitors`, `partners`. Each name keeps its own memory.

#### What if I change what I watch?

Add or remove accounts and keywords freely. Turn **♻️ Forget everything this watch remembers** on for one run to wipe the memory and start a fresh baseline.

#### Can I use it with the Apify API or an MCP server?

Yes to both. It is a normal Actor: call it from the API, schedule it, or expose it to an AI agent through the Apify MCP server.

#### How is this different from a Threads scraper?

A scraper returns everything on the page every time. This returns the difference since your last check, and bills only for that.

### Your feedback

Something missing, something wrong? Open an issue on the Actor's **Issues** tab or leave a review — both are read and answered.

### You might also like

| Actor | What it does |
|---|---|
| [Threads Scraper](https://apify.com/lergassy/threads-scraper) | The full archive: search, an account's posts, replies, reposts, whole threads, profiles and account discovery |
| [Threads Search Scraper](https://apify.com/lergassy/threads-search-scraper) | Keyword and hashtag search across top, recent and tag pages |
| [Threads Replies Scraper](https://apify.com/lergassy/threads-replies-scraper) | Replies and conversations: who answered what |
| [Threads Profile Scraper](https://apify.com/lergassy/threads-profile-scraper) | Profiles in bulk: followers, bio, links and contacts |

# Actor input Schema

## `usernames` (type: `array`):

Threads accounts to check on every run. Enter a username, with or without the @, or a full profile URL. Leave empty to watch keywords only.

## `keywords` (type: `array`):

Brand names, product names, competitors or #hashtags. Every run returns the posts mentioning them that were not returned before.

## `watchName` (type: `string`):

The name this watch remembers itself by. Give it any name — <b>brand-mentions</b>, <b>competitors</b> — and every run under that name returns only posts it has not returned before. Leave it empty for a preview run that remembers nothing and simply returns the latest posts.

## `maxPostsPerCheck` (type: `integer`):

How far down each account or search page to look on every run. Twenty-five covers a busy account checked hourly; raise it for rare checks of very active accounts.

## `maxAgeHours` (type: `integer`):

Skip anything published longer ago than this, even if the watch has never seen it. Useful on the first run and after a pause, so an old post does not arrive as breaking news. Zero means no age limit.

## `deliverBaseline` (type: `boolean`):

On the very first run of a new watch there is nothing to compare against. Leave this on to receive the posts that are on the page right now, so you can see what is being watched; turn it off to start silently and be told only about posts published from now on.

## `filterKeywords` (type: `array`):

Extra words a post must contain to be delivered. A post filtered out here is still remembered, so it will not arrive later as new.

## `languages` (type: `array`):

Two-letter codes such as en, ru, id. Threads labels only some posts with a language, so the script of the text is used where the label is missing.

## `minLikes` (type: `integer`):

Ignore posts below this number of likes. Zero delivers everything.

## `minReplies` (type: `integer`):

Ignore posts below this number of replies. Zero delivers everything.

## `searchTypes` (type: `array`):

Recent gives the newest mentions and is what a watch normally wants. Top adds the ones Threads ranks highest, tags reads the hashtag page.

## `resetWatch` (type: `boolean`):

Wipe the memory of this watch name and start a new baseline on this run. Use it after changing what you watch.

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

A hard ceiling on what one run can deliver and bill, whatever it finds.

## `concurrency` (type: `integer`):

How many watched targets to check at the same time.

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

Apify Proxy is used by default and needs no setup. Threads is read without a login, so datacenter proxies are enough.

## Actor input object example

```json
{
  "usernames": [
    "zuck"
  ],
  "keywords": [],
  "watchName": "",
  "maxPostsPerCheck": 25,
  "maxAgeHours": 0,
  "deliverBaseline": true,
  "filterKeywords": [],
  "languages": [],
  "minLikes": 0,
  "minReplies": 0,
  "searchTypes": [
    "recent",
    "top"
  ],
  "resetWatch": false,
  "maxItems": 1000,
  "concurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `newPosts` (type: `string`):

One row per post that this watch had not returned before: watched account or keyword, author, time, text, likes, replies, reposts, views, media URLs, links, mentions, hashtags and reply context.

# 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 = {
    "usernames": [
        "zuck"
    ],
    "maxPostsPerCheck": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("lergassy/threads-monitor").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 = {
    "usernames": ["zuck"],
    "maxPostsPerCheck": 25,
}

# Run the Actor and wait for it to finish
run = client.actor("lergassy/threads-monitor").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 '{
  "usernames": [
    "zuck"
  ],
  "maxPostsPerCheck": 25
}' |
apify call lergassy/threads-monitor --silent --output-dataset

```

## MCP server setup

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

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/EbbXL5TyTCy7vmDOi/builds/GplCtjCxsmCnDizZ5/openapi.json
