# Threads Search & Profile Posts Scraper | No Login (`scraping_solutions/threads-search-scraper`) Actor

Search public Threads posts with literal word, phrase or hashtag matching, or download posts from profiles. Filter by author and dates. Export text, links, engagement and media. No login or cookies required.

- **URL**: https://apify.com/scraping_solutions/threads-search-scraper.md
- **Developed by:** [Scraping Solutions](https://apify.com/scraping_solutions) (community)
- **Categories:** Social media, Marketing, Lead generation
- **Stats:** 17 total users, 14 monthly users, 88.9% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $1.70 / 1,000 threads 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

## Threads Search & Profile Posts Scraper

Search public Threads posts by literal keyword, exact phrase or hashtag, or collect available posts from public profiles. Export post text, links, authors, publication times, available engagement and media to JSON, CSV or Excel. No Threads login or cookies required.

### Two Download Modes

| Mode | Input | Purpose |
| --- | --- | --- |
| `keyword` | Keywords, phrases or hashtags | Find public posts whose text contains the complete term. Optionally restrict searches by author and dates. |
| `profile` | Usernames or profile URLs | Collect available public posts from specific accounts, without requiring a keyword. |

Use one mode per run. To search within one account, use `keyword` with `fromUsername`. To download that account's posts without a keyword, use `profile`.

### Quick Start

1. Choose **Search by keyword** or **Posts from profiles**.
2. Fill only the corresponding list. Remove the keyword example when switching to profile mode.
3. Start with 20 results per input. Optional author, date and ordering filters apply only to keyword searches.
4. Set an appropriate maximum run charge and start the Actor.
5. Export the dataset. Open **Storage > Key-value store > OUTPUT** for source counts, rejected entries, stop reasons and charged events.

#### Keyword Search

```json
{
  "mode": "keyword",
  "keywords": ["AI", "machine learning"],
  "maxResultsPerInput": 20,
  "sort": "top"
}
```

#### Search Within an Author and Date Range

```json
{
  "mode": "keyword",
  "keywords": ["AI"],
  "fromUsername": "meta",
  "oldestPostDate": "2026-09-01",
  "newestPostDate": "2026-09-27",
  "sort": "top",
  "maxResultsPerInput": 20
}
```

#### Profile Posts

```json
{
  "mode": "profile",
  "usernames": ["meta", "https://www.threads.com/@zuck"],
  "maxResultsPerInput": 20
}
```

### Input

| Field | Default | Behavior |
| --- | --- | --- |
| `mode` | `keyword` | `keyword` or `profile`. |
| `keywords` | None | Required for keyword mode. 1-100 entries, each 1-500 characters. The complete word, phrase or hashtag must occur in the post text. Plain text, not a Boolean query language. |
| `usernames` | None | Required for profile mode. 1-100 usernames or Threads profile URLs. No emails or post URLs. |
| `maxResultsPerInput` | `100` | 0-100,000 unique posts per input. 0 requests all available within safeguards, not unlimited or guaranteed coverage. |
| `sort` | `top` | `top` or `recent` for keyword searches. Top is recommended because it generally returns more unique matches per request, but its ranking is service-defined and is not guaranteed to sort by likes. Ignored in profile mode. |
| `fromUsername` | Empty | Optional author restriction for keyword mode. Accepts a username or Threads profile URL. The returned author's username must match exactly, ignoring case, before saving or charging. |
| `oldestPostDate` | Empty | Inclusive oldest UTC calendar date, `YYYY-MM-DD`. Single-digit month/day values are normalized. |
| `newestPostDate` | Empty | Inclusive newest UTC calendar date, `YYYY-MM-DD`. Must not precede the oldest date. |

Date filters are sent to the search service and enforced again locally using each post's UTC publication date. Both calendar-date boundaries are inclusive. Posts outside the range, or without a usable publication date while a date filter is active, are discarded before saving or charging. Date filters do not apply to profile mode. The Actor rejects unsupported combinations rather than silently ignoring them.

**Literal keyword verification:** search discovery can return recommendations that do not contain the requested term. The Actor checks every candidate locally before saving or charging it. Matching ignores case and normalizes whitespace. Short ASCII words use word boundaries, so `AI` matches `AI` and `#AI` but not `daily` or `said`. A multi-word entry must appear as the complete phrase in the same order. A hashtag entry such as `#AI` requires the hashtag, not just the word. Other writing systems use normalized literal substring matching. Posts without usable text are rejected in keyword mode. The Actor continues pagination after filtered pages while cursors, budget and safeguards allow it.

**Author verification:** `fromUsername` is sent to the search service and also checked against each returned post's author username. Posts from other authors or without an author username are discarded before saving or charging. A display name, text mention or quoted author is not a match. Pagination continues when a filtered page still has a next cursor, within the same budget and request safeguards. Filtering can reduce the final result count; it does not guarantee that all of an author's posts will be found.

The exact-author path has been verified with a non-empty cloud run. A combined author-and-date live sample returned no posts, so non-empty combined results remain unverified. `recent` did not always return posts in strict timestamp order; `top` returned a different result set, but ranking correctness has not been independently verified.

Invalid entries are reported by position and reason, without echoing accidentally pasted sensitive data. Valid entries continue. If no valid entry remains, the run fails with `INVALID_INPUT` before any data request.

### Output Fields

One row represents one unique post. Optional fields are omitted when absent; an unavailable count is never replaced with a made-up zero. Actual zero values remain `0`.

| Field | Description |
| --- | --- |
| `sourceType` | `keyword` or `profile`. |
| `sourceValue` | Keyword or normalized profile that first produced this post. |
| `postId` | Post identifier preserved as a string. Current responses use numeric media IDs in both modes; the older profile format uses shortcodes. |
| `postUrl` | Public post link when supplied or constructible from the returned author and shortcode. |
| `text` | Post text, when present. |
| `username`, `fullName` | Public author details. |
| `profileUrl`, `profilePicUrl` | Profile and picture links when available. |
| `isVerified` | Author verification flag when returned. |
| `publishedAt` | Publication time in UTC when supplied as a usable timestamp. |
| `likesCount`, `commentsCount` | Available likes and direct comment/reply counts. |
| `repostsCount`, `sharesCount`, `quotesCount` | Available engagement counts. These are separate metrics, not interchangeable. |
| `isReply` | Whether the result is a reply, when reported. |
| `imageUrls`, `videoUrls` | Available media URLs; these can expire. |
| `scrapedAt` | Extraction timestamp in UTC. |

#### Example Output

Illustrative record, not a promise that every result contains every field:

```json
{
  "sourceType": "keyword",
  "sourceValue": "AI",
  "postId": "1234567890123456789",
  "username": "example",
  "profileUrl": "https://www.threads.com/@example",
  "text": "An example post about AI.",
  "likesCount": 0,
  "commentsCount": 2,
  "isVerified": false,
  "publishedAt": "2026-09-27T10:00:00Z",
  "scrapedAt": "2026-09-27T12:00:00Z"
}
```

### Pricing

The Actor uses **pay per unique saved post**, with one result event. There are no start, page, retry or duplicate charges. Platform usage is included.

| Apify plan | Price per 1,000 saved posts |
| --- | --- |
| Free | $2.00 |
| Starter / Bronze | $1.90 |
| Scale / Silver | $1.80 |
| Business / Gold | $1.70 |
| Platinum / Diamond | $1.70 |

Search filters do not create a separate page charge. A run with no saved posts produces no result events. A partially completed run bills only the posts already saved.

### Free Plan Limits

Trial limits follow the existing Threads relationship Actor policy, independently tracked for this Actor:

| Execution origin | Inputs processed | Maximum runs per UTC day | Reserved posts per UTC day |
| --- | --- | --- | --- |
| Web | First valid input | 15 | 1,750 |
| API, MCP and other non-Web origins | First valid input | 5 | 1,000 |

The smaller of your requested maximum and remaining allowance applies. Reservations are consumed at the start of eligible runs, even if fewer posts are returned. Reserved allowance is not a charge: only saved posts generate result events. Paid subscribers can process all valid inputs within budget and internal safeguards.

### Reliability, Large Requests and Resume

- Posts stream to the dataset as each page is processed. Already saved posts remain available after a later failure.
- Deduplication is global within the run, including across keywords/profiles. A post appears once and belongs to the first input that found it.
- Transient errors receive at most two retries with increasing delays. Access denial stops all extraction; an unavailable profile does not block other profiles.
- Budget checks occur before data requests and writes. A small budget is allowed; the Actor does not require funding the entire requested maximum upfront.
- Repeated cursors or three duplicate-only pages stop pagination. An internal 1,000-request safeguard includes retries.
- If a non-empty response has no usable pagination information, results are retained and the summary reports `PAGINATION_UNAVAILABLE`; it does not claim that all posts were downloaded.
- Same-run platform migrations restore the stored checkpoint. Locally, rerun with the same input and storage directory. Limits can increase, but sources and filters must stay unchanged.
- A brand-new cloud run does not automatically resume an earlier run. No customer continuation token is implemented in this version.
- A local checkpoint from an older version can resume only if its saved posts satisfy the requested author filter. Otherwise, the Actor stops before any new write or charge and asks for fresh storage; it does not delete or rebill existing posts.
- Start with a 5-minute timeout for small pilots. For larger requests, use the measured request count and duration from a pilot to choose a larger timeout. High limits do not guarantee more available posts.

### Summary and Audit

`OUTPUT` lists results, duplicates, requests, average page size and stop reasons per source. `keywordFiltered` counts deduplicated candidates rejected by literal term verification. `authorFiltered` counts candidates rejected by the author check after keyword verification; `authorMissing` is the subset without a usable author username. `dateFiltered` counts candidates outside the inclusive UTC range; `dateMissing` is the subset without a usable publication date. The private audit stores the same count-only metrics without recording queries or authors. These counts are not charges.

`SUCCESS` includes reaching the requested maximum or a confirmed natural end with saved results. `PARTIAL` requires a real interruption, such as missing pagination, a later service failure or exhausted budget. A confirmed natural end without any accepted posts is `NO_RESULTS`, including when all posts were rejected by the author filter.

A separate private audit dataset stores counts, run context and sanitized errors. It does not store keyword text, profile identifiers, post content, credentials or pagination cursors, and it does not create result charges.

### Known Limitations

- Only publicly accessible content is supported. Private/restricted content is unavailable.
- Discovery is service-ranked and is not exhaustive full-text indexing or guaranteed historical coverage. Literal verification improves precision but cannot create candidates that discovery did not return.
- Boolean operators, language filtering and minimum-engagement filters are not implemented. Literal keyword/phrase/hashtag and exact author verification are enforced locally.
- Search and profile feeds may expose different fields, availability and page sizes.
- Two-page keyword and profile pagination has been verified with live responses. This does not establish unlimited access or exhaustive historical coverage.
- Media files are not downloaded; available URLs are returned.

### FAQ

**Can I download posts from several profiles or keywords?** Yes, with a paid subscription. Free processes the first valid input only.

**Can I combine keywords and profile lists in one run?** No. Select a mode. For a keyword within one author, use `fromUsername`.

**Does `AI AND marketing` enforce Boolean matching?** No. It is treated as one literal phrase, including the word `AND`. Submit `AI` and `marketing` as separate entries for two independent searches. This Actor does not evaluate Boolean expressions.

**Why are many discovered posts not delivered?** The search service can return recommendations unrelated to the literal query. They are counted as `keywordFiltered` and are neither saved nor charged.

**Why did I receive fewer posts than requested?** Availability, overlapping results, service limits, pagination or your budget may reduce the result count. Inspect `OUTPUT`.

**Are duplicates charged?** No. Posts are deduplicated by ID before writing and charging.

**Are empty searches or retries charged?** They do not produce result events.

**Does Top mean most likes?** No. Ranking is controlled by the search service.

**Can I filter dates on a profile download?** Not in this version. Author/date filtering is supported only for keyword searches.

**Can I export to CSV or Excel?** Yes, from the Apify dataset export menu.

**Can I resume without starting over?** Same-run migration and local checkpoint recovery are supported. Cross-run continuation is not implemented.

### Related Actors

- [Threads Followers & Following Scraper](https://apify.com/scraping_solutions/threads-followers-following-scraper)
- [Instagram Boolean Search Scraper](https://apify.com/scraping_solutions/instagram-boolean-search-scraper-posts-reels)
- [TikTok Boolean Search Scraper](https://apify.com/scraping_solutions/tiktok-boolean-search-scraper-videos-hashtags)

### Responsible Use and Support

Use public data responsibly, respect applicable privacy requirements and platform terms, and do not use this Actor for spam or harassment. Report issues with the run ID, mode and sanitized input. Never share credentials or internal cursors in a public issue.

### Categories

Social Media, Marketing, Lead Generation.

# Actor input Schema

## `mode` (type: `string`):

Keyword searches public posts. Profile downloads available public posts from the supplied profiles. Use one mode per run.

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

Required in keyword mode: 1-100 entries, each 1-500 characters. A post is saved only when its text contains the complete word, phrase or hashtag. Matching ignores case; AI does not match inside daily. This is not a Boolean parser. Do not also supply usernames.

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

Required in profile mode: 1-100 usernames, @usernames or Threads profile URLs. Remove keywords when switching to this mode. Invalid entries are reported by index.

## `maxResultsPerInput` (type: `integer`):

Maximum unique posts attributed to each input, from 0 to 100,000. 0 requests all available within budget and internal safeguards. Posts found under multiple inputs are saved and charged once, under the first matching input. Free quota can reduce the limit.

## `sort` (type: `string`):

Search order in keyword mode. Top is the recommended default because it generally returns more unique matches per request, but its ranking is service-defined and is not guaranteed to sort by likes. This setting is ignored in profile mode.

## `fromUsername` (type: `string`):

Optional Threads username or profile URL to restrict keyword searches to one author. Returned author usernames are checked for an exact, case-insensitive match before saving or charging. Posts from other or unidentified authors are discarded; counts appear in OUTPUT. Leave empty for profile mode.

## `oldestPostDate` (type: `string`):

Optional inclusive YYYY-MM-DD lower boundary in UTC. Returned posts are checked locally before saving or charging. Leave empty for profile mode.

## `newestPostDate` (type: `string`):

Optional inclusive YYYY-MM-DD upper boundary in UTC. Must not precede the oldest date. Returned posts are checked locally before saving or charging. Leave empty for profile mode.

## Actor input object example

```json
{
  "mode": "keyword",
  "keywords": [
    "AI"
  ],
  "maxResultsPerInput": 100,
  "sort": "top",
  "fromUsername": "",
  "oldestPostDate": "",
  "newestPostDate": ""
}
```

# Actor output Schema

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

No description

## `summary` (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": [
        "AI"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("scraping_solutions/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": ["AI"] }

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

```

## MCP server setup

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