# Threads Scraper: posts, profiles, replies & search (`pikoulas/threads`) Actor

Scrape Meta's Threads: every post of a profile with likes, replies, reposts, quotes, images, videos and links; profile details with exact followers, bio and links; a post's replies; a profile's replies; keyword search. No login, no browser.

- **URL**: https://apify.com/pikoulas/threads.md
- **Developed by:** [Spyridon Pikoulas](https://apify.com/pikoulas) (community)
- **Categories:** Social media, Marketing, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 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.

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 Scraper

Scrape posts, profiles, replies and search results from Meta's Threads, without an account or a
browser:

- **Profiles:** by username, @handle or URL. You get the profile's details and its posts, newest
  first, as far back as the profile goes, and its replies to other posts if you want them.
- **Posts:** any post by its URL (threads.com or threads.net) or code, with as many of its replies
  as you need, top or most recent first.
- **Search:** the top posts Threads shows for a keyword.

Every post comes with its text, date, likes, replies, reposts, quotes and shares, its images and
videos (every item of a carousel, with video URLs and thumbnails), link preview, links, mentions,
topic tag and hashtags, the post it quotes, whether it's a reply and to which post, and its
author's username, name, ID, verified badge and profile picture. Every profile comes with its exact
followers, name, bio, bio links, verified and private flags, topic tags and HD profile picture.

It is fast: 1,624 items from five profiles (200 posts and 50 replies each), two posts with 150
replies each and three searches took 79 seconds. It costs **$1 per 1,000 posts or replies** and $1
per 1,000 profiles.

### What people use it for

- **Influencer and brand research:** every post of a creator or a brand with its likes, replies,
  reposts and dates, and its exact follower count.
- **Audience and sentiment analysis:** the replies under a post, with who wrote them and how many
  likes they got.
- **Monitoring:** new posts of a list of profiles since a date, day by day.
- **Trend research:** what gets posted and liked about a keyword.
- **Datasets for AI:** posts and replies at scale, with their media.

### How to scrape Threads

1. Click **Try for free**; Apify's free plan covers a first run.
2. Enter **Profiles**, **Posts** or **Search terms**, and how many posts you want.
3. Click **Start**, then download the results as JSON, CSV, Excel or HTML, or read them through
   the API.

An input with more options:

```json
{
  "profiles": ["zuck", "https://www.threads.com/@mosseri"],
  "maxPostsPerProfile": 100,
  "maxRepliesPerProfile": 20,
  "posts": ["https://www.threads.com/@zuck/post/Ddt7cL5EfUG"],
  "maxRepliesPerPost": 100,
  "repliesSort": "top",
  "searchTerms": ["sourdough bread"],
  "maxPostsPerSearch": 30,
  "postedAfter": "2026-09-01"
}
```

A Threads URL works in any of the lists: a post URL pasted under profiles is scraped as a post.
Set `maxPostsPerProfile` to 0 for the profiles' details only, or turn off `includeProfileDetails`
for their posts only. `postedAfter` applies to profiles' posts and replies, replies to posts and
search results; posts you give by URL are scraped whatever their date.

### Output

A post (two of its six carousel items shown):

```json
{
  "type": "post",
  "id": "3994109866205639942",
  "code": "Ddt7cL5EfUG",
  "url": "https://www.threads.com/@zuck/post/Ddt7cL5EfUG",
  "text": "Agrippa said it's time to get back to work 😎",
  "createdAt": "2026-09-25T16:50:21Z",
  "likes": 4784,
  "replies": 412,
  "reposts": 242,
  "quotes": 40,
  "shares": 131,
  "mediaType": "carousel",
  "media": [
    {
      "type": "image",
      "url": "https://scontent-cph2-1.cdninstagram.com/v/t51.82787-15/823965183_17989304049103224_2823186847710225415_n.webp?...",
      "width": 2160,
      "height": 2700,
      "altText": null
    },
    {
      "type": "video",
      "url": "https://scontent-cph2-1.cdninstagram.com/o1/v/t16/f2/m84/AQP4tSDWZ_OEIoMfzn4s301-vcfiNtRApjffRh5SzYaduNAtQxKpQ6_4eg8xiS8EG4KR4TsjWUP5tpvvabT5n6JyGmv_gdfkdjSBZPM.mp4?...",
      "thumbnailUrl": "https://scontent-cph2-1.cdninstagram.com/v/t51.71878-15/821267767_2421957878213550_837854343537213600_n.jpg?...",
      "width": 1080,
      "height": 1350
    }
  ],
  "gifUrl": null,
  "linkUrl": null,
  "linkTitle": null,
  "linkDomain": null,
  "linkImage": null,
  "links": [],
  "mentions": [],
  "tag": null,
  "hashtags": [],
  "quotedPost": null,
  "isReply": false,
  "replyToUsername": null,
  "parentPostUrl": null,
  "isPinned": false,
  "isPaidPartnership": false,
  "authorUsername": "zuck",
  "authorName": "Mark Zuckerberg",
  "authorId": "63055343223",
  "authorVerified": true,
  "authorProfilePic": "https://scontent-cph2-1.cdninstagram.com/v/t51.82787-19/825322135_17989325280103224_1252773933700107438_n.jpg?...",
  "input": "https://www.threads.com/@zuck/post/Ddt7cL5EfUG"
}
```

A profile:

```json
{
  "type": "profile",
  "id": "63482099442",
  "username": "mosseri",
  "url": "https://www.threads.com/@mosseri",
  "name": "Adam Mosseri",
  "bio": "Father of three boys, married to an amazing woman, head of Instagram and supporter of Threads.",
  "bioLinks": ["http://mosseri.net/"],
  "followers": 1044759,
  "verified": true,
  "private": false,
  "profilePicUrl": "https://scontent-cph2-1.cdninstagram.com/v/t51.82787-19/652081753_17949596661115443_3143547630500927369_n.jpg?stp=dst-jpg_s640x640_tt6&...",
  "tags": ["Arsenal Threads"],
  "input": "mosseri"
}
```

A reply is a post with `"isReply": true`, the username it answers in `replyToUsername` and the URL
of the post it answers in `parentPostUrl`. The later posts of a thread its author wrote as a chain
are replies to the post before them. A quote has the quoted post's ID, code, URL, text, date,
likes, author and media in `quotedPost`. `hashtags` holds the post's topic tag and the #words of
its text, lowercased.

### Use it as an API

One call runs it and returns the results as JSON (for runs under 5 minutes; longer ones start a
run and read its dataset). Apify's Python and JavaScript clients, and its Make, Zapier and n8n
integrations, work the same way.

```bash
curl -X POST "https://api.apify.com/v2/acts/pikoulas~threads/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"profiles": ["zuck"], "maxPostsPerProfile": 5, "posts": ["https://www.threads.com/@zuck/post/Ddt7cL5EfUG"], "maxRepliesPerPost": 5, "searchTerms": ["sourdough bread"], "maxPostsPerSearch": 5}'
```

AI agents can call it as a tool through Apify's MCP server: `https://mcp.apify.com?tools=pikoulas/threads`.

### How much does it cost to scrape Threads?

You pay **$0.001 per post or reply**, which is $1 per 1,000, and **$0.001 per profile**. Runs that
go through Apify's residential proxy also pay its traffic, $0.0012 per 100 KB: a post from a
profile is about 2 to 12 KB (carousels and quotes fetch the post itself for their full media), a
reply to a post about 4 KB, a search result about 15 KB, a profile about 150 to 350 KB (its whole
page). There are no monthly fees.

### Good to know

- Logged out, Threads shows only its top posts for a search, a few dozen of them (23 to 74 in our
  runs), and no recent ones. A profile's posts and a post's replies have no such limit.
- `shares` is given for a profile's posts and replies and for posts by URL; Threads leaves it out
  (null) for search results and the replies under a post.
- Image and video URLs are signed and expire after a few days.
- A post found under several profiles, posts or searches is given once per run.
- Private profiles give their details but not their posts. Deleted and private posts, and
  profiles Threads only shows to logged-in users, can't be scraped, and the log names them.

### FAQ

#### Is it legal to scrape Threads?

It collects only what Threads shows publicly, without logging in. Scraping public data is
generally legal, but personal data is protected by laws such as the GDPR and the CCPA, and
Meta's terms may limit how you use what you collect. If you're unsure, ask a lawyer;
Apify's [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/) is a good start.

#### Something missing or not working?

Open an issue on the **Issues** tab with the input you used, or ask there for a field you need.

# Actor input Schema

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

Usernames, @handles or profile URLs (threads.com/@zuck). Gives the profile's details and its posts, newest first, as set below.

## `maxPostsPerProfile` (type: `integer`):

Posts from each profile, newest first (pinned ones on top), as far back as the profile goes. 0 for none.

## `maxRepliesPerProfile` (type: `integer`):

The profile's own replies to other posts (its Replies tab), newest first, each with the URL of the post it answers. 0 for none.

## `includeProfileDetails` (type: `boolean`):

One item per profile: exact followers, name, bio, bio links, verified and private flags, profile picture.

## `posts` (type: `array`):

Post URLs (threads.com/@user/post/...), threads.net ones too, or post codes. Gives each post and its replies, as set below.

## `maxRepliesPerPost` (type: `integer`):

Replies taken under each post URL above, the replies to replies Threads shows included. 0 for the posts only.

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

Top replies first, as Threads shows them, or the most recent first.

## `searchTerms` (type: `array`):

Keywords searched on Threads: the top posts it shows for each. Logged out, Threads shows a few dozen posts per search (33 to 74 in our runs).

## `maxPostsPerSearch` (type: `integer`):

How many posts to take from each search, at most the few dozen Threads shows.

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

Only posts and replies from this date on (YYYY-MM-DD). A profile's posts stop once they get past it.

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

Not needed for most runs. When Threads refuses the run's IP on Apify, the run switches to Apify's residential proxy by itself.

## Actor input object example

```json
{
  "profiles": [
    "zuck"
  ],
  "maxPostsPerProfile": 20,
  "maxRepliesPerProfile": 0,
  "includeProfileDetails": true,
  "posts": [
    "https://www.threads.com/@zuck/post/Ddt7cL5EfUG"
  ],
  "maxRepliesPerPost": 20,
  "repliesSort": "top",
  "maxPostsPerSearch": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

No description

## `profiles` (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 = {
    "profiles": [
        "zuck"
    ],
    "posts": [
        "https://www.threads.com/@zuck/post/Ddt7cL5EfUG"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("pikoulas/threads").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"],
    "posts": ["https://www.threads.com/@zuck/post/Ddt7cL5EfUG"],
}

# Run the Actor and wait for it to finish
run = client.actor("pikoulas/threads").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"
  ],
  "posts": [
    "https://www.threads.com/@zuck/post/Ddt7cL5EfUG"
  ]
}' |
apify call pikoulas/threads --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,pikoulas/threads"
        }
    }
}
```

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/Gx6ubIZdlgcUB6gfm/builds/DeCmDl5xixXIaxlDc/openapi.json
