# Threads Scraper – Profiles, Posts & Replies, No Login (`nourishing_courier/threads-scraper`) Actor

Scrape Meta Threads profiles, posts and replies without logging in. Followers, bio, post text, likes, replies, reposts, quotes, media URLs, link previews and dates as flat JSON/CSV rows. Handles, profile URLs, post URLs, keywords and tags. Pay only for delivered rows.

- **URL**: https://apify.com/nourishing\_courier/threads-scraper.md
- **Developed by:** [Ani Björkström](https://apify.com/nourishing_courier) (community)
- **Categories:** Social media, AI, Lead generation
- **Stats:** 2 total users, 1 monthly users, 50.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.50 / 1,000 profile, post or reply delivereds

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, Posts & Replies, No Login

Scrape **Meta Threads** without logging in: paste handles, profile URLs, post URLs, keywords or #tags and get **profiles, posts and replies as flat JSON / CSV rows** – follower counts, bio, post text, likes, replies, reposts, quotes, media URLs, link previews and timestamps. No Threads API access, no cookies, no browser, no proxy needed for normal volumes.

Threads has no public read API for third parties, so this Threads scraper reads the same public data any logged-out visitor sees on threads.com and turns it into clean rows for **social listening, influencer research, brand monitoring, competitor analysis and AI pipelines**. You pay only for delivered rows.

### What you get

Every row has a `type`: `profile`, `post`, `reply` or `error`.

**Profile rows**

| Field | Description |
|---|---|
| `userId`, `username`, `fullName` | Account identity |
| `bio`, `externalUrl` | Biography and the first link in bio |
| `followers` | Follower count as an integer |
| `isVerified`, `isPrivate` | Verification and privacy flags |
| `profilePicUrl`, `url` | Highest-resolution avatar and profile URL |

**Post and reply rows**

| Field | Description |
|---|---|
| `id`, `code`, `url` | Post id, short code and canonical URL |
| `username`, `userId`, `authorName`, `authorIsVerified` | Author |
| `text` | Full post text |
| `likes`, `replies`, `reposts`, `quotes`, `reshares` | Engagement counters |
| `postedAt` | ISO 8601 UTC timestamp |
| `mediaType`, `images`, `videos` | `text`, `image`, `video` or `carousel`, plus direct media URLs |
| `linkPreviewUrl`, `linkPreviewTitle` | Attached link card |
| `quotedPostUrl`, `repostOf` | Quote and repost targets |
| `isReply`, `replyToUsername`, `parentPostUrl` | Reply context |
| `lang`, `isEdited`, `isPaidPartnership` | Language and flags |
| `source`, `sourceKey` | Which input (profile, post, search) produced the row |
| `scrapedAt` | When the row was collected |

Failed targets produce one `error` row explaining why (private account, deleted post, unknown handle, throttling) and are never charged.

### Input

```json
{
  "profiles": ["zuck", "@meta", "https://www.threads.com/@nasa"],
  "postUrls": ["https://www.threads.com/@zuck/post/DdZ7sQvkTFn"],
  "searchQueries": ["ai agents", "#photography"],
  "maxPostsPerProfile": 100,
  "includeReplies": true,
  "maxRepliesPerPost": 50
}
```

- **Profiles** – handles or profile URLs. Each gives one profile row plus that account's latest posts (newest first) up to **Maximum posts per profile**. Threads serves 25 per page; the actor pages through the profile's Threads tab for you.
- **Post URLs** – individual posts. Each gives the post row and, with **Include replies**, the replies under it (top replies first, 25 per page, up to **Maximum replies per post**).
- **Keywords or #tags** – the first page of Threads search or tag results, about 15–20 posts per query. Logged-out visitors cannot page further, so treat search as discovery, not an archive.
- **Profile info only** – return just the profile rows (fastest way to monitor follower counts of many accounts).
- **Parallel targets** – 2 is safe from one IP; Meta throttles bursts. Use the **Proxy** option (residential) for hundreds of profiles or thousands of replies.

Fill nothing at all and the actor scrapes two demo profiles so you can see the output shape.

### How it works

Threads renders its Relay data into the HTML of every public page. The actor requests pages the way a browser navigation does, parses those payloads, and uses the same public GraphQL pagination the web client uses (persisted-query ids are discovered automatically from Meta's JavaScript bundles when they rotate). No login, no cookies from a real account, no Instagram credentials – nothing that can get an account banned.

### Use cases

- **Social listening & brand monitoring** – track what people post about your brand, product or competitors on Threads and alert your team in Slack.
- **Influencer research** – pull follower counts, bio links and recent engagement for a list of creators and rank them by average likes.
- **Competitor content analysis** – scrape a competitor's last 200 posts and see which formats (text, image, video, carousel) earn the most replies and reposts.
- **Lead generation** – bios and external links of accounts in a niche give agencies and B2B teams a warm outreach list.
- **Trend & market research** – hashtag and keyword pages show what is being said right now.
- **AI agents, LLM and RAG pipelines** – flat rows with text, timestamps and engagement drop straight into an embedding or summarisation pipeline; the actor is available through Apify's MCP server.
- **Academic research** – collect public discourse with clean metadata and reproducible inputs.

### Pricing

Pay per delivered row (`item` event): profile, post and reply rows count, error rows are free. No subscription, no minimum, no actor-start fee. A profile with 100 posts is 101 rows.

### Integrations

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("nourishing_courier/threads-scraper").call(run_input={
    "profiles": ["zuck", "nasa"],
    "maxPostsPerProfile": 50,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row["type"] == "post":
        print(row["postedAt"], row["likes"], row["text"][:80])
```

JavaScript:

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

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('nourishing_courier/threads-scraper').call({
  searchQueries: ['#fintech'],
  includeReplies: false,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

curl:

```bash
curl -X POST "https://api.apify.com/v2/acts/nourishing_courier~threads-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"profiles":["zuck"],"maxPostsPerProfile":10}'
```

Works with **n8n, Make and Zapier** through their Apify nodes, exports to Google Sheets, Airtable, CSV, Excel and JSON, and can be scheduled inside Apify for daily monitoring.

### Limits and fair use

- Public accounts and public posts only. Private accounts return an `error` row.
- Search and tag results are limited to the first page for logged-out visitors (about 15–20 posts).
- Meta rate-limits aggressive traffic from a single IP. The actor paces requests, rotates browser signatures and backs off on throttling; for very large runs enable a residential proxy.
- Meta changes its web client regularly. The parser scans the embedded data by shape rather than one fixed path, and pagination ids are rediscovered automatically, but a redesign can still cause temporary gaps – error rows will say so.
- You are responsible for complying with Meta's terms and applicable law (including GDPR) in how you use the data. This actor is a research and monitoring tool.

### FAQ

#### Can I scrape Threads without logging in?

Yes. This scraper never logs in and needs no Instagram or Threads account. It only reads what a logged-out visitor can see.

#### Is there a Threads API I can use instead?

Meta's official Threads API only covers your own account's content and publishing. For competitors, creators or hashtags you need a scraper like this one.

#### How many posts can I get per profile?

As many as the profile has, up to your `maxPostsPerProfile` cap (default 25, maximum 5,000). Pagination is automatic, 25 posts per page.

#### Does it collect replies?

Yes. Turn on **Include replies** to collect the replies under each post, top replies first, up to `maxRepliesPerPost`.

#### Can I search Threads by keyword or hashtag?

Yes, via **Keywords or #tags**. You get the first page of results (about 15–20 posts) per query, which is what Threads shows logged-out visitors.

#### Can I export Threads posts to CSV or Google Sheets?

Every run's dataset downloads as CSV, Excel, JSON or XML, and the Apify Google Sheets integration pushes it to a spreadsheet automatically.

#### Does it work with n8n, Make or Zapier?

Yes. All three have Apify integrations: start the run, wait for it to finish, read the dataset.

#### Is scraping Threads legal?

Scraping publicly available data is generally lawful, but you are responsible for how you use it and for complying with Meta's terms and privacy law in your jurisdiction.

#### What happens if a handle does not exist?

You get one `error` row for that target and the rest of the run continues. Error rows are not charged.

# Actor input Schema

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

Threads handles or profile URLs, one per line: zuck, @meta, https://www.threads.com/@nasa. Each gives one profile row plus that account's latest posts.

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

Optional. Individual post URLs such as https://www.threads.com/@zuck/post/DdZ7sQvkTFn. Each gives the post itself (and its replies when 'Include replies' is on). If you fill only this field, the demo profiles above are skipped.

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

Optional. Keywords ("ai agents") or hashtags ("#photography") - the first page of Threads search / tag results, about 15-20 posts per query. Threads does not let logged-out visitors page further, so this is a discovery feature, not a full archive.

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

How many posts to collect from each profile (newest first). Threads serves 25 per page, so 100 posts is 4 extra requests. Also caps the number of posts kept per keyword/tag search.

## `includeReplies` (type: `boolean`):

Also collect the replies under each post (top replies first). Costs one extra page load per post, so keep 'Maximum posts per profile' modest when this is on.

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

Cap for replies collected under each post when 'Include replies' is on. Threads serves 25 per page.

## `scrapeProfileOnly` (type: `boolean`):

Return just the profile row (followers, bio, verification, links) and skip the posts entirely. Fastest and cheapest way to monitor follower counts.

## `concurrency` (type: `integer`):

How many profiles/posts/searches to work on at once. Meta rate-limits aggressively; 2 is safe from one IP, go higher only with a proxy.

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

Optional. Not needed for a handful of profiles. For large runs (hundreds of profiles or thousands of replies) a residential proxy avoids Meta's per-IP throttling.

## Actor input object example

```json
{
  "profiles": [
    "zuck",
    "meta"
  ],
  "maxPostsPerProfile": 25,
  "includeReplies": false,
  "maxRepliesPerPost": 25,
  "scrapeProfileOnly": false,
  "concurrency": 2,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `items` (type: `string`):

Every profile, post and reply row with engagement counts, media URLs and dates.

## `itemsCsv` (type: `string`):

The same rows as a spreadsheet-ready CSV file.

## `consoleView` (type: `string`):

Open the run's dataset in Apify Console.

# 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",
        "meta"
    ]
};

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

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

```

## MCP server setup

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