# Threads Posts Scraper (`khadinakbar/threads-posts-scraper`) Actor

Extract structured public Threads posts from profile handles, profile URLs, and individual post URLs.

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

## Pricing

from $5.00 / 1,000 public post scrapeds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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 Posts Scraper?

Threads Posts Scraper is an Apify Actor for analysts, automation builders, and AI agents that need structured public Threads posts from profile handles, profile URLs, or individual post URLs. It accepts public Threads input and returns one validated dataset record per public post, with canonical post URL, post ID, text, publication time, public author metadata, public engagement metrics when available, parsed media and text entities, provider source, and scrape timestamp.

Each record represents one public Threads post. The most useful downstream fields include `postUrl`, `postId`, `text`, `publishedAt`, `authorUsername`, `authorName`, `authorVerified`, `authorProfileUrl`, `likeCount`, `replyCount`, `repostCount`, `quoteCount`, `viewCount`, `media`, `hashtags`, `mentions`, `externalUrls`, `source`, and `scrapedAt`.

### Best fit and connected workflows

This Actor fits workflows that begin with known public Threads identities or direct public post links and need normalized record-level output.

Common routing patterns include:

- Social listening pipelines that start from a curated set of public creator or brand profiles.
- Content review flows that collect a defined set of public post URLs for analysis or reporting.
- AI enrichment workflows that turn public Threads posts into structured inputs for tagging, summarization, extraction, or classification.
- Automation flows that send one row per post into spreadsheets, databases, BI tools, review queues, or internal applications.

### Practical scenario

A social media manager has public profile handles for a brand and two competitors. They enter those handles in `startUrls`, keep `maxPosts` at 10, and run the Actor. The dataset returns `postUrl`, `authorUsername`, `text`, `publishedAt`, `likeCount`, `replyCount`, `repostCount`, and `source`. The manager uses `publishedAt` and the engagement fields to choose posts for a weekly report, then opens `postUrl` to review the public post context.

### Input

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `startUrls` | array | Yes | Public Threads profile handles, profile URLs, or individual post URLs to collect from. Examples: `@zuck`, `https://www.threads.com/@zuck`, or `https://www.threads.com/@zuck/post/ABC123`. Up to 20 entries are accepted and duplicate posts are removed. This input is for public profile, profile URL, or post URL collection only. |
| `maxPosts` | integer | No | Maximum number of unique public posts returned across the entire run. Defaults to 10 and accepts 1 to 20. For example, 10 caps the dataset and event charges at ten posts even when multiple profiles are supplied. |
| `providerOrder` | string | No | Controls the verified public-data provider order. `auto` uses ScrapeCreators first and SociaVault only on an upstream interruptions. The explicit values are available for diagnostics. |

#### Focused input example

```json
{
  "startUrls": [
    "@zuck",
    "https://www.threads.com/@instagram"
  ],
  "maxPosts": 10,
  "providerOrder": "auto"
}
```

### Output

One validated record is written per public Threads post. Results live in the default dataset, and execution metadata is written to key-value store records for the run summary and detailed diagnostics.

| Field | Type | Description |
| --- | --- | --- |
| `recordType` | string | Always `post`. |
| `postId` | string | Threads post identifier. |
| `postUrl` | string | Canonical public Threads post URL. |
| `text` | string, null | Post caption or text as publicly served. |
| `publishedAt` | string, null | Publication time in ISO 8601 format. |
| `authorUsername` | string | Public Threads author handle without `@`. |
| `authorName` | string, null | Public display name. |
| `authorVerified` | boolean, null | Public verification status. |
| `authorProfileUrl` | string, null | Public Threads profile URL. |
| `likeCount` | integer, null | Public likes count. |
| `replyCount` | integer, null | Public direct reply count when returned. |
| `repostCount` | integer, null | Public repost or reshare count when returned. |
| `quoteCount` | integer, null | Public quote count when returned. |
| `viewCount` | integer, null | Public view count when returned. |
| `isReply` | boolean, null | Whether the record is a reply when reported. |
| `isRepost` | boolean, null | Whether the record is a repost when reported. |
| `media` | array | Public image or video URLs when returned. |
| `hashtags` | array | Hashtags parsed from the public post text. |
| `mentions` | array | Mentions parsed from the public post text. |
| `externalUrls` | array | External URLs parsed from the public post text. |
| `source` | string | Provider that supplied the public data. |
| `scrapedAt` | string | Collection time in ISO 8601 format. |

#### Illustrative output record

```json
{
  "recordType": "post",
  "postId": "ABC123",
  "postUrl": "https://www.threads.com/@instagram/post/ABC123",
  "text": "Public post text",
  "publishedAt": "2024-01-15T12:34:56Z",
  "authorUsername": "instagram",
  "authorName": "Instagram",
  "authorVerified": true,
  "authorProfileUrl": "https://www.threads.com/@instagram",
  "likeCount": 1200,
  "replyCount": 45,
  "repostCount": 18,
  "quoteCount": null,
  "viewCount": null,
  "isReply": false,
  "isRepost": false,
  "media": [],
  "hashtags": ["threads"],
  "mentions": ["@meta"],
  "externalUrls": ["https://example.com"],
  "source": "scrapecreators",
  "scrapedAt": "2024-01-15T12:40:00Z"
}
```

### How it works

The Actor accepts public Threads profile handles, profile URLs, or post URLs as inputs. It uses verified public-data provider routing, with ScrapeCreators first in `auto` mode and SociaVault available as an explicit route for diagnostics. Both provider routes return the same normalized output shape.

The dataset contains one validated record per public post. The Actor also writes execution metadata to the key-value store, including `OUTPUT` and `RUN_SUMMARY`.

The live contract uses SDK-coupled write-and-charge billing. Each validated public post written to the dataset is one `Public post scraped` event, and one `Actor start` event is charged per run. Apify platform usage is billed separately under Pay per event plus usage.

### Pricing

This Actor uses Pay per event pricing on Apify.

- `Actor start` is charged once per run and scales by allocated memory.
- `Public post scraped` is charged once per validated public post written to the dataset.

For example, a run that returns ten public posts produces ten post events plus one start event. Open the live Pricing tab in the Apify console for the current pricing details.

Apify platform usage is charged separately from Actor events.

### Use with AI agents (MCP)

This Actor is available as an Apify Actor usable through Apify MCP. The exact Actor identity is `khadinakbar/threads-posts-scraper`.

Tool description: submit public Threads profile handles, profile URLs, or post URLs, then read the structured dataset output for each validated public post.

> Collect up to 10 public Threads posts from @zuck and https://www.threads.com/@instagram. Return one record per post with the canonical URL, author handle, text, publication time, public metrics, source, and scrape timestamp.

Output interpretation:

- `postUrl` is the canonical link to the public post.
- `authorUsername` identifies the public author handle without `@`.
- `text` contains the post caption or body as publicly served.
- `publishedAt` and `scrapedAt` support timeline-aware workflows.
- `likeCount`, `replyCount`, `repostCount`, `quoteCount`, and `viewCount` reflect public metrics when returned.
- `source` shows which public provider supplied the record.

Provenance and scope:

- One dataset record corresponds to one validated public post.
- Duplicate posts are removed across the run.
- The provider order can be set to `auto`, `scrapecreators-first`, or `sociavault-first`.
- Results come from public provider routes and preserve the normalized dataset contract.

Pagination and cost guidance:

- `maxPosts` limits the total number of unique posts returned across the run.
- Event-based pricing is driven by validated dataset records.
- Review the live Pricing tab for the current event pricing in the Apify UI.

### Example with the Apify API

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({
  token: process.env.APIFY_TOKEN,
});

const run = await client.actor('khadinakbar/threads-posts-scraper').call({
  startUrls: ['@zuck', 'https://www.threads.com/@instagram'],
  maxPosts: 5,
  providerOrder: 'auto',
});

const { items } = await client.dataset(run.defaultDatasetId).listItems({ clean: true });

console.log(items);
```

### Best results and outcome guidance

Use a focused set of public handles or direct public post URLs when you want a compact dataset. Use `maxPosts` to control the total number of unique posts collected in a run. When you want provider tracing for diagnostics, switch `providerOrder` from `auto` to one of the explicit provider orders.

For the clearest downstream use, keep inputs to public profile handles, public profile URLs, or direct public post URLs. The output records are designed for one-row-per-post processing in spreadsheets, databases, BI tools, and AI pipelines.

### Continue the workflow

- Then use [Threads Search Scraper](https://apify.com/khadinakbar/threads-search-scraper) to extend Threads Posts Scraper research with a complementary discovery contract.
- Then use [TikTok Ads Library Scraper for Ad Research](https://apify.com/khadinakbar/tiktok-ads-library-scraper) to extend Threads Posts Scraper with a neighboring social-media research source when the brief calls for Tiktok data.

### Design note

I found that the live dataset contract always includes `recordType` with the description "Always 'post'." That makes each output row easy to interpret as a single post-level record.

### FAQ

#### Can I start from a public profile handle?

Yes. `startUrls` accepts public Threads profile handles such as `@zuck`.

#### Can I start from a profile URL or a post URL?

Yes. `startUrls` accepts public profile URLs and individual public post URLs.

#### How many posts can one run return?

`maxPosts` controls the total number of unique public posts returned across the full run, with a supported range of 1 to 20.

#### Which public providers are used?

The contract lists ScrapeCreators and SociaVault, with `auto` routing ScrapeCreators first and SociaVault as a fallback path.

#### What data is written to the dataset?

One validated record per public post, including identity, content, author metadata, metrics when returned, parsed entities, source, and scrape time.

#### Is this Actor usable through Apify MCP?

Yes. It is an Apify Actor and can be used through Apify MCP with the exact Actor identity `khadinakbar/threads-posts-scraper`.

### Responsible use

Use this Actor only for public Threads data that you are authorized to collect and process. Respect platform terms, applicable privacy law, and the rights of people whose public posts you collect.

# Changelog

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

# Actor input Schema

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

Public Threads profile handles, profile URLs, or individual post URLs to collect from. Examples: '@zuck', 'https://www.threads.com/@zuck', or 'https://www.threads.com/@zuck/post/ABC123'. Up to 20 entries are accepted and duplicate posts are removed. This is NOT for private, login-only, search, or hashtag data.

## `maxPosts` (type: `integer`):

Maximum number of unique public posts returned across the entire run. For example, 10 caps the dataset and event charges at ten posts, even when multiple profiles are supplied. Defaults to 10 and accepts 1–20 because public provider routes expose only recent posts. This is NOT a per-profile cap.

## Actor input object example

```json
{
  "startUrls": [
    "@zuck",
    "https://www.threads.com/@instagram"
  ],
  "maxPosts": 10
}
```

# Actor output Schema

## `posts` (type: `string`):

No description

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

No description

## `diagnostics` (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 = {
    "startUrls": [
        "@zuck"
    ]
};

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

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

```

## MCP server setup

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