# Threads Search Scraper - Keywords, Tags & Profiles (`scrapesage/threads-search-scraper`) Actor

Search Threads by keyword or hashtag and get the posts with text, like, reply and repost counts, media, hashtags and author identity. Also pulls a profile's recent timeline. No login needed.

- **URL**: https://apify.com/scrapesage/threads-search-scraper.md
- **Developed by:** [Scrape Sage](https://apify.com/scrapesage) (community)
- **Categories:** Social media, SEO tools, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.71 / 1,000 post scrapeds

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 Search Scraper - Keywords, Tags & Profiles

Search **Threads** by keyword or hashtag and get the posts back as clean, structured rows - text, engagement counts, media, author identity and timestamps. Also pulls any public profile's recent timeline. **No login, no cookies, no session token.**

Built for social listening, brand monitoring, competitor tracking and content research on the network that is still cheap to monitor.

***

### What you get

One row per post, every row carrying the same 28 fields:

| Field | What it is |
|---|---|
| `postUrl`, `postCode`, `postId` | Canonical link and IDs |
| `text`, `textLength` | Full post text |
| `username`, `userFullName`, `userId` | Author identity |
| `userIsVerified` | Verified badge, true/false |
| `userProfileUrl`, `userProfilePicUrl` | Author links |
| `likeCount`, `replyCount`, `repostCount`, `quoteCount` | Engagement |
| `engagementTotal` | The four counts summed - sort on this |
| `publishedAt` | ISO 8601 timestamp |
| `isReply`, `isQuotePost` | Post kind, true/false |
| `hashtags`, `mentions` | Parsed from the text |
| `imageUrl`, `videoUrl`, `hasMedia` | Attached media |
| `sourceType`, `sourceQuery` | Which keyword/tag/profile found it |
| `scrapedAt` | When this row was collected |

Every record carries every field, so your CSV never has ragged columns.

### Search modes - combine as many as you like in one run

- **Keywords** - `["supabase", "claude code"]` searches Threads' post index
- **Hashtags** - `["ai", "startup"]` searches the tag feed
- **Usernames** - `["zuck", "mosseri"]` pulls those profiles' recent posts

### Filters

`minLikes` · `onlyWithMedia` · `excludeReplies` · `maxPerSource` · `maxResults`

Filters run **inside** the crawl, so a filtered-out post never costs you anything.

***

### Example input

```json
{
  "keywords": ["supabase"],
  "hashtags": ["ai"],
  "maxResults": 100,
  "minLikes": 10,
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

### Example output

```json
{
  "type": "post",
  "postUrl": "https://www.threads.com/@user/post/DMxxxxxxx",
  "text": "We just shipped realtime presence...",
  "username": "user",
  "userFullName": "A Name",
  "userIsVerified": false,
  "likeCount": 412,
  "replyCount": 33,
  "repostCount": 12,
  "quoteCount": 2,
  "engagementTotal": 459,
  "publishedAt": "2026-08-05T14:21:03.000Z",
  "isReply": false,
  "hashtags": ["supabase"],
  "hasMedia": true,
  "imageUrl": "https://...",
  "sourceType": "keyword",
  "sourceQuery": "supabase"
}
```

***

### Pricing

**$0.003 per post.** You are charged only for rows actually delivered to your dataset.

A run that finds nothing - a nonsense keyword, or filters that exclude everything - costs **$0** and tells you why in the run status message.

### Honest limits

Please read these before buying; they are properties of Threads, not bugs:

- **Threads serves logged-out visitors one page of recent results per search.** This actor is built for *monitoring* (run it on a schedule and accumulate) rather than deep historical backfill. A single run returns roughly 10-25 posts per keyword.
- **Hashtags and mentions are sparse** because Threads is a text-first network - measured on a real 134-post sample, only 8 posts carried a hashtag and 1 carried an @mention. The parser extracts every one that exists.
- **Media is optional**: about 37% of posts carry an image and 11% a video.
- Use the **residential proxy** (the default). Threads throttles per IP.

### Tips

- Schedule it. The value is in the time series - run hourly or daily on your brand terms and let the dataset build.
- Sort by `engagementTotal` to find what actually landed.
- `sourceQuery` tells you which of your terms surfaced each post, so you can run 10 keywords in one job and still attribute them.

### Related actors

- **Instagram Profile Scraper** - bulk bio and follower stats
- **Instagram Leads Scraper** - emails and contacts from IG profiles
- **Facebook Reels Scraper** - Reels with play counts

# Actor input Schema

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

Search phrases, e.g. a product name, a competitor or a topic. Each is searched separately.

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

Tag searches, with or without the # - e.g. "ai". Uses Threads' tag results rather than general search.

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

Threads profiles whose recent posts you want, e.g. "zuck" or a full profile URL.

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

Only keep posts with at least this many likes - useful for finding what actually landed.

## `onlyWithMedia` (type: `boolean`):

Keep only posts carrying an image or video.

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

Drop posts that are replies to another post, keeping original posts only.

## `maxPerSource` (type: `integer`):

Cap per keyword, hashtag or profile.

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

Total cap across every source. Set 0 for no limit (explicit opt-in).

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

Meta serves its logged-out pages most reliably to residential IPs. Keep the default.

## Actor input object example

```json
{
  "keywords": [
    "supabase",
    "vibe coding"
  ],
  "hashtags": [
    "ai"
  ],
  "usernames": [
    "zuck"
  ],
  "minLikes": 0,
  "onlyWithMedia": false,
  "excludeReplies": false,
  "maxPerSource": 50,
  "maxResults": 100,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

Every scraped Threads post as a JSON item in the default dataset.

# 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 = {
    "keywords": [
        "supabase"
    ],
    "hashtags": [],
    "usernames": [],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapesage/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 = {
    "keywords": ["supabase"],
    "hashtags": [],
    "usernames": [],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapesage/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 '{
  "keywords": [
    "supabase"
  ],
  "hashtags": [],
  "usernames": [],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call scrapesage/threads-search-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapesage/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/4heVXhyLugJghtHHO/builds/03bliOw1VZcMBvAVv/openapi.json
