# Threads Scraper — $0.15/1K · Posts, Profiles & Search (`apivault_labs/threads-scraper`) Actor

Collect public Threads profiles and initial-page posts or keyword results. Source text, dates, engagement and media URLs with explicit coverage limits.

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

## Pricing

from $0.08 / 1,000 useful record delivereds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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 public profiles, posts and search — illustrative artwork](https://raw.githubusercontent.com/apivault-labs/apivault-labs/5b1abd6/assets/threads-scraper/readme-cover-v1.png)

### Threads public posts, profiles and keyword research

Collect public Threads observations for content research, small account inventories and keyword monitoring. Get the source's post text, author, dates, available engagement counts and media URLs, or a public profile's name, biography and followers. No Threads login, user cookies, external provider key or mandatory paid proxy is required.

**Coverage is the public initial page, not a complete archive.** Profiles, feed availability and search ranking can vary by time and location. A public-page shell without structured records is an error, not a successful empty scrape. This is an independent tool and is not affiliated with Meta.

#### Quick start

Choose **Recent profile posts**, keep `nasa` and start with five records:

```json
{"mode":"posts","usernames":["nasa"],"maxResults":5}
```

Inspect the Dataset and `SUMMARY`. Source may expose fewer posts than requested. A limit of 100 does not force a hundred records or add pagination.

#### Choose the right mode

| Goal | Mode | Input | Coverage |
|---|---|---|---|
| Read public profile metadata | profiles | usernames | One profile record per accessible account |
| Read recent public posts | posts | usernames | Initial public feed only; primary posts, without contextual replies or quoted posts as extra rows |
| Search a phrase | search | searchQueries | Initial public search results; source ranking, no exhaustive keyword coverage |

#### Examples

Read one public profile:

```json
{"mode":"profiles","usernames":["https://www.threads.com/@nasa"],"maxResults":1}
```

Compare two explicit accounts:

```json
{"mode":"profiles","usernames":["nasa","zuck"],"maxResults":2}
```

Search a phrase:

```json
{"mode":"search","searchQueries":["space"],"maxResults":5}
```

Request the recent source ordering:

```json
{"mode":"search","searchQueries":["space"],"searchSort":"recent","maxResults":5}
```

Filter the accessible feed by date:

```json
{"mode":"posts","usernames":["nasa"],"maxResults":5,"postedAfter":"2026-10-01","postedBefore":"2026-11-01"}
```

Date examples are historical sample configuration, not an instruction to use those dates forever. Change them to your research window. Filters do not recover older posts outside the initial page.

#### Output and missing values

| Record | Fields | Meaning |
|---|---|---|
| Post | id, shortcode, postUrl, username, authorId, text, publishedAt | Public identity and source text; source timestamp converted to UTC |
| Engagement | likeCount, replyCount, repostCount, quoteCount | Nonnegative source integers; unknown stays null, not zero |
| Media | imageUrls, videoUrls | Source URLs; files are not downloaded and links may expire |
| Profile | id, username, fullName, biography, followerCount, isVerified, profileImageUrl, bioLinks | Validated requested account identity and source metadata |
| Provenance | recordType, sourceUrl, observedAt | Distinguish collection time from publication time |

A useful post must have a real identity/author and source text or media. A useful profile must match the requested handle, have an ID, name and valid follower count. Contextual replies, quoted posts and recommendations are not silently relabeled as the requested author's posts. Unknown fields remain null; real source zero is retained. Media-only posts can have null text. The illustrative contract does not guarantee every field on every record.

#### Complete input reference

| Parameter | Default | Purpose |
|---|---|---|
| `mode` | `"posts"` | Select one output type. Public-source coverage is limited; inspect SUMMARY. |
| `usernames` | `["nasa"]` | For posts/profiles. Enter 1–20 handles or HTTPS threads.com / threads.net profile URLs. Ignored in search. |
| `searchQueries` | `"not set"` | Search mode only. Enter 1–20 phrases, at most 200 characters each. |
| `searchSort` | `"top"` | Requested source order, not a relevance or strict chronology guarantee. |
| `maxResults` | `5` | Global delivered-record cap across all inputs. Does not extend the public initial page. |
| `sourceTimeoutSeconds` | `60` | Overall source collection deadline, excluding Actor startup and output delivery. |
| `postedAfter` | `"not set"` | Optional ISO date or RFC3339 timestamp. Inclusive. Filters only accessible posts; does not fetch history. |
| `postedBefore` | `"not set"` | Optional ISO date or RFC3339 timestamp. Exclusive. Posts/search only; unknown dates are excluded when filtering. |
| `proxyMode` | `"direct"` | Direct by default. `residential` explicitly enables paid Apify Residential Proxy (US). Direct cloud IPs may receive HTTP429. |

#### Optional Residential Proxy

Direct cloud requests can be rate limited. Choose the Residential route only if needed; Apify proxy traffic is charged separately in addition to result events and platform usage. This is not included in the per-record tariff. The Actor does not automatically switch to a paid proxy. It does not accept user credentials or cookies. Source refusal still fails visibly.

```json
{"mode":"posts","usernames":["nasa"],"maxResults":3,"proxyMode":"residential"}
```

#### Limits, errors and completeness

The collector requests one public HTML page per distinct input, up to 20 inputs. Responses are capped at 6 MB, individual requests at 30 seconds and overall collection at `sourceTimeoutSeconds`. It does not accept arbitrary network destinations, login credentials or cookies. `threads.net` profile inputs normalize to the current `threads.com` domain.

`maxResults` is global across inputs. IDs are deduplicated within a run. Cross-run history and change detection are not built in; keep previous exports in your own database. Dates use UTC: after is inclusive, before exclusive. Unknown dates are excluded when applying a date filter.

`SUMMARY` records sources, delivered/collected counts, source-row count and `sourceHasNextPage`. A source continuation marker is not proof of fetched pagination: `paginationConfirmed` and `fullCoverage` remain false. Full post archives, all authored replies, reply-tree reconstruction, user search and private accounts are not supported in this initial version.

Invalid input, unavailable structured records and source HTTP failures go to `ERRORS` instead of the Dataset. A wholly failed request fails the run. Mixed batches preserve useful records, report PARTIAL and fail visibly so downstream tools can inspect the diagnostics. A valid source response with no matches can finish with zero records. This is different from a login shell or refused request.

Output can stop at the platform charging budget after collection; compare `recordsCollected` and `recordsDelivered`. `deliveryLimited=true` indicates this. No data quality or complete-coverage guarantee is inferred from a green run status alone.

#### Pricing

The tariff is **$0.15 per 1,000 delivered records on FREE**, $0.12 on Starter, $0.10 on Scale and $0.08 on Business (current enterprise tiers also $0.08). **No start fee. Platform resources are paid separately by the user.** A record is one useful post or profile delivered to the Dataset; failed inputs and diagnostics do not create result events.

At the FREE rate, five delivered records cost $0.00075 in result events plus platform usage. A failed or empty run can still incur resources. This is not an all-in cost or free monthly allowance. A charging budget may stop delivery after source collection; metering and termination are not instantaneous.

This is below the compared Automation Lab post/profile event prices; it is not a guarantee of the cheapest total run or equivalent archive coverage. Read the active Apify pricing card before running.

#### API, agents and automation

Use generic Apify API JSON matching this schema after the Actor is published. Select a single mode, cap the records, and inspect `SUMMARY`/`ERRORS` and run status before importing. Store your Apify token in your environment; never place it in an input or public URL.

JSON/CSV/Excel export, scheduling and webhooks use the standard Apify platform. There is no dedicated published n8n node, Python package or custom MCP server for this new Actor yet. Those integrations are not claimed. Permanent Actor ID: `rba0ClR6EJZuftwwv`. Actor page: https://apify.com/apivault_labs/threads-scraper.

```python
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("rba0ClR6EJZuftwwv").call(run_input={"mode":"posts","usernames":["nasa"],"maxResults":5}, max_total_charge_usd=0.02)
if run["status"] != "SUCCEEDED":
    raise RuntimeError("Inspect SUMMARY and ERRORS before importing partial data")
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row)
```

#### FAQ

**Can I fetch every post?** No. The public initial feed is a limited observation. A page cursor does not make the archive implemented.

**Does search return only exact keyword matches?** No. These are Threads' source-ranked results. No local exact-match filter or total-result count is promised.

**Are follower counts added to every post author?** No. Profile mode returns followers for supplied accounts; posts do not trigger hidden per-author requests or extra billing events.

**Are reply counts the replies themselves?** No. Counts are metadata. Reply bodies and complete conversations are not collected.

**Can this calculate growth or engagement rate?** No built-in historical baseline or inferred performance score is provided. Use source counts in your own reviewed analysis.

**Will a failed run cost nothing?** Result-event charges must correspond to useful delivered rows, while platform usage and any configured start fee remain separate. Read the final published tariff.

# Changelog

This Actor's version history is a separate document: https://apify.com/apivault_labs/threads-scraper/changelog.md

# Actor input Schema

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

Select one output type. Public-source coverage is limited; inspect SUMMARY.

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

For posts/profiles. Enter 1–20 handles or HTTPS threads.com / threads.net profile URLs. Ignored in search.

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

Search mode only. Enter 1–20 phrases, at most 200 characters each.

## `searchSort` (type: `string`):

Requested source order, not a relevance or strict chronology guarantee.

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

Global delivered-record cap across all inputs. Does not extend the public initial page.

## `sourceTimeoutSeconds` (type: `integer`):

Overall source collection deadline, excluding Actor startup and output delivery.

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

Optional ISO date or RFC3339 timestamp. Inclusive. Filters only accessible posts; does not fetch history.

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

Optional ISO date or RFC3339 timestamp. Exclusive. Posts/search only; unknown dates are excluded when filtering.

## `proxyMode` (type: `string`):

Direct may return429 from cloud IPs. Residential uses separately charged Apify traffic, only when explicitly selected. No login cookies.

## Actor input object example

```json
{
  "mode": "posts",
  "usernames": [
    "nasa"
  ],
  "searchSort": "top",
  "maxResults": 5,
  "sourceTimeoutSeconds": 60,
  "proxyMode": "direct"
}
```

# Actor output Schema

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

No description

## `summary` (type: `string`):

No description

## `errors` (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 = {
    "usernames": [
        "nasa"
    ]
};

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

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

```

## MCP server setup

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