# Threads Search Scraper — Keyword Search to JSON (`northbound-data/threads-search-scraper`) Actor

Search public Threads (Meta) by keyword and get clean structured JSON: text, author, timestamp, likes, replies, reposts. No login or cookies. Duplicates across keywords are removed, so you are never billed twice for the same post.

- **URL**: https://apify.com/northbound-data/threads-search-scraper.md
- **Developed by:** [Northbound Data](https://apify.com/northbound-data) (community)
- **Categories:** Social media, Automation, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 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/platform/actors/running/actors-in-store#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 Search Scraper — Keyword Search to Clean JSON

Search public **Threads (Meta)** by keyword and get back a flat, structured dataset: post text, author, timestamp, likes, replies, reposts. **No login. No cookies. No account of yours is ever used.**

Give it a list of keywords, get one row per matching post.

***

### Why this one

**Duplicates across keywords are removed — and never billed twice.**

If you search `ai agents`, `ai automation` and `llm tools`, the same post will often match more than one of them. Most scrapers hand you that post three times and charge you three times. This Actor deduplicates by post ID across the whole run, so you pay once and your dataset stays clean. Each record carries the `query` field that matched it.

**Structure-adaptive parsing.** Most Threads scrapers hard-code GraphQL `doc_id` values or fixed JSON paths, so they break the moment Meta ships a change. This one identifies data by structural signature, not by path — a Meta refactor degrades output instead of killing the run.

**Retries transient failures.** A single flaky response does not become a failed run. The Actor retries with backoff, and distinguishes a genuinely missing target (returns immediately, no wasted compute) from a temporary hiccup (retried).

**Measured 0% failure rate.** Across a 24-task benchmark (8 profiles, 10 posts, 6 keyword searches) this engine delivered **647 records with zero failed tasks**, averaging 5.5 s per task. The two largest Threads Actors on the Store run at 13.5% and 13.1% failure (measured 2026-08-19).

**Reports its own reliability.** Every run writes a `RUN_SUMMARY` with `queries`, `itemsPushed`, `failedQueries` and `failureRate`, so you can verify quality yourself instead of taking our word for it.

***

### Deep search — about 2.5x more posts per keyword

Threads exposes **five separate public search surfaces**, and each returns a different result set:

| Surface | What it is |
|---|---|
| `default` | The standard results page |
| `recent` | Recency-weighted results |
| `top` | Engagement-weighted results |
| `users` | Results surfaced through matching accounts |
| `tags` | Results surfaced through matching hashtags |

Meta caps **each individual surface** at roughly 20 results. Most scrapers query only the default surface and stop there, so they hand you ~20 posts.

This Actor queries **all five and merges them, deduplicated by post ID**. Measured on real keywords:

| Keyword | Single surface | All five merged |
|---|---|---|
| `ai agents` | 20 | **47** |
| `climate tech` | 21 | **54** |

That is **2.4–2.7x more unique posts per keyword**, and every record carries a `search_surface` field so you can see where it came from. Set `searchDepth` to `standard` if you prefer the faster, cheaper single-surface behaviour.

**This is not a bypass.** All five surfaces are the same public endpoints the Threads website itself uses, read logged-out. We do not use accounts, cookies, or any circumvention.

### Honest limitation — please read before you buy

Even with all five surfaces merged, you get roughly **50 posts per keyword, not thousands**. Meta's per-surface cap is real and we do not pretend otherwise. Anything promising thousands of logged-out search results is either using logged-in accounts (against Threads' terms, and those accounts get banned) or it is not telling you the truth.

This Actor is built for **breadth**: give it 200 keywords and get ~50 fresh posts for each, reliably. If you need a deep historical archive of one keyword, this is not the right tool and you should not buy it.

***

### Why residential proxy is the default

Meta serves **empty shell pages to datacenter IPs**. When that happens this Actor falls back to full browser rendering, which still returns correct data but is dramatically slower and more expensive.

Measured on the Apify platform, same target, same day (2026-08-19):

| Proxy | Mode used | Time per profile | Compute cost per run |
|---|---|---|---|
| Datacenter (Apify default) | browser rendering | **150 s** | $0.127 |
| Residential | direct fetch | **3.3 s** | $0.0086 |

That is 45x faster and 15x cheaper, for a residential transfer cost of roughly 7% of what the returned records are worth. So `RESIDENTIAL` ships as the default proxy group.

You can override it, but if you switch to datacenter expect slow runs — the Actor will still work, it just has to render every page.

***

### Input

```json
{
  "searchQueries": ["ai agents", "climate tech", "web scraping"],
  "includeReplies": true,
  "maxItems": 1000
}
```

| Field | Type | Notes |
|---|---|---|
| `searchQueries` | array | Keywords to search. Deduplicated automatically. |
| `includeReplies` | boolean | Default `true`. Set `false` for top-level posts only. |
| `searchDepth` | string | `deep` (default) queries all five surfaces (~50 posts/keyword); `standard` queries only the default surface (~20). |
| `maxItems` | integer | Hard cap on billed records. Your safety net. |
| `proxyConfiguration` | object | Defaults to `RESIDENTIAL`. See the section above — datacenter IPs get shell pages from Meta and force slow rendering. |

### Output

One flat record per matching post:

```json
{
  "id": "3961381054679086896",
  "code": "Db5pxS4G_cw",
  "url": "https://www.threads.com/@someone/post/Db5pxS4G_cw",
  "query": "ai agents",
  "is_reply": false,
  "text": "This website has 1M+ skills for your AI agents",
  "posted_at": "2026-08-11T13:04:02.000Z",
  "like_count": 101,
  "reply_count": 2,
  "repost_count": 0,
  "quote_count": 0,
  "author": {
    "id": "63294227753",
    "username": "someone",
    "full_name": "Some One",
    "is_verified": false,
    "profile_pic_url": "https://…"
  },
  "media": { "images": [], "videos": [], "alt_text": null },
  "source_url": "https://www.threads.com/search?q=ai%20agents",
  "scraped_at": "2026-08-15T07:28:00.000Z"
}
```

### What it's used for

- **Threads social listening & brand monitoring** — track how a topic, product or category is
  actually discussed, including the comments people leave on posts that match your keywords,
  across all five public search surfaces rather than the one most tools read
- **Hashtag monitoring** — the `tags` surface is queried as a first-class source, not an afterthought
- **Sentiment datasets** — every record carries text, engagement counts and a timestamp, which is
  what a sentiment pipeline needs and nothing it does not
- **Competitor tracking** — sample competitor names and category terms on the same schedule
- **Trend research** — sample hundreds of keywords cheaply and compare engagement between them
- **Lead and creator discovery** — find accounts posting about your niche
- **AI agents & RAG** — clean JSON in, no HTML parsing, ready to embed

#### On breadth vs depth

This Actor is built for **breadth**: many keywords, ~50 fresh posts each, reliably, on a schedule.
That shape suits social listening and brand monitoring, where you care about what is being said
across a category right now. It is **not** a historical archive tool — see the honest limitation
above before you buy.

### Pricing

Pay per result. You are charged only for records actually delivered to your dataset, and duplicates within a run are never billed twice. `maxItems` caps your spend.

### Related

Need posts, replies and profiles as well as search? See **Threads Scraper — Posts, Profiles, Replies & Search** by the same author.

### The numbers behind this page

Everything this Actor claims about Threads' logged-out ceilings — the ~20 reply
cap, the five search surfaces, the four profile tabs, and the empty shell page
Meta serves to datacenter IPs as a valid HTTP 200 — is written up with the
measurements, dates and method here:

**[What Threads actually returns when you are not logged in](https://zhanghengrui0308.github.io/threads-data-client/)**

It is a reference, not a sales page. If you are evaluating any Threads scraper,
including someone else's, those are the limits to test them against.

***

### Open-source client

There is a small MIT-licensed JavaScript client for this Actor, so you do not
have to write the run-start / polling / dataset-pagination plumbing yourself:

**[github.com/zhanghengrui0308/threads-data-client](https://github.com/zhanghengrui0308/threads-data-client)** — zero dependencies, Node 18+.

```js
import { ThreadsClient } from 'threads-data-client';

const threads = new ThreadsClient(process.env.APIFY_TOKEN);

const rows = await threads.search(['ai agents', 'climate tech'], { maxItems: 200 });
```

It also exposes `estimateCost(actor, records, tier)`, which tells you the exact
USD bill for a run before you start it, at your own plan tier.

You do not need it — the Actor works fine from the Apify Console, the API, or
any HTTP client. It is there if you would rather read the code than trust a
description of it.

***

### Legal & scope

Reads **public** Threads pages only. No login, no cookies, no CAPTCHA solving, no access-control circumvention. **On `robots.txt`, stated plainly:** `threads.com/robots.txt` runs an allowlist. Named crawlers
(Googlebot, Bingbot, GPTBot, ClaudeBot and others) are granted specific access; for every other user
agent the file says `Disallow: /`, and its opening notice states that automated collection requires
express written permission from Meta. **This Actor is not on that allowlist.** We say so because you
should decide with the real facts rather than a comfortable summary, and because you are the party
accountable for how the data is collected and used under Meta's terms and applicable law. You are responsible for how you use the data, including GDPR/CCPA obligations where personal data is involved.

# Actor input Schema

## `searchQueries` (type: `array`):

Keywords to search on Threads. Duplicates across keywords are removed automatically, so you are never billed twice for the same post.

## `includeReplies` (type: `boolean`):

Include replies that match the keyword, not just top-level posts.

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

Hard cap on total records pushed to the dataset. Your safety net against unexpected charges. The default of 100 keeps a first trial run cheap; raise it for production runs.

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

Proxy settings. RESIDENTIAL is the default and strongly recommended: Meta serves empty shell pages to datacenter IPs, which forces this Actor into slow browser rendering. Measured on 2026-08-19: datacenter took 150s per profile, residential took 3.3s — 45x faster and 15x cheaper in compute. Residential transfer is billed by Apify at ~7% of what these results are worth.

## `searchDepth` (type: `string`):

How many of Threads' public search surfaces to query per keyword. "deep" queries all five (default, recent, top, users, tags) and merges the results, which returns roughly 2.4-2.7x more unique posts than a single surface. "standard" queries only the default surface - faster and cheaper, about 20 posts.

## Actor input object example

```json
{
  "searchQueries": [
    "ai agents"
  ],
  "includeReplies": true,
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "searchDepth": "deep"
}
```

# Actor output Schema

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

One record per matching post or reply, with author, text, timestamp, engagement counts and the keyword that matched it.

## `runSummary` (type: `string`):

Reliability report for this run: keywords attempted, items delivered, failed keywords and the resulting failureRate.

# 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 = {
    "searchQueries": [
        "ai agents"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("northbound-data/threads-search-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 = { "searchQueries": ["ai agents"] }

# Run the Actor and wait for it to finish
run = client.actor("northbound-data/threads-search-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 '{
  "searchQueries": [
    "ai agents"
  ]
}' |
apify call northbound-data/threads-search-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,northbound-data/threads-search-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/9zImgTLV4Y9r6K1Tt/builds/RhEPmSxkLk9acAVNw/openapi.json
