# Threads Search Scraper: Posts by Keyword, Mentions & Monitoring (`nice_dev/threads-search-scraper`) Actor

Search Threads by keywords, phrases and hashtags without login: hundreds of recent posts per keyword, only posts that contain your keyword, views, author followers and bio contacts, monitoring of new mentions. Export JSON, CSV or Excel.

- **URL**: https://apify.com/nice_dev/threads-search-scraper.md
- **Developed by:** [Nice Dev](https://apify.com/nice_dev) (community)
- **Categories:** Social media, Lead generation, MCP servers
- **Stats:** 15 total users, 10 monthly users, 94.9% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.09 / 1,000 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?

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

### 🔎 What is Threads Search Scraper?

**Threads Search Scraper** finds the **posts that mention your keywords on [Threads](https://www.threads.com)**, Meta's text network: brand names, products, topics, `#hashtags`, phrases. For each post you get the **text, date, likes, replies, reposts, quotes, views, media and links**, the **author** (with **Author profiles**: follower count and bio), and **where your keyword was found**.

Type a few **keywords** (`nike`, `#ai`, `"air max"`), click **Start**, and download the results in JSON, CSV or Excel. No login, nothing to set up. Schedule it with **Only new posts** to **monitor mentions**: each run returns only the posts you have not received yet.

### 📋 What data can you extract from Threads search?

One item per post, 113 fields:

| Category | What you get |
| --- | --- |
| 🎯 **Keyword match** | which of your keywords the post contains and where (text, quoted post, link, image description, topic), the search that found it — `nike` in `text`, found by `nike dunk` |
| 📝 **Post** | text, link, date to the second, edited or not — `Nike SB Dunk restock today` |
| 📊 **Engagement** | likes, replies, reposts, quotes, shares and **views**, plus a ready-made **engagement rate** (interactions per view, or per follower when a post has no views) — `2,234 likes, 44 replies, 9,045 views` |
| 🖼️ **Media** | every photo and video of the post (carousels included, with the length of each video), the sound file of a voice note, alt text, GIF, stickers, music and podcast shared |
| 🔗 **Links and mentions** | links of the text and of the link card (real target, no redirect), mentioned accounts, accounts tagged on the photos, hashtags, topic and its ID |
| 💬 **Conversations** | who the post answers and that post's text, quoted post, reposts, polls with their votes |
| 👤 **Author** | username, name, verified badge, picture, profile link, **follower count and bio**; on request the **e-mails and phone numbers written in the bio**, and those found on the **website the author cites in the bio** |
| 📁 **Extras (optional)** | a **summary of each keyword** (posts per day, average and median likes and views, top hashtags, top authors, top posts) **your own copy of the photos and videos** of the posts, and the **contacts found on the websites of the authors** — `nike: 281 posts, median 3 likes` · `media-3905-1.jpg` · `hello@acme-shop.fr` |
| 🤖 **AI (optional)** | an **AI sentiment label** (positive, neutral or negative, with a score) and **your own AI labels** (the ones you wrote that apply to the post, with a score) — `negative, 0.91` · `pricing, 0.82` |

Every field, with an example, is listed in the **Output** section below.

### ✅ Why use Threads Search Scraper?

- 💸 **Cheap**: $0.10 per 1,000 results, down to $0.088 on paid Apify plans — proxy and platform usage included.
- 🎯 **Only posts that really mention your keyword**: Threads pads its public search results with popular posts that have nothing to do with it (up to 3 out of 4 for a common word). They are dropped — and never charged — and every row says where the keyword was found.
- 📈 **Hundreds of posts per popular keyword**: after Threads' Top, Recent and topic views, **Deep search** also searches the phrases people write around your keyword (`nike dunk`, `nike stock`, `sepatu nike`) and the site in other languages — on the Apify platform, `nike` gave 290 posts in under 6 minutes with the default options (views and authors on), 481 in under 4 minutes with both off, where one search page gives 20-35.
- 🔔 **Mention monitoring built in**: tick **Only new posts** and schedule the Actor (every hour, every day): each run returns — and charges — only the posts it never delivered before.
- 👤 **Who is talking**: follower count and bio of every author (with **Author profiles**), views of every post, an engagement rate on every post, and on request the contacts written in the author's bio.
- 🤖 **What they think**: tick **AI sentiment label** for a positive / neutral / negative label on each post, and write **AI labels** (`pricing`, `complaint: The author reports a problem`) to see which of your topics each post is about.
- 📊 **A report per keyword**: tick **Keyword statistics** and get, next to the dataset, one record that sums up each keyword: how many posts and replies, posts per day, average and median likes, replies, reposts, quotes and views, median engagement rate, the top hashtags, authors and posts.
- 📁 **Photos and videos that do not expire**: the media links Threads gives are signed and stop working. Tick **Download photos and videos** and each file is kept in your run's key-value store, with a link on the row.
- 🔁 **Same input as other Threads search Actors**: `keywords`, `maxItemsPerKeyword`, `sortByRecent` work as they are.
- 🧩 **Search inside accounts**: every post of chosen accounts (their whole history) that contains your keywords.
- 🔌 API, scheduling, integrations (Make, Zapier, n8n, Google Sheets…) and JSON / CSV / Excel export via the Apify platform.

### 🚀 How to scrape Threads search results

1. Create a free Apify account.
2. Open **Threads Search Scraper** and type one or more **Keywords** (e.g. `nike`, `#ai`, `"air max"`).
3. Set **Max posts per keyword** (50 by default, 0 = as many as Threads shows) and click **Start**.
4. Download the dataset in JSON, CSV, Excel or via API.
5. To follow a brand or a topic, tick **Only new posts** and schedule the Actor.

### 💰 How much does it cost to scrape Threads search results?

This Actor uses **pay per event** pricing: **$0.10 per 1,000 results** (posts) without an Apify subscription — plus **$0.01 per run start** (one per GB of memory: one at the default 512 MB). Paid Apify plans pay less: $0.09 (Bronze), $0.089 (Silver) and $0.088 (Gold) per 1,000 results. **Author profiles** (off by default: follower count and bio of each distinct author) adds **$0.29 per 1,000 authors** looked up ($0.28, $0.27 and $0.26 on Bronze, Silver and Gold). The other extras, all off by default, each have their own price: a price per author whose bio gives an e-mail or a phone number (**Author contacts**, off by default), a price per post given an **AI sentiment label** (`post-sentiment`, off by default; a post without text costs nothing), a price per post and per label judged with **AI labels** (`ai-label`, off by default; each label you write is charged once for each post it is judged on, whether it applies or not), a price per keyword summarised (**Keyword statistics**, `keyword-stats`, off by default; a keyword needs at least 5 posts in the run, at most 50 keywords are given), a price per media file kept (**Download photos and videos**, `media-file`, off by default; a file that could not be kept costs nothing), a price per author whose website gives an e-mail or a phone number (**Contacts from the author's website**, `website-contacts`, off by default; a website that gives neither costs nothing). The filters Threads does not apply itself (`postedAfter` / `postedBefore`, `minLikes`, `minReplies`, `minReposts`, `mediaOnly`, `mediaTypes`, `excludeReplies`, `verifiedOnly`, `excludeAuthors`, `excludeKeywords`) are checked by the Actor on every post it reads, kept or not: each post checked is charged a filter check (`filter-check`): **$0.14 per 1,000 posts checked** ($0.13, $0.12 and $0.096 on Bronze, Silver and Gold), once per run however many views or searches show it again, and with **Only new posts** once per post and per filter setting (see *Monitoring* below). The posts Threads adds without your keyword are never charged. The two AI options need 2 GB of memory (Run options → Memory): with less, they are skipped, the log says so and nothing is charged. The engagement rate is free. See the **Pricing** tab for the amounts of the other extras. Example, without a subscription: keyword searches that save 5,000 posts ≈ $0.51; a daily mention monitor of 300 new posts ≈ $0.04. Platform usage (compute, proxy) is included in the price.

### ⚙️ Input

```json
{
    "keywords": ["nike", "#ai", "\"air max\""],
    "maxItemsPerKeyword": 100
}
```

Monitor a brand every hour: only the posts not delivered before, the last day only, no replies:

```json
{
    "keywords": ["apify", "web scraping"],
    "maxItemsPerKeyword": 200,
    "postedAfter": "24 hours",
    "excludeReplies": true,
    "onlyNew": true,
    "stateKey": "apify-mentions"
}
```

A keyword in the whole history of a few accounts, with the contacts of their bio:

```json
{
    "keywords": ["mars"],
    "fromUsers": ["nasa", "spacex"],
    "includeAuthorProfiles": true,
    "includeAuthorContacts": true
}
```

| Field | Notes |
| --- | --- |
| `keywords` | Words, phrases or hashtags as typed in the Threads search box: `nike`, `artificial intelligence`, `#ai`; `"air max"` in quotes = the exact phrase; `@account` = that account's posts (its whole history). |
| `maxItemsPerKeyword` | Posts per keyword (`0` = as many as Threads shows). A rare keyword can give a few dozen. |
| `sortByRecent` | Threads' Recent view first, each page taken newest first (on by default); off = Threads' Top ranking first. |
| `deepSearch` | Also search the phrases found around the keyword and the site in other languages (on by default); off = the three views of the search only (about 15-35 posts per keyword). |
| `includeViews` | Read each post a keyword search finds on its own page for its views (on by default); off = faster, no views. The posts of accounts and replies have no views. |
| `fromUsers` | Accounts (`nasa`, `@nasa`, profile URL) whose whole history is searched for the keywords (all their posts without keywords). |
| `startUrls` | Threads search URLs (`https://www.threads.com/search?q=nike`), profile or post URLs, or a text file of URLs (one per line). |
| `maxItems` | Stop after this many results for the whole run (`0` = unlimited). |
| `requireKeywordMatch` | Only the posts that contain a keyword (on by default); off = also the loosely related posts Threads adds (with no matched keyword). |
| `postedAfter`, `postedBefore` | Publication date range: `2026-09-01` (a UTC day), or a period before now (`24 hours`, `7 days`, `2 weeks`). |
| `minLikes`, `minReplies`, `minReposts`, `mediaOnly`, `excludeReplies` | Only the posts with at least that many likes / replies / reposts, with a photo or a video, or that are not replies. |
| `mediaTypes` | Only the posts of these kinds: `text` (a link card, a poll or a GIF can come with it), `image`, `carousel`, `video`, `audio` (a voice note). Empty (the default) = every kind. |
| `verifiedOnly` | Only the posts whose author has the verified badge (off by default). |
| `excludeAuthors` | Drop the posts of these accounts (`nasa`, `@nasa` or a profile URL). |
| `excludeKeywords` | Drop the posts whose text, image descriptions or link title contain one of these words (case and accents ignored; also inside a longer word: `art` drops `party`). |
| `includeAuthorProfiles`, `includeAuthorContacts` | Follower count and bio of each author (off by default; needed for the contacts); e-mails and phone numbers written in that bio (off by default). |
| `includeSentiment` | An AI sentiment label (positive / neutral / negative) and its score on each post and reply, in two extra fields (off by default). Charged once per row labelled; nothing for a post without text. Requires 2 GB of memory (Run options → Memory); with less the option is skipped and nothing is charged. |
| `aiLabels` | AI labels: your own labels, one per entry — a name (`pricing`) or a name and a sentence that is true when the label applies (`competitor: The author compares tools`); up to 20. Each post and reply gets the labels that apply, with a score from 0 to 1, in `aiLabelMatches`. Empty (the default) = off. Charged per row and per label judged, whether it applies or not; nothing for a post without text. Requires 2 GB of memory (Run options → Memory); with less the option is skipped and nothing is charged. |
| `includeKeywordStats` | A summary of each keyword in the KEYWORD_STATS record of the key-value store, never in the dataset (off by default). Charged once per keyword given; a keyword needs at least 5 posts in the run, at most 50 keywords. With `onlyNew`, only the posts delivered in this run are counted. |
| `downloadMedia`, `maxMediaFileMb` | Keep the photos, videos and voice notes of the posts in the key-value store and give their links in two extra columns of the row (off by default). Charged once per file kept; a file over `maxMediaFileMb` (50 MB by default, 1 to 100; at most 50 below 1 GB), gone or out of time is not kept and not charged. |
| `includeWebsiteContacts` | Open the website each author cites in its bio and add the e-mails, phone numbers and social links found there (off by default; needs `includeAuthorProfiles`, without it nothing happens). Charged once per author for whom at least one e-mail or phone number is found; a website that cannot be opened or gives none costs nothing. |
| `includeProfile` | One profile row per account of @account keywords and `fromUsers` (off by default, no extra request). |
| `repliesForAllPosts`, `maxReplies`, `repliesSort` | Also the replies under every post found: how many per post, `top` or `recent` first. |
| `onlyNew`, `stateKey`, `resetState` | Monitoring: only the posts never delivered under this memory key; `resetState` forgets the memory. |
| Advanced | `maxSearchPagesPerKeyword` (bound on the search pages of one keyword, 300 by default), `proxyConfiguration` (Apify proxy by default, included in the price; the residential proxy is not available), `maxConcurrency`, `maxRequestsPerMinute`, `maxRequestRetries`, `debugLog`. |

### 📦 Output

A post as the run saved it (empty fields left out, links shortened):

```json
{
    "type": "post",
    "id": "3994728069789340396",
    "url": "https://www.threads.com/@dimas.sdwo/post/DdwIAO2E1Ls",
    "source": "search",
    "sourceInput": "nike",
    "scrapedAt": "2026-09-26T14:42:13.838Z",
    "searchQuery": "nike",
    "matchedKeywords": [
        "nike"
    ],
    "matchedIn": [
        "text"
    ],
    "code": "DdwIAO2E1Ls",
    "text": "WTS PRELOVED❗️❗️❗️\n1. Nike Dri-fit Stride Runinng Shorts 5” Size L\n2. Adidas Terrex Climacool 5L Size S + 2Flask 500ml Fieldway\nLok Surabaya, minat DM gusyy",
    "createdAt": "2026-09-26T13:18:36.000Z",
    "createdAtTimestamp": 1790428716,
    "isEdited": false,
    "likeCount": 4,
    "replyCount": 6,
    "repostCount": 0,
    "quoteCount": 0,
    "shareCount": 1,
    "viewCount": 401,
    "engagementRate": 0.0249,
    "engagementBase": "views",
    "mediaType": "carousel",
    "hasMedia": true,
    "images": [
        {
            "url": "https://instagram.fnap7-1.fna.fbcdn.net/v/t51.82787-15/825323203_17972180118140782_8033678563312053090_n.jpg",
            "width": 2788,
            "height": 2788,
            "altText": null
        },
        {
            "url": "https://instagram.fnap7-1.fna.fbcdn.net/v/t51.82787-15/825323100_17972180127140782_4343163602084703056_n.jpg",
            "width": 2455,
            "height": 2455,
            "altText": null
        },
        {
            "url": "https://instagram.fnap7-1.fna.fbcdn.net/v/t51.82787-15/825323375_17972180145140782_9065125105949654558_n.jpg",
            "width": 3024,
            "height": 3024,
            "altText": null
        },
        {
            "url": "https://instagram.fnap7-1.fna.fbcdn.net/v/t51.82787-15/825323088_17972180175140782_5901268117608142722_n.jpg",
            "width": 3024,
            "height": 3024,
            "altText": null
        },
        {
            "url": "https://instagram.fnap7-2.fna.fbcdn.net/v/t51.82787-15/825323395_17972180184140782_5360971089617000564_n.jpg",
            "width": 3024,
            "height": 3024,
            "altText": null
        }
    ],
    "videos": [],
    "mediaUrls": [
        "https://instagram.fnap7-1.fna.fbcdn.net/v/t51.82787-15/825323203_17972180118140782_8033678563312053090_n.jpg",
        "https://instagram.fnap7-1.fna.fbcdn.net/v/t51.82787-15/825323100_17972180127140782_4343163602084703056_n.jpg",
        "https://instagram.fnap7-1.fna.fbcdn.net/v/t51.82787-15/825323375_17972180145140782_9065125105949654558_n.jpg",
        "https://instagram.fnap7-1.fna.fbcdn.net/v/t51.82787-15/825323088_17972180175140782_5901268117608142722_n.jpg",
        "https://instagram.fnap7-2.fna.fbcdn.net/v/t51.82787-15/825323395_17972180184140782_5360971089617000564_n.jpg"
    ],
    "mentions": [],
    "userTags": [],
    "hashtags": [],
    "links": [],
    "topicTag": "Running Threads",
    "isReply": false,
    "isQuotePost": false,
    "isRepost": false,
    "mediaCount": 5,
    "isGif": false,
    "stickerUrls": [],
    "pollOptions": [],
    "likeCountsHidden": false,
    "replyControl": "everyone",
    "authorId": "64141212781",
    "authorUsername": "dimas.sdwo",
    "authorFullName": "Dimas sadewo",
    "authorIsVerified": false,
    "authorProfilePicUrl": "https://instagram.fnap7-1.fna.fbcdn.net/v/t51.82787-19/731113161_17960488296140782_378451424120892358_n.jpg",
    "authorUrl": "https://www.threads.com/@dimas.sdwo",
    "authorFollowerCount": 60,
    "authorEmails": [],
    "authorPhones": [],
    "authorWebsiteEmails": [],
    "authorWebsitePhones": [],
    "authorSocialLinks": [],
    "bioLinks": [],
    "emails": [],
    "phones": [],
    "profileTags": []
}
```

You can download the dataset in various formats such as JSON, HTML, CSV or Excel.

#### Keyword statistics

With **Keyword statistics**, the run also writes one record, `KEYWORD_STATS`, to its key-value store (a link is in the run's log). It is not a row of the dataset. Shortened example, from 29 posts:

```jsonc
{
    "generatedAt": "2026-10-10T12:00:00.000Z",
    "onlyNew": false,
    "rowsRead": 29,
    "minRowsPerKeyword": 5,
    "keywordsFound": 1,
    "keywordsDelivered": 1,
    "keywords": [
        {
            "keyword": "nike",
            "posts": 16,
            "replies": 13,
            "firstPostAt": "2026-09-23T09:42:16.000Z",
            "lastPostAt": "2026-09-23T22:58:13.000Z",
            "periodDays": 0.55,
            "postsPerDay": 29,
            "perPost": {
                "likes": { "mean": 61.34, "median": 2 },
                "replies": { "mean": 11.66, "median": 2 },
                "reposts": { "mean": 2.48, "median": 0 },
                "quotes": { "mean": 0.28, "median": 0 },
                "views": { "mean": null, "median": null }
            },
            "engagementRateMedian": null,
            "mediaShare": 0.069,
            "authors": 26,
            "verifiedAuthorsShare": 0.0769,
            "rowsWithLanguage": 2,
            "languages": [{ "language": "ja", "share": 0.5, "rows": 1 }, { "language": "zh_tw", "share": 0.5, "rows": 1 }],
            "topHashtags": [],
            "topAuthors": [{ "username": "barrettpall", "rows": 2, "likes": 1285 }],
            "topPosts": [{ "id": "3992702351627170477", "url": "https://www.threads.com/@barrettpall/post/Ddo7aJymrKt", "likes": 806 }],
            "sentiment": null
        }
    ],
    "notDelivered": []
}
```

- A post counts under **every** keyword it contains, so the posts of your keywords can add up to more than the dataset. A post found without a keyword match (**Only posts that contain a keyword** off) counts under the keyword it was searched with. Posts of accounts (`@account`, `fromUsers` without a keyword) and profile rows belong to no keyword.
- Averages and medians cover posts and replies together; a count Threads hides is left out, never counted as 0. `postsPerDay` is the number of rows divided by the days between the first and the last post, a period under one day counting as one day. `languages` only lists the posts where Threads gives a language. `sentiment` is filled when **AI sentiment label** is on: the share of positive, neutral and negative posts among those labelled.
- A keyword needs at least 5 posts (replies included) in the run; at most 50 keywords are given, the biggest first, and the keywords left out are named in `notDelivered`. With **Only new posts**, only the posts delivered in this run are counted (`onlyNew: true` in the record).

#### Media files

With **Download photos and videos**, every photo, video and voice note of the posts the run delivers is kept in the run's key-value store as `media-<post id>-<n>.<extension>` (`media-<post id>-audio.<extension>` for a voice note), with its real content type. The row says where, in `storedMediaUrls` (same order as `mediaUrls`; `null` for a file not kept) and `storedAudioUrl`. The links Threads gives in `mediaUrls` and `audioUrl` are signed by Meta and expire: your copy stays. A GIF (`gifUrl`), the author's picture and the picture of a link card are not copied.

A file is kept whole or not at all, and charged only when it is kept. Not kept, and not charged: a file larger than `maxMediaFileMb`, a file Threads no longer serves, a download that fails or runs out of time, and any file beyond what the run's maximum cost pays for. The log says how many files were kept and why the others were not.

#### Contacts from the author's website

With **Contacts from the author's website** (and **Author profiles**, where the links come from), the Actor opens the website each author cites in its bio: its home page and up to two pages of the same site that the home page links as contact, about or legal notice (a link-in-bio page such as Linktree is one page). The row gets `authorWebsite` (the site), `authorWebsiteEmails` and `authorWebsitePhones` (`+` and digits for an international number), and `authorSocialLinks` (Instagram, Facebook, LinkedIn, X, YouTube, TikTok, WhatsApp and Telegram profiles, from the bio and from the website). Each website is read once per run: every post of the author carries the same values.

An author is charged once per run, and only when at least one e-mail address or phone number is found on its website; the social links are free. Links to Instagram, Facebook, YouTube, TikTok, X, LinkedIn, WhatsApp, Telegram and Threads are never opened, and the Actor reads only the website the author itself cites. A website that cannot be opened, is protected or gives nothing costs nothing, and the log counts them.

#### All 113 fields

| Fields | What you get |
| --- | --- |
| `type`, `id`, `url`, `source`, `sourceInput`, `scrapedAt` | `post` or `profile`, Threads id, public link, what produced the row (`search`, `hashtag`, `profile-posts`, `profile`, `post`, `replies`), the keyword / account / URL you gave, ISO timestamp |
| `searchQuery`, `matchedKeywords`, `matchedIn` | **Keyword match**: the search sent to Threads (`nike dunk`), your keywords found in the post, where (`text`, `quotedPost`, `link`, `imageAlt`, `topic`) |
| `code`, `text`, `createdAt`, `createdAtTimestamp`, `isEdited`, `language` | **Post**: code of its URL, full text, publication date (what the date filters read), edited, language when Threads gives it |
| `sentiment`, `sentimentScore`, `aiLabelMatches` | **AI** (options): `positive`, `neutral` or `negative` for the text of the post or reply, and the confidence in it from `0` to `1` (**AI sentiment label**); the labels you wrote that apply to the text, each as `{ "label", "score" }`, `[]` when none applies (**AI labels**). `null` when the option is off or skipped, or when the row has no text |
| `likeCount`, `replyCount`, `repostCount`, `quoteCount`, `shareCount`, `viewCount`, `likeCountsHidden` | **Engagement**; views read on the post's own page (`includeViews`: posts found by a keyword search, and post URLs), `null` for the posts of accounts, replies, and a post too new for Threads to show them; `likeCountsHidden` = the author hides likes and views: `likeCount` and `viewCount` are then `null`, never a false 0 |
| `engagementRate`, `engagementBase` | **Engagement rate** (computed for you, free): likes + replies + reposts + quotes divided by the views (`views`), or by the author's follower count when the post has no views (`followers`; needs **Author profiles**), 4 decimals — `0.0249`. A count Threads does not give counts 0, unless it gives none of the four. `null` when the post has neither views nor followers |
| `mediaType`, `hasMedia`, `hasAudio`, `audioUrl`, `mediaCount`, `images`, `videos`, `videoDuration`, `mediaUrls`, `accessibilityCaption` | **Media**: `text`, `image`, `video`, `carousel` or `audio` (a voice note: its sound file is `audioUrl`); every photo (`url`, `width`, `height`, `altText`) and video (`url`, `width`, `height`, `thumbnailUrl`, `durationSeconds`); `videoDuration` = the length in seconds of the post's video (the first of a carousel) |
| `storedMediaUrls`, `storedAudioUrl` | **Your copy of the media** (**Download photos and videos**): where each file of `mediaUrls` is kept in the run's key-value store, in the same order, `null` for a file not kept; where the voice note of `audioUrl` is kept. `[]` and `null` when the option is off |
| `isGif`, `gifUrl`, `stickerUrls`, `musicTitle`, `musicArtist`, `musicSongId`, `podcastName`, `podcastEpisodeName`, `podcastPlatform`, `podcastUrl` | GIF, stickers, song attached, podcast episode shared |
| `mentions`, `userTags`, `hashtags`, `links`, `topicTag`, `topicId`, `linkUrl`, `linkTitle`, `linkDisplayUrl`, `linkImageUrl` | **Links and mentions**: usernames, accounts tagged on the photos and videos (rare), hashtags, links of the text, topic and its ID, link card — real targets, no redirect |
| `pollOptions`, `pollTotalVotes`, `pollIsClosed`, `pollExpiresAt` | **Polls**: `{text, votes}` per option |
| `isReply`, `replyToUsername`, `replyToText`, `replyToPostId`, `replyToUrl`, `replyDepth`, `rootPostUsername`, `isLikedByAuthor`, `relatedTo` | **Conversations**: the post answered and its text, depth under a post whose replies are read, starter of the thread, the post URL a reply belongs to |
| `isQuotePost`, `quotedPostId`, `quotedPostUrl`, `quotedPostText`, `quotedPostUsername`, `isRepost`, `repostedByUsername` | Quoted post; reposts (the original post, and who reposted it) |
| `isPinned`, `replyControl`, `isPaidPartnership`, `isSpoiler`, `isAiGenerated`, `isGhostPost`, `locationId`, `locationName` | Pinned on the profile, who can reply, paid partnership, spoiler, AI label, 24-hour post, place tagged (`locationId` and `locationName` only: no address or coordinates; Threads gives a place to about 3 % of the posts of its search results) |
| `authorId`, `authorUsername`, `authorFullName`, `authorIsVerified`, `authorProfilePicUrl`, `authorUrl`, `authorFollowerCount`, `authorBio`, `authorEmails`, `authorPhones` | **Author**; followers and bio with **Author profiles**, e-mails and phone numbers of the bio with **Author contacts** |
| `authorWebsite`, `authorWebsiteEmails`, `authorWebsitePhones`, `authorSocialLinks` | **Author's website** (**Contacts from the author's website**): the website cited in the bio, the e-mails and phone numbers found on it, the social profiles of the bio and of the website. `null` and `[]` when the option is off |
| `username`, `fullName`, `bio`, `bioLinks`, `emails`, `phones`, `followerCount`, `isVerified`, `isPrivate`, `profilePicUrl`, `profileTags`, `transparencyLabel` | **Profile** rows (`includeProfile`): name, bio, its links, e-mails and phone numbers written in it, followers, badges, topics |

### 💡 Tips

#### How to get more results

Keep **Deep search** on and raise `maxItemsPerKeyword` (or set it to `0`). A popular keyword (a brand, a celebrity) gives hundreds of posts per run; a rare one gives what Threads shows publicly — a few dozen recent posts. Add related keywords and hashtags, and schedule the Actor with **Only new posts**: Threads' public search turns quickly, each run brings new posts.

#### How to reduce costs

The price is per post saved, so the levers are `maxItemsPerKeyword`, `maxItems`, the filters and `onlyNew` for recurring runs (you never pay twice for the same post). **Author profiles** is charged per distinct author: leave it off (the default) when you do not need follower counts. The AI options are charged per post (and per label): leave them off, or keep the number of labels low, when you only need the text. **Keyword statistics** is charged per keyword and **Download photos and videos** per file kept: leave them off when the dataset is enough. The posts Threads adds without your keyword are never charged.

#### Several keywords in one run

Put them all in `keywords`: each one is searched on its own, with its own `maxItemsPerKeyword` cap. A post found by several keywords is saved — and charged — once, with all of them in `matchedKeywords`.

#### Monitoring: only the new posts

Tick **Only new posts** (`onlyNew`) and schedule the Actor. The first run returns everything; each later run skips the posts already delivered: they are not saved and not charged, and a search that finds only known posts stops early. The memory lives in a named key-value store of your account (`threads-search-scraper-seen`, up to 150,000 posts per key) and is only updated with posts that really reached the dataset. Besides them, the same store keeps the posts your filters dropped (never delivered, never counted as delivered): the next runs with the SAME filters skip them without checking or charging them again. A post dropped by `postedAfter`, `mediaOnly`, `mediaTypes`, `excludeReplies`, `verifiedOnly`, `excludeAuthors` or `excludeKeywords` costs one filter check, once per filter setting. A post dropped for its likes, replies or reposts (`minLikes`, `minReplies`, `minReposts`) or by `postedBefore` is checked, and charged, again at each run: it may reach the minimum or the date later, and you would lose it. Change a filter, a keyword, an account or a URL and the dropped posts are forgotten (checked, and charged, once more under the new filters); changing a cap (`maxItems`, `maxItemsPerKeyword`, `maxSearchPagesPerKeyword`) or the options **View counts**, **Author profiles**, **Author contacts** and **Profile of each searched account** keeps them. An account of `fromUsers` (or an `@account` keyword) stops once it meets 20 posts in a row you already have (pinned posts are not counted). Give each schedule its own `stateKey`, and tick `resetState` once to start over.

#### Filter by author and by media

`verifiedOnly`, `excludeAuthors` and `mediaTypes` read what Threads already shows with each post, and cost no extra request. In our tests on `nike` (54 posts that contain the word), `verifiedOnly` keeps 1, `mediaTypes: ["video"]` keeps 4 and `mediaTypes: ["text"]` keeps 35. Every post the filters check is charged a filter check, kept or not.

#### Filter by publication date

`postedAfter` and `postedBefore` take a date (`2026-09-01`, the whole day is included, UTC) or a period before now (`24 hours`, `7 days`, `2 weeks`), counted from the start of the run; the log shows it as `Date range (UTC)`. The filter reads `createdAt`. Threads' public search mostly shows posts from the last day or two: a date range further back gives few posts from a search — use `fromUsers` to search accounts' whole history.

### 🔌 Integrations and API

Call the Actor via the Apify API, the JavaScript or Python clients, or connect it with integrations and webhooks (Make, Zapier, n8n, Google Sheets, Slack, Airtable…). The dataset can be fetched as JSON or CSV from any tool.

### 🤖 Use with AI agents (MCP)

AI agents (Claude, ChatGPT, Cursor…) can find and run this Actor through the [Apify MCP server](https://mcp.apify.com), billed to their Apify account like any run — for questions such as "what are people saying about X on Threads". It returns one item per Threads post that mentions the keywords. Actor id: `nice_dev/threads-search-scraper`; MCP server with this Actor only: `https://mcp.apify.com/?tools=fetch-actor-details,nice_dev/threads-search-scraper`.

Smallest input, for a cheap first call:

```json
{
    "keywords": ["apify"],
    "maxItemsPerKeyword": 10,
    "includeViews": false,
    "includeAuthorProfiles": false
}
```

Key output fields: `text`, `createdAt`, `url`, `authorUsername`, `likeCount`, `replyCount`, `engagementRate`, `matchedKeywords` and `authorFollowerCount`.

Cost: per post saved, plus a small run start fee and, when on, per author looked up and per AI label (`includeSentiment`, `aiLabels`, both off by default); see the pricing section above. Cap each call with `maxItems` and, through the API, with the run option `maxTotalChargeUsd`.

### ❓ FAQ

#### Is it legal to scrape Threads?

The Actor only reads what Threads shows publicly to any visitor without an account. It logs in to nothing and uses no account or cookie of yours. With **Contacts from the author's website** it also opens the public website an author itself cites in its bio, and nothing else. Results contain personal data (usernames, names, bios, posts, and the e-mails or phone numbers people wrote in their bio or published on their website), which is protected by GDPR: do not store it without a legitimate reason, and delete what an author has deleted. You are responsible for using the data in compliance with Threads' Terms of Use and applicable law. This Actor is not affiliated with Threads or Meta.

#### Does it need a Threads account or a proxy?

No account. The proxy is included in the price: leave the default setting (the residential proxy is not available). When Threads refuses a request, it is sent again at once on a new proxy session.

#### Why do other Actors return posts without my keyword?

Threads adds loosely related popular posts to the results it shows visitors (tested on `nike`: 50 of 185 threads contained the word). This Actor keeps only the posts that contain your keyword — untick **Only posts that contain a keyword** to get them all.

#### Is the data safe to open in Excel or to show on a web page?

Posts and bios are their authors' own words, copied as they are. A text can begin with `-`, `+`, `=` or `@` (a mention, `-20% today`): Excel and Google Sheets may read such a cell of a CSV file as a formula. The Actor leaves the text as it is, so that the JSON and the API give the real value: when you open a CSV, import these columns as text. Every URL field holds an http(s) URL or null. On a web page, escape every field like any text written by a stranger.

#### Known limitations

- Without an account, Threads' search shows **recent posts only** (about 90 % from the last 24 hours) and no page after the first: the history of a keyword is not reachable. Deep search widens what it shows; a rare keyword still gives a few dozen posts. To search further back, use `fromUsers` (the whole history of chosen accounts).
- Threads ignores its own "Recent" order, dates and author filters for visitors without an account: this Actor applies the date, author, verified and media-type filters itself, and `sortByRecent` orders the posts of each page.
- Views are shown by Threads a little while after a post is published: a very new post can have `viewCount` null.
- Followers and following lists need a Threads account: not available.
- Replies under a post: Threads shows visitors about 80 % of the replies it counts.
- `onlyNew` remembers post ids, not their content: a post whose likes changed is not returned again.
- Files kept with **Download photos and videos** weigh on the run's storage and memory: a photo is a fraction of a MB, a video can be tens. With less than 1 GB (the default is 512 MB) the files are copied 4 at a time and none over 50 MB is kept; for many videos, or for videos above 50 MB, give the run 1 GB or more (Run options → Memory) and raise `maxMediaFileMb`.

**A run the platform stops without warning** (out of memory, run timeout)

- Resurrect it: it goes on from where it stood at most a minute before the stop. The results already saved are skipped: none is delivered or charged twice, and `maxItems` still counts them.
- With `onlyNew`, the memory is saved after each write (at most once every 2 seconds): resurrect the stopped run and the posts it had saved meanwhile join the memory; leave it stopped for good, and the next run may return the posts of its last 2 seconds once more.

#### Something doesn't work?

The last line of the log counts the results saved, filtered out, not found on Threads, and the requests that failed after every retry. Those requests are listed, with the reason, in the `FAILED_REQUESTS` record of the run's key-value store. A run fails when Threads changes its pages: it stops and names what it could not read, instead of ending green with empty columns or no results.

If Threads changes its pages, you are told instead of paying for blank rows: if the first 20 posts read all lack their date, author, verified badge, media type, counts or views (views are checked on posts more than 6 hours old, read on their own page: a newer post often has none yet) — or the first 20 profiles their username or followers —, the run saves nothing more, stops and fails, and its last message names the missing field. A smaller run (5 to 19 posts) is checked the same way at its end: its rows are kept, and the run fails with the field's name.

### 🛟 Support

Open an issue in the **Issues** tab with a link to your run: the run log and the `FAILED_REQUESTS` record of the key-value store show exactly which URLs failed and why.

# Actor input Schema

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

Words, phrases or hashtags, as typed in the Threads search box: `nike`, `artificial intelligence`, `#ai`. Put a phrase in quotes (`"air max"`) to require the exact phrase. `@account` = the posts of that account (its whole history). Max 100 keywords of 200 characters.

## `maxItemsPerKeyword` (type: `integer`):

Posts to save for EACH keyword (after filters and deduplication). 0 = as many as Threads shows. A rare keyword can return fewer: Threads shows visitors only its recent public posts (see **Deep search**).

## `sortByRecent` (type: `boolean`):

On: Threads' Recent view is read first and each page is saved newest first. Off: Threads' Top ranking first. Threads' public search shows recent posts either way (about 90 % from the last 24 hours).

## `deepSearch` (type: `boolean`):

Find more posts per keyword: after Threads' Top, Recent and topic views, also search a one-word keyword as a hashtag (`#nike`), the longer phrases found around your keyword in the results (`nike dunk`, `nike stock`) and the site in other languages, keeping only posts that contain your keyword. Off = the three views only (about 15-35 posts per keyword).

## `includeViews` (type: `boolean`):

Fill `viewCount` by reading each post a keyword search finds on its own page, the only place Threads shows the views (about 0.8 MB and 1 s per post; very new posts can have none yet). The posts of accounts (`@account`, **Search inside accounts**) and replies have no views. Turn it off for the fastest runs.

## `fromUsers` (type: `array`):

Usernames (`nasa`, `@nasa`) or profile URLs: every post of these accounts (their whole history, newest first) that contains one of the keywords. Without keywords, all their posts. Max 1 000 accounts.

## `startUrls` (type: `array`):

Threads search URLs (`https://www.threads.com/search?q=nike`), profile URLs or post URLs: handled like a keyword, an @account keyword or a single post. A text file of URLs (one per line, uploaded or linked) works too. Max 1 000 URLs.

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

Maximum number of results (posts, replies and profiles) for the whole run, after deduplication and filters. 0 = no limit.

## `requireKeywordMatch` (type: `boolean`):

Keep only the posts in which one of your keywords appears (text, quoted post, shared link, image description or topic; case and accents ignored). Threads pads its public results with loosely related posts: turned off, you get them too (field `matchedKeywords` empty).

## `postedAfter` (type: `string`):

Only posts published on or after this date: `2026-09-01` (a day in UTC), or a period before now such as `24 hours`, `7 days`, `2 weeks`. Threads' public search mostly shows posts from the last day or two; on an account, the history stops at older posts (pinned posts excepted).

## `postedBefore` (type: `string`):

Only posts published on or before this date (the whole UTC day is included), or older than a period such as `30 days`.

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

Only posts with at least this many likes. 0 = no minimum.

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

Only posts with at least this many replies. 0 = no minimum.

## `minReposts` (type: `integer`):

Only posts reposted at least this many times (quotes not counted: the number under Threads' repost button adds them). 0 = no minimum.

## `mediaOnly` (type: `boolean`):

Only posts with at least one image or video.

## `mediaTypes` (type: `array`):

Only the posts of these kinds: `text` (no photo or video of its own: a link card, a poll or a GIF can come with it), `image` (one photo), `carousel` (several photos or videos), `video`, `audio` (a voice note). Empty = every kind.

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

Drop the replies (posts written under another post) and keep only top-level posts.

## `verifiedOnly` (type: `boolean`):

Only the posts whose author has the verified badge. Off = every author.

## `excludeAuthors` (type: `array`):

Drop the posts of these accounts: usernames (`nasa`, `@nasa`) or profile URLs. Max 1 000 accounts.

## `excludeKeywords` (type: `array`):

Drop the posts whose text, image descriptions or link title contain one of these words (case and accents ignored). A word is also found inside a longer one: `art` drops `party` too.

## `includeAuthorProfiles` (type: `boolean`):

Fill the author's follower count and bio on every post, by opening the profile page of each distinct author once (charged as an extra event per author, see Pricing). Unticked (default): no follower count nor bio.

## `includeAuthorContacts` (type: `boolean`):

Also give the e-mail addresses and phone numbers written in the author's bio (`authorEmails`, `authorPhones`). Needs **Author profiles**; charged once per author who has at least one (see Pricing). Nothing is looked up outside Threads.

## `includeProfile` (type: `boolean`):

For `@account` keywords and **Search inside accounts**: also save one profile row per account (name, bio, links, followers, e-mails and phones of the bio). Read from the same page as its first posts (no extra request).

## `repliesForAllPosts` (type: `boolean`):

Also save the replies under every post found (see **Max replies per post**). One or more extra requests per post that has replies.

## `maxReplies` (type: `integer`):

Replies to save under each post found (with **Replies of every post found**) and under each post URL. 0 = the post only. Threads shows visitors about 80 % of the replies it counts.

## `repliesSort` (type: `string`):

Top = Threads' own ranking (most relevant first), Recent = newest first.

## `includeSentiment` (type: `boolean`):

Add an AI sentiment label to the text of each post and reply: positive, neutral or negative, with a score from 0 to 1, in two extra fields. Charged once per post or reply that gets a label (an extra event, see Pricing); a post without text costs nothing. Requires 2 GB of memory (Run options → Memory): with less, the option is skipped, the log says so and nothing is charged. Unticked (default): those fields stay empty.

## `aiLabels` (type: `array`):

Your own labels, judged on the text of each post and reply: a name such as `pricing`, or a name and a sentence that is true when the label applies, after a colon, such as `competitor: The author compares tools`. Up to 20. Each post and reply gets the labels that apply, with a score from 0 to 1, in `aiLabelMatches`. Charged per post and per label judged, whether it applies or not (an extra event, see Pricing); a post without text costs nothing. Requires 2 GB of memory (Run options → Memory): with less, the option is skipped, the log says so and nothing is charged. Empty (default): off.

## `includeKeywordStats` (type: `boolean`):

Add a summary of each keyword to the run's key-value store, in the `KEYWORD_STATS` record (never in the dataset): number of posts and replies, first and last date, posts per day, average and median likes, replies, reposts, quotes and views, median engagement rate, share of posts with media, share of verified authors, languages when Threads gives them, top 10 hashtags, top 10 authors, top 5 posts by likes, and the share of positive, neutral and negative posts when **AI sentiment label** is on. A post that contains several keywords counts under each. Charged once per keyword given (an extra event, see Pricing); a keyword needs at least 5 posts in the run and at most 50 keywords are given, the biggest first. With **Only new posts**, only the posts delivered in this run are counted. Unticked (default): nothing is added.

## `downloadMedia` (type: `boolean`):

Keep a copy of the photos, videos and voice notes of each post in the run's key-value store (`media-<post id>-<n>.<extension>`) and put the links in `storedMediaUrls` (same order as `mediaUrls`) and `storedAudioUrl`. The links Threads gives in `mediaUrls` are signed and expire: your copy does not. Charged once per file kept (an extra event, see Pricing); a file that could not be kept (too big, gone, out of time) costs nothing and shows as `null`. The files are kept for the posts the run delivers. For many videos, give the run 1 GB or more of memory (Run options → Memory). Unticked (default): nothing is downloaded and those fields stay empty.

## `maxMediaFileMb` (type: `integer`):

With **Download photos and videos**: a file larger than this is not kept and not charged (`null` in `storedMediaUrls`). A photo is a fraction of a MB, a video a few MB to a few tens. Above 50, give the run 1 GB or more of memory (Run options → Memory): with less, no file over 50 MB is kept.

## `includeWebsiteContacts` (type: `boolean`):

Open the website each author cites in its bio (its home page and up to two of its contact, about or legal pages; one page for a link-in-bio page such as Linktree) and add the e-mail addresses, phone numbers and social links found there, in `authorWebsite`, `authorWebsiteEmails`, `authorWebsitePhones` and `authorSocialLinks`. Needs **Author profiles** (the links come from the bio): without it the option does nothing. Charged once per author for whom at least one e-mail address or phone number is found (an extra event, see Pricing); a website that cannot be opened or gives nothing costs nothing. Links to Instagram, Facebook, YouTube, TikTok, X, LinkedIn, WhatsApp and Telegram are never opened, they are listed as they are. Unticked (default): those fields stay empty.

## `onlyNew` (type: `boolean`):

Skip the posts that a previous run (same **Memory key**) already delivered: they are not saved and not charged. Schedule the Actor (every hour, every day) to follow a brand or a topic: each run returns only what is new. First run = everything is new. An account (`fromUsers`, @account) stops after 20 posts in a row already delivered (pinned posts excepted).

## `stateKey` (type: `string`):

Name of the memory used by **Only new posts**. Give each schedule / task its own key (e.g. `brand-watch`) so that they do not share their memory. Letters, digits, `-` and `_`.

## `resetState` (type: `boolean`):

Forget everything remembered under this **Memory key** before the run: this run returns (and charges) every post again. Untick it afterwards.

## `maxSearchPagesPerKeyword` (type: `integer`):

Upper bound on the Threads search pages read for one keyword by **Deep search** (about 1 MB each). The search also stops by itself after several pages in a row without a new matching post.

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

Apify Proxy or your own proxies. Keep the default (Apify Proxy): it is included in the price, and the Actor switches to another IP by itself when Threads refuses one. The residential Apify proxy is not available in this Actor.

## `maxConcurrency` (type: `integer`):

Maximum number of requests processed in parallel. With **Views**, each search page also reads the pages of its posts, up to 4 at once (never more than this number).

## `maxRequestsPerMinute` (type: `integer`):

Rate of the search pages and API calls. The pages of the posts (views) and of the authors are read inside them and not counted here. Threads' pages are not limited per IP; its API is, whatever the speed: lowering this does not help.

## `maxRequestRetries` (type: `integer`):

Retries per request before it is marked as failed.

## `debugLog` (type: `boolean`):

Include debug messages in the run log.

## Actor input object example

```json
{
  "keywords": [
    "nike"
  ],
  "maxItemsPerKeyword": 20,
  "sortByRecent": true,
  "deepSearch": true,
  "includeViews": true,
  "fromUsers": [],
  "startUrls": [],
  "maxItems": 1000,
  "requireKeywordMatch": true,
  "minLikes": 0,
  "minReplies": 0,
  "minReposts": 0,
  "mediaOnly": false,
  "mediaTypes": [],
  "excludeReplies": false,
  "verifiedOnly": false,
  "excludeAuthors": [],
  "excludeKeywords": [],
  "includeAuthorProfiles": false,
  "includeAuthorContacts": false,
  "includeProfile": false,
  "repliesForAllPosts": false,
  "maxReplies": 20,
  "repliesSort": "top",
  "includeSentiment": false,
  "includeKeywordStats": false,
  "downloadMedia": false,
  "maxMediaFileMb": 50,
  "includeWebsiteContacts": false,
  "onlyNew": false,
  "stateKey": "default",
  "resetState": false,
  "maxSearchPagesPerKeyword": 300,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxConcurrency": 4,
  "maxRequestsPerMinute": 120,
  "maxRequestRetries": 5,
  "debugLog": false
}
```

# Actor output Schema

## `results` (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 = {
    "keywords": [
        "nike"
    ],
    "maxItemsPerKeyword": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("nice_dev/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": ["nike"],
    "maxItemsPerKeyword": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

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

```

## MCP server setup

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