# Threads User Posts Scraper (`maximedupre/threads-user-posts-scraper`) Actor

Collect public Threads posts, account replies, and reposts from the profiles you choose. Get text, dates, author details, media links, and available engagement counts for research and reporting. No Threads login is needed.

- **URL**: https://apify.com/maximedupre/threads-user-posts-scraper.md
- **Developed by:** [Maxime Dupré](https://apify.com/maximedupre) (community)
- **Categories:** Social media, Marketing, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 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

### 🧵 Turn public Threads account posts into research data

Researchers, social media teams, and developers can collect public Threads posts from the accounts they choose. Get post text, dates, author details, media links, and available engagement counts in a dataset for research and reporting. No Threads login is needed.

- Compare the public engagement counts on posts from a list of creators.
- Save posts from brand accounts to review their published content.
- Collect replies written by chosen accounts to study what they discuss.
- Review the public posts that selected accounts share as reposts.
- Export post text, dates, and media links for a content report.

#### 📦 Post content, authors, and public counts

Each saved row is one public post. Original posts, account replies, and reposts use the same row shape. Author details describe the post's author, who may differ from the submitted account when you collect reposts.

Rows include source IDs and publication times. Other fields appear when the source provides them, such as likes, replies, reposts, quotes, shares, views, media, topics, links, polls, and profile details. Missing data stays unknown rather than becoming a made-up value.

The first eligible match for a post is saved as it is found. If another submitted handle, link, or ID finds the same post later, that match is ignored. `submittedProfile` shows only the first saved match.

#### ▶️ Collect posts from your chosen Threads accounts

1. Add accounts to **Threads profiles** using handles, `@handles`, full profile links, or numeric account IDs.
2. Choose original posts, account replies, reposts, or a mix.
3. Set **Maximum posts** for a smaller run, or leave it empty to collect all available results until the source is exhausted.
4. Start the Actor and open the `dataset` output. Export the data as JSON, CSV, or Excel.

Only public content is covered. If one profile cannot be read, the Actor logs a warning and continues with the others. Public access does not guarantee every historical post.

#### ⚙️ Input

| Field | Type | What it does |
| --- | --- | --- |
| `profiles` | array of strings | Required. Add 1 to 50 accounts as handles, `@handles`, full Threads profile links, or numeric account IDs. Full links must start with `https://`. |
| `contentTypes` | array of strings | Choose one or more of `posts`, `replies`, and `reposts`. Replies are written by the submitted accounts. If omitted, only original posts are collected. |
| `maxPosts` | integer | Sets a total post limit across all submitted profiles, with a minimum of 1 and no fixed upper bound in the schema. Leave it empty to collect all available results of the selected types until the source is exhausted. |

**Example input**

This public input comes from a successful current-beta run using the default profile and post limit:

```json
{
  "profiles": [
    "@zuck"
  ],
  "contentTypes": [
    "posts"
  ],
  "maxPosts": 3
}
```

#### 🧾 Output

The `dataset` output is a string link to the default dataset overview. Export JSON or use the dataset API to read all saved fields.

**Output link**

| Field | Type | What it does |
| --- | --- | --- |
| `dataset` | string | Opens the default dataset overview with the saved Threads posts. |

**Post row fields**

All content types share this table. `postId`, `publishedAt`, `author`, `author.accountId`, and `author.username` are required. A row also has nonblank text or at least one media entry with a media URL or accessibility text. Other fields can be missing when unavailable. Dotted paths describe nested objects; `[]` marks array entries.

| Field | Type | What it does |
| --- | --- | --- |
| `postId` | string | The ID Threads assigned to the post. |
| `submittedProfile` | string | The first submitted handle, profile link, or account ID whose feed led to the saved post. |
| `text` | string | Text written in the post. |
| `publishedAt` | string | Source publication date and time in ISO format. |
| `author` | object | Public details about the post author. |
| `author.accountId` | string | The author's Threads account ID. |
| `author.username` | string | The author's public username. |
| `author.displayName` | string | The author's public display name. |
| `author.isVerified` | boolean | Whether Threads marks the author as verified. |
| `author.profileImageUrl` | string | Source link to the author's profile image. |
| `author.followerCount` | integer | The follower count reported by Threads. |
| `author.biography` | string | The author's public bio. |
| `author.emails` | array of strings | Email addresses published in the author's bio. |
| `author.phoneNumbers` | array of strings | Phone numbers published in the author's bio. |
| `author.fediverseSharingEnabled` | boolean | Whether Threads says the author shares posts to the Fediverse. |
| `author.profileLinks` | array of strings | Links shown on the author's public profile. |
| `author.profileTopics` | array of strings | Topic labels shown on the author's profile. |
| `author.linkedPodcasts` | array of objects | Podcasts linked from the author's profile. |
| `author.linkedPodcasts[].title` | string | The linked podcast title. |
| `author.linkedPodcasts[].url` | string | The linked podcast URL. |
| `likeCount` | integer | Source-reported likes. |
| `replyCount` | integer | Source-reported replies. |
| `repostCount` | integer | Source-reported reposts. |
| `quoteCount` | integer | Source-reported quotes. |
| `viewCount` | integer | Public views reported by Threads. |
| `shareCount` | integer | Source-reported shares. |
| `media` | array of objects | Photos or videos attached to the post. |
| `media[].mediaType` | string | The source media type. Required for each media entry. |
| `media[].mediaUrl` | string | Source photo or video URL. |
| `media[].altText` | string | Source accessibility text. |
| `media[].width` | integer | Source media width in pixels. |
| `media[].height` | integer | Source media height in pixels. |
| `media[].coverUrl` | string | Source video cover image URL. |
| `media[].hasAudio` | boolean | Whether Threads reports that the video has audio. |
| `topicLabels` | array of strings | Topic or trend labels attached to the post. |
| `hashtags` | array of strings | Hashtags written in the post. |
| `sharedLinks` | array of strings | Web destinations shared in the post. |
| `stickers` | array of objects | Public stickers attached to the post. |
| `stickers[].stickerId` | string | Source sticker ID for matching the same sticker across posts. |
| `stickers[].imageUrl` | string | Source sticker image link. Each sticker has an ID, an image link, or both. |
| `linkPreviewTitles` | array of strings | Titles shown in attached link previews. |
| `mentionedAccounts` | array of objects | Accounts Threads resolved from written mentions. |
| `mentionedAccounts[].accountId` | string | Mentioned account ID, when available. |
| `mentionedAccounts[].username` | string | Mentioned username. Required for each account entry. |
| `relatedPosts` | array of objects | Source references for replies, quotes, or reposts. |
| `relatedPosts[].relationType` | string | Relationship: `reply`, `quote`, or `repost`. Required for each reference. |
| `relatedPosts[].postId` | string | Related post ID. Required for each reference. |
| `poll` | object | Public poll options and vote details. |
| `poll.closesAt` | string | Source voting close date and time in ISO format. |
| `poll.isClosed` | boolean | Whether Threads reports that voting has closed. |
| `poll.options` | array of objects | Poll answer options. Required when a poll object is present. |
| `poll.options[].text` | string | Answer text. Required for each option. |
| `poll.options[].voteCount` | integer | Source vote count for the option. |
| `language` | string | Source language label. |
| `taggedPlaces` | array of strings | Place names attached to the post. |
| `replySettings` | string | The source reply-permission setting. |
| `isEdited` | boolean | Whether Threads labels the post as edited. |
| `isPinned` | boolean | Whether Threads labels the post as pinned. |
| `isSponsored` | boolean | Whether Threads labels the post as sponsored. |
| `isAiLabeled` | boolean | Whether Threads labels the post as AI generated. |
| `isSpoilerLabeled` | boolean | Whether Threads marks post content as a spoiler. |

**Example post row**

This complete row comes from a successful current-beta run. Source text and public values are shown as returned.

```json
{
  "postId": "3996155940894885511",
  "submittedProfile": "@zuck",
  "publishedAt": "2026-09-28T12:35:32.000Z",
  "author": {
    "accountId": "63055343223",
    "username": "zuck",
    "displayName": "Mark Zuckerberg",
    "isVerified": true,
    "profileImageUrl": "https://scontent-dfw5-2.cdninstagram.com/v/t51.82787-19/825322135_17989325280103224_1252773933700107438_n.jpg?stp=dst-jpg_s640x640_tt6&efg=eyJ2ZW5jb2RlX3RhZyI6InByb2ZpbGVfcGljLmRqYW5nby4xMDgwLmV4cGVyaW1lbnRhbCJ9&_nc_ht=scontent-dfw5-2.cdninstagram.com&_nc_cat=100&_nc_oc=Q6cZ2gEs-Cc8nbOXQ28CObZ7k-ax2soCBsvvM9Hju6I50QaHxIR9KP_t_lSsBA1TOH8GtWU&_nc_ohc=m7kbRoL6cbMQ7kNvwEuxwri&_nc_gid=9wOVEKyZvpCm5TokyhIuTQ&edm=APs17CUBAAAA&ccb=7-5&oh=00_AQMEauO6JXpwFYT3_pjKcSIC2zvU5kdo_KipdcuWjf9Elw&oe=6ACF40EB&_nc_sid=10d13b",
    "followerCount": 5745084,
    "biography": "Mostly superintelligence and MMA takes",
    "fediverseSharingEnabled": true,
    "profileTopics": [
      "AI Threads",
      "UFC Threads",
      "AI",
      "MMA",
      "memes"
    ]
  },
  "text": "We believe superintelligence will create significant new opportunities for all people and businesses. Meta already serves billions of people at scale and helps hundreds of millions of businesses reach customers. Today we are starting the next major pillar of our business, Meta Enterprise Platform, to help businesses use AI to grow and transform in new ways as well.",
  "likeCount": 2692,
  "replyCount": 2616,
  "repostCount": 170,
  "quoteCount": 156,
  "shareCount": 179,
  "replySettings": "everyone",
  "isEdited": false,
  "isPinned": false,
  "isSponsored": false,
  "isSpoilerLabeled": false,
  "isAiLabeled": false,
  "viewCount": 415811
}
```

#### 💳 Pricing

You pay for each public post that is read, checked, and saved from a submitted profile. This includes saved account replies and reposted posts when you select them. Later matches for the same post are ignored within the run.

The **Post** event covers the saved post, not setup work, failed reads, or profiles with no saved posts. See the Actor's Pricing tab for your current tier price. Use `maxPosts` to set a total post limit.

#### 🔌 Integrations

Open the `dataset` output in Apify Console, download JSON, CSV, or Excel, or read rows through the Apify dataset API in your own workflow. Apify schedules let you run the same input again; keep past exports yourself if you need a history.

https://www.youtube.com/watch?v=bNACk1_S_6w\&list=PLObrtcm1Kw6MUrlLNDbK9QRg8VDJg0gOW\&index=4

#### ❓ FAQ

##### Are account replies the same as comments under an account's posts?

No. `replies` collects public replies written by the accounts you submit. It does not collect other users' full comment threads.

##### What happens when two submitted profiles lead to the same post?

The first eligible match is saved. Later matches are ignored, and the row is not rewritten to add them. `submittedProfile` keeps only the first saved match.

##### Does Maximum posts apply to each account?

No. `maxPosts` is one total limit across all submitted profiles. Leave it empty to collect all available results of the selected types until the source is exhausted.

##### Can I collect every post an account has ever published?

The Actor collects available public content. It cannot guarantee access to every historical post, even when you leave the post limit empty.

##### Why are some counts or profile details missing?

Optional fields depend on what Threads makes public. Missing data is unknown. A missing count does not mean zero, and a missing label does not mean false.

##### Can I search by keyword or submit a single post URL?

This Actor reads feeds from known accounts. Keyword search, account discovery, and standalone post-detail collection are outside its scope. See Related Actors for other Threads workflows.

##### Does the Actor keep media files or track deleted posts?

No. It returns available source media links rather than a permanent media archive. It does not retain history, compare runs, or detect deletions.

##### Do I need a Threads login?

No. The Actor collects public content without a Threads login. Private content is outside its scope.

### 📝 Changelog

**v0.0** (09-10-2026)

- Initial release.

### 🆘 Support

For issues, questions, or feature requests, [file a ticket](https://console.apify.com/actors/maximedupre~threads-user-posts-scraper/issues) and I'll fix or implement it in less than 24h 🫡

### 🔗 Related Actors

- [Threads Search Post Scraper](https://apify.com/maximedupre/threads-search-post-scraper) finds public posts by keyword or hashtag and looks up known posts by URL or ID.
- [Threads Replies Scraper](https://apify.com/maximedupre/scrape-threads-replies) collects public conversation replies from post or profile URLs with root-post context.
- [Threads Video Downloader](https://apify.com/maximedupre/threads-video-downloader) gets direct source video links from known public Threads post URLs.
- [Twitter Scraper](https://apify.com/maximedupre/twitter-scraper) collects public X posts and profile data for research on another social platform.
- [Facebook User Posts Scraper](https://apify.com/maximedupre/facebook-user-posts-scraper) collects public profile and Page posts with text, authors, media, and engagement data.

**Made with ❤️ by Maxime Dupré**

# Actor input Schema

## `profiles` (type: `array`):

Add up to 50 accounts using handles, @handles, full Threads profile links, or numeric account IDs. Use complete links that start with https://.

## `contentTypes` (type: `array`):

Choose one or more: original posts, replies written by the accounts, or posts shared as reposts. If omitted, only original posts are collected.

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

Stop after this many posts across all submitted profiles. Leave empty to collect all available posts of the selected types until the source is exhausted.

## Actor input object example

```json
{
  "profiles": [
    "@username",
    "https://www.threads.net/@username",
    "123456789"
  ],
  "contentTypes": [
    "posts"
  ],
  "maxPosts": 3
}
```

# Actor output Schema

## `dataset` (type: `string`):

Open the collected Threads posts.

# 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 = {
    "profiles": [
        "@zuck"
    ],
    "maxPosts": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("maximedupre/threads-user-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 = {
    "profiles": ["@zuck"],
    "maxPosts": 3,
}

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

```

## MCP server setup

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