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

Scrape posts from any public Threads profile: full text, like/reply/repost/quote counts, media, and timestamps.

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

## Pricing

from $4.70 / 1,000 post returneds

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## Threads Posts Scraper: Every Post From Any Public Threads Profile

**Scrape posts from any public [Threads](https://www.threads.com) profile — full post text, engagement counts, media, and timestamps — with no login, no cookies, and no browser.**

---

**Simple Input-Output Example**

Input:
```json
{
  "usernames": ["natgeo"],
  "maxPostsPerProfile": 50
}
````

Output (one row per post):

```json
{
  "postId": "3942534943066968922",
  "code": "Da2sqRsElNa",
  "url": "https://www.threads.com/@natgeo/post/Da2sqRsElNa",
  "username": "natgeo",
  "fullName": "National Geographic",
  "userId": "63269174602",
  "isVerified": true,
  "profilePicture": "https://scontent.cdninstagram.com/v/natgeo-avatar.jpg",
  "text": "Find someone who's as excited for World Snake Day as this little garter snake.",
  "likes": 1093,
  "replies": 92,
  "reposts": 45,
  "quotes": 7,
  "media": {
    "type": "image",
    "imageUrl": "https://scontent.cdninstagram.com/v/garter-snake.jpg",
    "width": 1080,
    "height": 1350,
    "isCarousel": false,
    "carouselCount": 0,
    "altText": "A garter snake coiled on a mossy log"
  },
  "isQuote": false,
  "quotedPostCode": null,
  "createdAt": "2026-07-16T16:00:11+03:00",
  "createdAtUnix": 1784206811
}
```

**Important Notes:**

- Results come back **in seconds** — no login, no cookies, no browser automation
- **Pay per result — $0.00499 per post returned.** Failed and empty lookups are **never charged**
- **Public profiles only**, and **profile feeds only** — this Actor does **not** search Threads by keyword or hashtag
- Posts are returned **newest first**; `maxPostsPerProfile` controls how deep each profile goes (1–500)
- All data comes from **public sources** only
- Contact: contact@endspec.net

***

### Full Actor Documentation

#### Threads Posts Scraper

**Get every public post from any Threads account, as clean structured data.** Post text, like/reply/repost/quote counts, media details, author info, and exact publish timestamps — for one profile or a whole list of them.

***

#### Overview

The **Threads Posts Scraper** is an Apify Actor that scrapes posts from public profiles on [Threads](https://www.threads.com). Give it a list of Threads usernames or profile URLs and it walks each profile's feed newest-first, returning one clean row per post with the full text, all four engagement counters, media metadata, and timestamps.

It runs against a data service, not a browser — so there is no login step, no cookie handling, no proxy tuning, and no CAPTCHA to solve. You send usernames, you get rows.

**What this Actor does not do:** it does not search Threads by keyword, hashtag, or topic, and it does not read private profiles. It is a **profile-feed scraper**, deliberately and only. If you need keyword search across Threads, this is not the right tool.

##### What You Can Do

- **Scrape a Threads profile's full post feed**: newest first, up to 500 posts per profile per run
- **Capture complete post text**: the full body of each post, not a truncated preview
- **Measure engagement**: likes, replies, reposts, and quotes for every post
- **Collect media metadata**: media type (image / video / carousel), image URL, dimensions, carousel item count, and accessibility alt text
- **Identify quote posts**: know whether a post quotes another, and which post it quotes
- **Track multiple accounts in one run**: pass a list of usernames and get all their posts into a single dataset
- **Feed downstream systems**: export to JSON, CSV, or Excel from the Apify dataset, or pull it via the Apify API into your own pipeline

##### Data Availability

**All data returned by this Actor is publicly available information.** It only returns posts that account owners have published publicly on Threads — the same content any logged-out visitor can see on a public profile page. Private profiles cannot be retrieved. This Actor simply makes public post data easier to collect programmatically and at scale.

***

#### Actor Input Parameters

The Actor accepts the following input parameters:

**usernames**
• Type: array of strings
• Required: Yes (in practice — the run fails with no valid entry)
• Default: prefilled with `["natgeo"]` in the Apify console
• Description: Threads usernames or profile URLs to scrape. Each entry may be a bare handle, an `@handle`, or a full profile URL.
e.g., `["natgeo", "@zuck", "https://www.threads.com/@mosseri"]`

**maxPostsPerProfile**
• Type: integer
• Required: Optional
• Default: `50`
• Minimum: `1` — Maximum: `500`
• Description: Maximum number of posts to return for **each** profile in `usernames`. Posts are fetched newest first.
e.g., `100`

**Important Notes:**

- **At least one valid username is required** — the input schema marks nothing as strictly required, but a run with no usable entry in `usernames` fails immediately with `No valid Threads username or profile URL provided.` and returns no rows and no charges.
- **Three input formats, all equivalent** — `natgeo`, `@natgeo`, and `https://www.threads.com/@natgeo` all resolve to the same profile. `threads.net` URLs work too. Mix formats freely in one list.
- **Invalid entries are skipped, not fatal** — an entry that isn't a recognizable username or profile URL is dropped with a warning in the run log; the remaining profiles still run.
- **Duplicates are removed** — the same profile listed twice (in any format) is scraped once.
- **`maxPostsPerProfile` is per profile, not per run** — three profiles at `maxPostsPerProfile: 100` can return up to 300 posts, and you are billed for every post returned.
- **The cap is a ceiling, not a target** — a profile with 12 posts returns 12 posts, whatever the cap says.

***

#### Input Examples

##### Example 1: Single Profile, Default Depth

```json
{
  "usernames": ["natgeo"]
}
```

**When to use:** The simplest run. Returns up to 50 of `@natgeo`'s most recent posts (the default `maxPostsPerProfile`).

##### Example 2: Multiple Profiles, Mixed Input Formats

```json
{
  "usernames": [
    "natgeo",
    "@zuck",
    "https://www.threads.com/@mosseri"
  ],
  "maxPostsPerProfile": 100
}
```

**When to use:** Competitor or portfolio tracking across several accounts. All three formats are accepted and normalized to the same thing — you do not need to clean your list first.

##### Example 3: Shallow Probe of a Large List

```json
{
  "usernames": ["natgeo", "zuck", "mosseri", "threads", "instagram"],
  "maxPostsPerProfile": 10
}
```

**When to use:** Checking recent activity across many accounts cheaply, or test-driving the Actor before a big run. Low `maxPostsPerProfile` keeps both runtime and cost small.

##### Example 4: Deep Archive of One Profile

```json
{
  "usernames": ["natgeo"],
  "maxPostsPerProfile": 500
}
```

**When to use:** Backfilling a profile's post history with full engagement data. `500` is the hard maximum per profile per run.

##### Example 5: No Usable Input (Will Fail)

```json
{
  "usernames": []
}
```

**Result:** The run fails with `No valid Threads username or profile URL provided.` No rows are produced and nothing is charged. The same happens if every entry in the list is malformed.

***

#### Output Structure

The Actor pushes **one row per post** to the Apify dataset. Results can be downloaded as JSON, CSV, Excel, XML, or fetched via the Apify API. The dataset's **Overview** table view shows `username`, `text`, `likes`, `replies`, `reposts`, `quotes`, `createdAt`, and `url`; the full field set is always present in the raw data and in exports.

##### Successful Post Row Format

```json
{
  "postId": "string",
  "code": "string",
  "url": "string",
  "username": "string",
  "fullName": "string",
  "userId": "string",
  "isVerified": true,
  "profilePicture": "string",
  "text": "string",
  "likes": 0,
  "replies": 0,
  "reposts": 0,
  "quotes": 0,
  "media": null,
  "isQuote": false,
  "quotedPostCode": null,
  "createdAt": "string",
  "createdAtUnix": 0
}
```

**Field Descriptions:**

**postId**
• Type: string
• Description: Threads' numeric identifier for the post. Stable — use it as your deduplication key.

**code**
• Type: string
• Description: The post's short code, as it appears at the end of its Threads URL.

**url**
• Type: string
• Description: Direct link to the post on Threads.

**username**
• Type: string
• Description: Handle of the post's author (without `@`). Falls back to the username you supplied if the post carries no author record.

**fullName**
• Type: string | null
• Description: The author's display name.

**userId**
• Type: string | null
• Description: Threads' numeric identifier for the author.

**isVerified**
• Type: boolean | null
• Description: Whether the author's account carries a verification badge.

**profilePicture**
• Type: string | null
• Description: URL of the author's avatar image.

**text**
• Type: string | null
• Description: The full text of the post. `null` or empty for media-only posts.

**likes**
• Type: number | null
• Description: Like count at the time of scraping.

**replies**
• Type: number | null
• Description: Reply count at the time of scraping.

**reposts**
• Type: number | null
• Description: Repost count at the time of scraping.

**quotes**
• Type: number | null
• Description: Quote count at the time of scraping.

**media**
• Type: object | null
• Description: Media attached to the post, or `null` for text-only posts. When present, contains:

- `type` — one of `"image"`, `"video"`, or `"carousel"`
- `imageUrl` — direct URL to the post's image (for video and carousel posts, the cover image)
- `width` / `height` — pixel dimensions of that image
- `isCarousel` — boolean; true for multi-item posts
- `carouselCount` — number of items in the carousel (`0` when not a carousel)
- `altText` — the accessibility caption, when the author or platform supplied one

**isQuote**
• Type: boolean
• Description: `true` when this post quotes another post.

**quotedPostCode**
• Type: string | null
• Description: The short code of the quoted post, when `isQuote` is `true`.

**createdAt**
• Type: string | null
• Description: Publish time as an ISO 8601 timestamp.

**createdAtUnix**
• Type: number | null
• Description: Publish time as a Unix timestamp, for easy sorting and filtering.

##### Error and Empty-Result Row Format

Rows that are **not** posts carry a `status` field. Successful post rows have **no** `status` field — testing for the presence of `status` is the reliable way to separate posts from problems:

```json
{
  "status": "error",
  "username": "string",
  "error": "string"
}
```

**status**
• Type: string
• Description: Always `"error"` on these rows.

**username**
• Type: string
• Description: The normalized username the row refers to, so you can tell which profile in your list had the problem.

**error**
• Type: string
• Description: One of exactly four messages (see the examples below). Every one of them ends with **"You were not charged."** — because you were not.

***

#### Output Examples

##### Example 1: Image Post With Full Engagement Data

```json
{
  "postId": "3942534943066968922",
  "code": "Da2sqRsElNa",
  "url": "https://www.threads.com/@natgeo/post/Da2sqRsElNa",
  "username": "natgeo",
  "fullName": "National Geographic",
  "userId": "63269174602",
  "isVerified": true,
  "profilePicture": "https://scontent.cdninstagram.com/v/natgeo-avatar.jpg",
  "text": "Find someone who's as excited for World Snake Day as this little garter snake.",
  "likes": 1093,
  "replies": 92,
  "reposts": 45,
  "quotes": 7,
  "media": {
    "type": "image",
    "imageUrl": "https://scontent.cdninstagram.com/v/garter-snake.jpg",
    "width": 1080,
    "height": 1350,
    "isCarousel": false,
    "carouselCount": 0,
    "altText": "A garter snake coiled on a mossy log"
  },
  "isQuote": false,
  "quotedPostCode": null,
  "createdAt": "2026-07-16T16:00:11+03:00",
  "createdAtUnix": 1784206811
}
```

##### Example 2: Text-Only Post That Quotes Another Post

Text-only posts return `media: null`. Nothing is missing — there is simply no media on the post.

```json
{
  "postId": "3942534943066968923",
  "code": "Da2sqRsElNb",
  "url": "https://www.threads.com/@natgeo/post/Da2sqRsElNb",
  "username": "natgeo",
  "fullName": "National Geographic",
  "userId": "63269174602",
  "isVerified": true,
  "profilePicture": "https://scontent.cdninstagram.com/v/natgeo-avatar.jpg",
  "text": "This is the part everyone gets wrong about snake season.",
  "likes": 141,
  "replies": 12,
  "reposts": 3,
  "quotes": 1,
  "media": null,
  "isQuote": true,
  "quotedPostCode": "DadRSwPoMbB",
  "createdAt": "2026-07-15T12:13:31+03:00",
  "createdAtUnix": 1784106811
}
```

##### Example 3: Carousel Post With Partial Author Data

Not every field is populated on every post. Missing values come back as `null` rather than being dropped, so your schema stays stable.

```json
{
  "postId": "3942534943066968931",
  "code": "Da2sqRsElNc",
  "url": "https://www.threads.com/@smallshop/post/Da2sqRsElNc",
  "username": "smallshop",
  "fullName": null,
  "userId": "71422900135",
  "isVerified": false,
  "profilePicture": null,
  "text": "Three new colorways, live now.",
  "likes": 18,
  "replies": 2,
  "reposts": 0,
  "quotes": 0,
  "media": {
    "type": "carousel",
    "imageUrl": "https://scontent.cdninstagram.com/v/colorway-1.jpg",
    "width": 1080,
    "height": 1080,
    "isCarousel": true,
    "carouselCount": 3,
    "altText": null
  },
  "isQuote": false,
  "quotedPostCode": null,
  "createdAt": "2026-07-14T09:02:44+03:00",
  "createdAtUnix": 1783929764
}
```

##### Example 4: Profile Found, But No Posts (Empty Result)

The profile resolved, but its feed returned nothing — an account that has never posted, or one whose posts are not publicly visible.

```json
{
  "status": "error",
  "username": "emptyaccount",
  "error": "No posts were found for this profile. You were not charged."
}
```

##### Example 5: Profile Could Not Be Retrieved

Emitted when the profile cannot be resolved — a typo, a handle that no longer exists, a private account, or an intermittent lookup failure. Retrying is worthwhile: see the FAQ.

```json
{
  "status": "error",
  "username": "no_such_handle_here",
  "error": "This profile could not be retrieved. Check that the username is correct and the profile is public, then retry. You were not charged."
}
```

##### Example 6: Temporarily Rate Limited

```json
{
  "status": "error",
  "username": "natgeo",
  "error": "Our servers are busy right now — please retry shortly. You were not charged."
}
```

##### Example 7: Unexpected Failure

```json
{
  "status": "error",
  "username": "natgeo",
  "error": "Something went wrong on our side. You were not charged."
}
```

**Those four `error` strings are the complete set.** The Actor never emits anything else in that field — no raw technical errors, no stack traces, no partial internal detail. If you see one of these, it means what it says, and no charge was made for it.

***

#### Use Cases

##### For Social Media Marketers and Brand Teams

**Competitive and brand monitoring:** Track what competitor accounts publish on Threads, how often, and what actually lands. The four engagement counters on every post let you rank content by real performance rather than gut feel.

**Example Workflow:**

1. List your competitors' Threads handles in `usernames`
2. Set `maxPostsPerProfile` to cover your reporting window (e.g. `100`)
3. Schedule the Actor to run daily or weekly in the Apify console
4. Export the dataset to CSV or push it to your BI tool
5. Sort by `likes` and `replies` to see which themes outperform, and by `createdAt` to see cadence

##### For Analysts and Researchers

**Engagement benchmarking:** Build a baseline for what "good" looks like in your category. Because every post carries `likes`, `replies`, `reposts`, `quotes`, and `createdAtUnix`, you can compute engagement rates, posting frequency, and time-of-day effects across any set of accounts.

**Example Workflow:**

1. Assemble a cohort of accounts in the same category
2. Run the Actor at `maxPostsPerProfile: 500` to backfill history
3. Group rows by `username` and bucket `createdAtUnix` by week
4. Compare median engagement per post across the cohort
5. Re-run periodically and append to track drift over time

##### For Businesses and Content Teams

**Content research and repurposing:** Find which of your own Threads posts performed best, and mine adjacent accounts for format ideas — carousels vs. single images vs. text-only is directly visible in the `media` field.

**Example Workflow:**

1. Scrape your own profile plus three accounts you admire
2. Split rows by `media.type` (`image`, `video`, `carousel`, or `null` for text-only)
3. Compare average engagement per media type
4. Rebuild your content calendar around the formats that actually win

##### For Developers and Data Teams

**Pipeline integration:** Pull Threads content into a warehouse, a social listening product, or an LLM pipeline. The output shape is fixed and every field is documented, so it maps cleanly onto a table.

**Example Workflow:**

1. Call the Actor via the Apify API or a scheduled task
2. Use the presence of `status` to route error rows away from post rows
3. Deduplicate against your store using `postId`
4. Load `text` into your embedding or classification pipeline
5. Keep `likes` / `replies` / `reposts` / `quotes` as time-series snapshots per scrape

***

#### Best Practices

##### Input

- **Don't pre-clean your list** — bare handles, `@handles`, and profile URLs all work, and duplicates are removed for you
- **Start small** — do a `maxPostsPerProfile: 10` test run against your list before launching a 500-per-profile job
- **Remember the cap multiplies** — `maxPostsPerProfile` applies to every profile, so a 20-profile list at `500` can return up to 10,000 billable posts
- **Batch sensibly** — profiles are processed one after another, so very large lists mean longer runs; split them across several runs or scheduled tasks

##### Error Handling

- **Test for `status`, not for success** — post rows have no `status` field; anything carrying `status: "error"` is a problem row, not a post
- **Retry a "profile could not be retrieved"** — profile lookups can fail intermittently even for accounts that exist. The Actor already retries internally before giving up, but a fresh run on that single handle is often enough to get it
- **Treat "our servers are busy" as transient** — wait a little and re-run just the affected profiles
- **If *every* profile in a run comes back busy or failed, contact us** — a whole run failing is not normal and is worth a support ticket
- **Log the Apify run ID** — include it when you contact support

##### Data Usage

- **Deduplicate on `postId`** — it is stable across runs; `code` and `url` are fine for humans but `postId` is the key
- **Snapshot, don't assume** — engagement counts are true at the moment of scraping and keep moving; store them with a scrape timestamp if you care about trends
- **Sort with `createdAtUnix`** — it is the least ambiguous of the two timestamps for programmatic use
- **Respect privacy and platform terms** — use public post data for legitimate business purposes only

***

#### Cost, Performance, and Limits

##### Billing

- **You pay per post returned** — the Actor charges a single event, `post-returned`, once for each post row it delivers. **$0.00499 per post.**
- **Errors and empty results are free** — every `status: "error"` row is unbilled, which is why each of those messages ends in "You were not charged."
- **Failed profiles don't poison the run** — in a multi-profile run you pay for the posts you actually received, and nothing for the profiles that failed
- **Partial results are billed as delivered** — if a profile returns some posts and then the feed stops early, you keep and pay for the posts you got, and no error row is added for that profile

##### Performance

- **Fast, and no browser** — this is a data-service Actor, not a headless-browser scraper. Runs finish in seconds to a couple of minutes depending on how many posts you ask for.
- **Posts arrive in pages** — the feed is paginated behind the scenes and rows stream into the dataset as pages come in
- **Retries are built in** — profile resolution and page fetches are retried automatically with backoff before any error row is emitted, so ordinary transient hiccups never reach you

##### Limits

- **Profile feeds only.** There is no keyword, hashtag, or topic search in this Actor. It cannot answer "who mentioned my brand on Threads" — only "what did this account post".
- **Public profiles only.** Private accounts return `This profile could not be retrieved...`
- **500 posts per profile per run** is the hard maximum; the default is 50. For deeper history, that ceiling is the ceiling.
- **Newest first, no date filter.** You control depth with `maxPostsPerProfile`; you cannot request a specific date range. Filter on `createdAt` / `createdAtUnix` after the fact.
- **Media metadata, not media files.** You get the media type, cover image URL, dimensions, and alt text — not a downloadable video file.
- **Engagement counts are point-in-time**, captured when the run happens.

***

#### Data Sources and Legality

**All data returned by this Actor is publicly available information published on [Threads](https://www.threads.com).** It returns only posts that account owners have chosen to make public — the same content visible to any member of the public viewing that profile. No private profiles, no logged-in-only content, no personal data behind an access control.

**Your responsibility:** You are responsible for complying with all applicable laws and regulations, and with the terms of service of any platform whose public data you collect. That includes GDPR, CCPA, and any local rules that apply to you when personal data is involved. Scraping publicly available data is generally lawful in many jurisdictions, but how you store, process, and use it is on you.

**Practical guidance:**

- Use collected post data for legitimate purposes such as research, analytics, and competitive intelligence
- Do not republish scraped content in ways that infringe the author's rights
- Honor removal requests from individuals whose public posts you have stored
- If in doubt about a specific use case, take legal advice — this section is information, not a legal guarantee

***

#### FAQ

**Q: Can I search Threads for a keyword, hashtag, or topic?**
A: No. This Actor scrapes profile feeds only. You give it accounts; it gives you those accounts' posts. It cannot search Threads for mentions of a term.

**Q: Can it scrape private profiles?**
A: No. Only publicly visible profiles can be retrieved. A private account returns `This profile could not be retrieved. Check that the username is correct and the profile is public, then retry. You were not charged.`

**Q: I got "This profile could not be retrieved" for an account I know exists. Why?**
A: Profile lookups are occasionally flaky — the same handle can fail on one attempt and succeed on the next. The Actor already retries several times with backoff before giving up, so this is uncommon, but it happens. First check the spelling and that the profile is public; if both are fine, just run that handle again.

**Q: Am I charged for profiles that fail or return nothing?**
A: No. You are charged only for posts actually delivered to your dataset. Every error row says so explicitly.

**Q: What input formats does `usernames` accept?**
A: Bare handles (`natgeo`), `@handles` (`@natgeo`), and full profile URLs (`https://www.threads.com/@natgeo`, and `threads.net` URLs too). You can mix all three in one list.

**Q: How many posts can I get from one profile?**
A: Up to 500 per profile per run, set via `maxPostsPerProfile`. The default is 50. Live checks have paginated well past 80 posts on a single profile without failures.

**Q: How fresh is the data?**
A: It reflects the profile's live public feed at the moment of the run — in our checks, the newest post in a feed was less than a day old. Engagement counts are equally a snapshot of that moment.

**Q: Does it download images or videos?**
A: It returns media *metadata* — type, cover image URL, dimensions, carousel item count, and alt text. It does not return downloadable video files.

**Q: How do I tell post rows apart from error rows in my code?**
A: Post rows have no `status` field. Error rows always have `status: "error"`. Check for the presence of `status`.

**Q: Can I scrape several profiles in one run?**
A: Yes — that is what `usernames` is for. Note that `maxPostsPerProfile` applies to each profile separately, and you are billed per post returned across all of them.

**Q: What formats can I export?**
A: Anything the Apify dataset supports — JSON, CSV, Excel, XML — via the console or the Apify API.

**Q: Can I run this on a schedule?**
A: Yes. Use Apify's scheduling to run it daily or weekly and append to your own store, deduplicating on `postId`.

***

#### Contact & Support

**Questions? Need help? We're here for you.**

For questions, technical support, feature requests, or anything else about the Threads Posts Scraper, reach out:

**Email:** contact@endspec.net

**Response Time:** We respond within 24 hours on business days.

**What to include in your message:**

- A description of the question or issue
- Your Apify run ID, if applicable
- The input you used
- Any `error` message or `status` value you received

You can also report issues through the **Issues** tab on this Actor's Apify page. We're committed to helping you get the most out of this Actor — whether you're integrating it into a pipeline, troubleshooting a run, or figuring out whether it fits your use case.

***

#### Related Actors

- [Instagram Instant Media Scraper](https://apify.com/endspec/instagram-instant-media-scraper) – scrape media and post data from public Instagram profiles.
- [YouTube Instant Email Scraper](https://apify.com/endspec/youtube-instant-email-scraper) – find publicly listed contact emails for YouTube channels.
- [LinkedIn Instant Profile Search](https://apify.com/endspec/linkedin-instant-profile-search) – search LinkedIn profiles by name, job title, or company.

***

*Last updated: July 2026*

# Actor input Schema

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

Threads usernames or profile URLs to scrape. Accepts 'natgeo', '@natgeo', or 'https://www.threads.com/@natgeo'.

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

Maximum posts to return for each profile. Posts are fetched newest first.

## Actor input object example

```json
{
  "usernames": [
    "natgeo"
  ],
  "maxPostsPerProfile": 50
}
```

# Actor output Schema

## `dataset` (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": [
        "natgeo"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("endspec/threads-instant-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 = { "usernames": ["natgeo"] }

# Run the Actor and wait for it to finish
run = client.actor("endspec/threads-instant-posts-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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": [
    "natgeo"
  ]
}' |
apify call endspec/threads-instant-posts-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=endspec/threads-instant-posts-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Threads Posts Scraper",
        "description": "Scrape posts from any public Threads profile: full text, like/reply/repost/quote counts, media, and timestamps.",
        "version": "0.1",
        "x-build-id": "rDep6u3CLnHqfAAP7"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/endspec~threads-instant-posts-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-endspec-threads-instant-posts-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/endspec~threads-instant-posts-scraper/runs": {
            "post": {
                "operationId": "runs-sync-endspec-threads-instant-posts-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/endspec~threads-instant-posts-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-endspec-threads-instant-posts-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "usernames": {
                        "title": "Threads Profiles",
                        "type": "array",
                        "description": "Threads usernames or profile URLs to scrape. Accepts 'natgeo', '@natgeo', or 'https://www.threads.com/@natgeo'.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxPostsPerProfile": {
                        "title": "Max Posts Per Profile",
                        "minimum": 1,
                        "maximum": 500,
                        "type": "integer",
                        "description": "Maximum posts to return for each profile. Posts are fetched newest first.",
                        "default": 50
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
