# Threads Scraper - Profiles, Search, Hashtags & Posts (`abdullahbilal-y/threads-profile-scraper`) Actor

Scrape public Threads (threads.com) profiles and their recent posts - followers, bio, verification, likes, replies and reposts. No login or cookies required.

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

## Pricing

from $2.00 / 1,000 results

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 - Profiles, Search, Hashtags & Posts

### What does Threads Scraper do?

This Actor extracts **public data from [Threads](https://www.threads.com)**, Meta's text-based social network, four different ways: **profiles** (followers, bio, bio links, verification, recent posts), **keyword search**, **hashtag feeds**, and **single posts**.

Its defining feature is **quality filtering that happens before you are billed**. Threads search and hashtag pages are full of zero-engagement noise — one-word posts, "inbox me" DM bait, follow-for-follow spam. This Actor drops those rows *before* they reach your dataset, and Apify bills per dataset item, so **filtered-out junk costs you nothing**. In testing, a hashtag run found 40 posts, removed 30, and charged for 10.

It needs **no login, no cookies and no session tokens**, and talks to Threads over plain HTTP instead of driving a headless browser — which is why it is fast and cheap. Put a username in the Input tab and press Start to try it.

Running on Apify also gives you a REST API, scheduled runs, webhooks, monitoring, and exports to JSON, CSV, Excel and Google Sheets.

### Why use Threads Scraper?

- **Lead generation** — pull bio links, follower counts and verification status for lists of creators.
- **Influencer research** — check real engagement before you pay for a campaign, including a `isPaidPartnership` flag showing sponsored posts.
- **Social listening** — track keywords and hashtags in your niche, without wading through spam.
- **Competitor monitoring** — schedule a daily run and watch rival accounts and branded tags over time.
- **Dataset building** — assemble clean engagement data for research or a dashboard.

### How to use Threads Scraper

1. Click **Try for free**.
2. Choose a **mode**: Profiles, Keyword search, Hashtag, or Post URL.
3. Fill the matching field — usernames, search keywords, hashtags, or post links.
4. Optional but recommended for search and hashtags: set **Minimum text length** to `80` and tick **Exclude spam**.
5. Press **Start**, then download from the **Output** tab as JSON, CSV, Excel or HTML.

### Input

| Field | Applies to | Description |
|---|---|---|
| `mode` | all | `profile`, `search`, `hashtag` or `post` |
| `usernames` | profile | Handles, `@handles` or profile URLs |
| `searchQueries` | search | Keywords or phrases |
| `hashtags` | hashtag | Tags, with or without `#` |
| `postUrls` | post | Full Threads post links |
| `searchSort` | search | `top` or `recent` |
| `minLikes` | all | Drop posts below this like count |
| `minTextLength` | all | Drop posts shorter than this — the strongest noise filter |
| `excludeSpam` | all | Remove DM-bait and follow-for-follow spam |
| `languages` | all | Keep only these language codes |
| `maxResultsPerQuery` | search/hashtag/post | Cap per query |
| `maxPostsPerProfile` | profile | Cap posts attached to each profile |

```json
{
  "mode": "search",
  "searchQueries": ["digital marketing", "saas founder"],
  "searchSort": "top",
  "minTextLength": 80,
  "minLikes": 1,
  "excludeSpam": true
}
```

### Output

Profile mode returns one item per profile with posts nested. Search, hashtag and post modes return one item per post. Download as JSON, HTML, CSV, or Excel.

```json
{
  "username": "zuck",
  "fullName": "Mark Zuckerberg",
  "biography": "Mostly superintelligence and MMA takes",
  "bioLinks": ["https://example.com"],
  "followerCount": 5741571,
  "isVerified": true,
  "userId": "63055343223",
  "postsScraped": 5,
  "posts": [
    {
      "url": "https://www.threads.com/@zuck/post/DdZ7sQvkTFn",
      "text": "Muse for Mac is out today!",
      "likeCount": 1699,
      "replyCount": 256,
      "repostCount": 128,
      "postedAt": "2026-09-18T14:22:01+00:00",
      "isPaidPartnership": false
    }
  ]
}
```

#### Data fields

| Field | Description |
|---|---|
| `username` / `fullName` | Handle and display name |
| `biography` | Profile bio text |
| `bioLinks` | External links from the bio — websites, shops, landing pages |
| `followerCount` | Threads followers (not Instagram followers) |
| `isVerified` / `isPrivate` | Account flags |
| `userId` | Stable numeric Threads user ID |
| `profilePicUrl` | Avatar image URL |
| `text` | Post body text |
| `likeCount` / `replyCount` / `repostCount` / `quoteCount` | Engagement |
| `postedAt` | ISO 8601 timestamp |
| `url` | Canonical post link |
| `author` / `authorId` / `authorIsVerified` | Post author |
| `isPaidPartnership` | Whether the post is marked as sponsored |
| `detectedLanguage` | Language when Threads reports one |
| `imageUrl` / `mediaType` / `altText` | Attached media |

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

Billing is **per result** — one profile, or one post from search, hashtag or post mode. Because compute runs on plain HTTP rather than a browser, cost per run is very low, and the Apify free tier includes enough monthly credit to try it and run small jobs.

**You are not charged for results your filters remove**, and you are not charged for profiles that do not exist. Filtering is applied before anything is written to the dataset.

### Tips

- **Set `minTextLength` to 80 for search and hashtags.** This is the single most effective setting. Junk posts run 3–30 characters; real content runs 150+.
- **Batch your inputs.** One run with 200 usernames is faster and cheaper than 200 runs.
- **Use `recent` sort** for monitoring and `top` for research.
- **Turn off `includePosts`** in profile mode when you only need follower counts.
- **Schedule runs** to build a follower-growth or keyword time series.

### FAQ

**Do I need a Threads or Instagram account?**
No. The Actor reads only publicly visible pages. There is no login step.

**How many posts do I get per profile?**
Threads shows roughly the **4–10 most recent posts** on a public profile page and then requires a login, so that is the ceiling for profile mode — for anyone, not just this Actor. Use search or hashtag mode for larger volumes, which return roughly 20–35 posts per query.

**Why did my search return fewer rows than I asked for?**
Either Threads served fewer public results, or your filters removed the rest. The run log prints both counts. Filtered rows are never charged.

**Can it scrape private profiles?**
No. Private profiles return metadata only, with no posts.

**Why is a post's `text` sometimes empty?**
Image- and video-only posts have no caption. Engagement counts are still returned.

### Legal and disclaimer

This Actor collects only **publicly available data** — what any visitor can see without logging in. It does not access private profiles, bypass authentication, or use logged-in sessions.

You are responsible for how you use the data, including compliance with GDPR, CCPA and other data-protection law, and with Meta's Terms of Service. If you process personal data, make sure you have a valid legal basis.

### Support

Found a bug, or need a field that is not returned yet? Open a ticket on the **Issues** tab and it will be looked at. Feature requests are welcome and genuinely shape what gets built next.

# Actor input Schema

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

Pick one. Each mode uses its own input field below.

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

Bare username (zuck), @handle, or full profile URL. One per entry.

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

Keywords or phrases to search Threads for.

## `hashtags` (type: `array`):

Tags to scrape, with or without the leading # symbol.

## `postUrls` (type: `array`):

Full Threads post links, e.g. https://www.threads.com/@zuck/post/ABC123.

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

Used by search mode. 'Top' favours engagement, 'Recent' favours freshness.

## `minLikes` (type: `integer`):

Drop posts below this like count. Threads search returns a lot of zero-engagement noise; filtered posts are removed BEFORE they reach your dataset, so you are never charged for them.

## `minTextLength` (type: `integer`):

Drop posts with less text than this. The single most effective noise filter - junk posts run 3-30 characters ('Pm ka', 'Inbox me') while real content runs 150+. Try 80 to start. Not charged for what is filtered.

## `excludeSpam` (type: `boolean`):

Remove posts matching common follow-for-follow / 'inbox me' / phone-number spam patterns. Deliberately conservative.

## `languages` (type: `array`):

Optional language codes (en, ja, es...). Note: Threads tags a language on only about 7% of posts, so this removes posts explicitly marked as another language and keeps untagged ones. Minimum text length is a far stronger filter.

## `includePosts` (type: `boolean`):

Return the profile's recent posts alongside its metadata. Turn off for a faster profile-only run.

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

Cap on posts attached to each profile. Note: Threads only renders roughly the 4-10 most recent posts on a public profile page, so raising this above ~10 will not return more.

## `maxResultsPerQuery` (type: `integer`):

Cap on posts returned per keyword, hashtag or post URL. Threads serves roughly 20-35 per public page.

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

Optional. Threads is reachable without a proxy, but one helps on very large runs.

## Actor input object example

```json
{
  "mode": "profile",
  "usernames": [
    "zuck",
    "mosseri"
  ],
  "searchQueries": [
    "digital marketing"
  ],
  "hashtags": [
    "ai",
    "startup"
  ],
  "searchSort": "top",
  "minLikes": 0,
  "minTextLength": 0,
  "excludeSpam": false,
  "includePosts": true,
  "maxPostsPerProfile": 25,
  "maxResultsPerQuery": 50,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (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": [
        "zuck",
        "mosseri"
    ],
    "searchQueries": [
        "digital marketing"
    ],
    "hashtags": [
        "ai",
        "startup"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("abdullahbilal-y/threads-profile-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": [
        "zuck",
        "mosseri",
    ],
    "searchQueries": ["digital marketing"],
    "hashtags": [
        "ai",
        "startup",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("abdullahbilal-y/threads-profile-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": [
    "zuck",
    "mosseri"
  ],
  "searchQueries": [
    "digital marketing"
  ],
  "hashtags": [
    "ai",
    "startup"
  ]
}' |
apify call abdullahbilal-y/threads-profile-scraper --silent --output-dataset

```

## MCP server setup

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