# Threads (/docs/threads) Threads [#threads] Meta's Threads, behind the unified SocialCrawl envelope: profiles, a user's posts, one post's detail, the replies on a post, keyword search over public posts, and user search. Every endpoint is a `GET`, every one costs **1 credit**, and posts come back as the same canonical `Post` object you get from TikTok or Instagram, so one parser covers all three. Base URL: `/v1/threads/...` Getting Started [#getting-started] 1\. Fetch a profile [#1-fetch-a-profile] ```bash curl "https://www.socialcrawl.dev/v1/threads/profile?handle=zuck" \ -H "x-api-key: sc_your_api_key_here" ``` 2\. Fetch their content [#2-fetch-their-content] ```bash curl "https://www.socialcrawl.dev/v1/threads/user/posts?handle=zuck" \ -H "x-api-key: sc_your_api_key_here" ``` 3\. Read computed fields [#3-read-computed-fields] When an endpoint supports a computed field and the required source inputs are present, the unified response includes that optional field. Depending on the endpoint, optional fields can include `engagement_rate`, `language`, `content_category`, and `estimated_reach`. See [Computed fields](/docs/computed-fields.md) for formulas, clamping rules, and null semantics. What you can get [#what-you-can-get] * **Profiles** — `GET /v1/threads/profile` takes a `handle` (no `@`) and returns followers, bio, avatar, and verification. The external website a user sets in their bio comes back at `author.ext.bio_link`, `null` when they have not set one. * **A user's posts** — `GET /v1/threads/user/posts` returns roughly 15 recent posts for a handle. There is no cursor on this one (see below). * **One post** — `GET /v1/threads/post` takes the post `url` and returns the full detail object. * **Replies on a post** — `GET /v1/threads/post/comments` takes the same `url` and returns the reply window Threads bundles with the post, typically about 20 replies, each with text, like count, direct reply count, author handle, display name, avatar, verification, pinned flag, and timestamp. * **Keyword search** — `GET /v1/threads/search` takes a `query` and returns matching public posts. This is the endpoint with the most behaviour to understand; the next two sections are about it. * **User search** — `GET /v1/threads/search/users` takes a `query` and returns matching accounts with follower counts and verification. Search returns one window, not a page [#search-returns-one-window-not-a-page] `GET /v1/threads/search` returns a single result window — typically 15 to 20 posts. Threads gives the upstream no cursor at all; its only paging lever is the date filter. So the endpoint synthesises pagination for you, and you have two ways to go deeper: * **Send the cursor back.** Pass `pagination.next_cursor` from the previous response as `cursor` to get the next (older) window. One window, 1 credit. * **Ask for a count and let the API walk.** Set `limit` (1-100) and the API re-queries shrinking date windows server-side, de-duplicates by post id, and returns up to that many unique posts in one call. It bills **1 credit per window consumed** (about 15-20 posts each) and refunds the unused window budget, so a `limit=100` call that runs dry after three windows costs 3 credits, not 7. `start_date` and `end_date` (both `YYYY-MM-DD`, inclusive) bound the search to a period. The walk starts at `end_date` and works backwards, and never crosses `start_date` — which makes the pair the right way to page a fixed period without runaway cost. ```bash # One window, cheapest possible probe curl "https://www.socialcrawl.dev/v1/threads/search?query=artificial%20intelligence" \ -H "x-api-key: sc_your_api_key_here" # Collect up to 60 unique posts from a bounded period in one call curl "https://www.socialcrawl.dev/v1/threads/search?query=artificial%20intelligence&limit=60&start_date=2026-07-01&end_date=2026-07-31" \ -H "x-api-key: sc_your_api_key_here" ``` **Threads search is a sampled window, not an index, and it is nondeterministic run to run.** Running the identical query three times in a row on 2026-08-09 returned 20 posts each time and matched itself at only **0.693 Jaccard** — 26 unique posts across the three runs. This is upstream behaviour and every Threads provider has it. A second run that returns a slightly different set is not data loss, and comparing two vendors on a single query measures the sampling, not the coverage. If you need a stable set, collect with `limit` over a bounded `start_date` / `end_date` window and de-duplicate on post id your side. Topic tags [#topic-tags] Posts filed under a Threads topic tag carry the tag name at `post.ext.topic_tag` (values look like `bali` or `dokter gigi`) with its stable id at `post.ext.topic_tag_id`. Both fields are present on `search`, `user/posts`, and `post`. Two things to plan around. Both fields are **absent on untagged posts, which are the majority** — treat them as optional, never assume they exist. And **Threads exposes no tags-only search mode upstream**, so there is no way to ask for "every post under `bali`". The supported pattern is to run a keyword search and group or filter the results by `topic_tag` client-side. Replies come as one window [#replies-come-as-one-window] `GET /v1/threads/post/comments` is the same upstream call as `GET /v1/threads/post` — one request returns the post and the replies bundled with it, and the two endpoints just pick different halves. A post and its replies therefore cost one credit each, and there is no way to save by combining them. That bundling has consequences worth knowing before you build on it: * It is **one window with no cursor**, so there is no way to page deeper into a long conversation. Roughly 20 replies is what exists. * `comment.url` is constructed from the reply's shortcode and its author handle, because the upstream sends no permalink on reply items. * `comment.post_id` and `comment.parent_id` are **`null`** for the same reason — the upstream surfaces neither id on a reply. If you need to attach a reply to its parent post, carry the post url through yourself. ```bash curl "https://www.socialcrawl.dev/v1/threads/post/comments?url=https://www.threads.com/@zuck/post/DZpPDXbCeTt" \ -H "x-api-key: sc_your_api_key_here" ``` A user's posts do not paginate [#a-users-posts-do-not-paginate] `GET /v1/threads/user/posts` returns one fixed window of about 15 recent posts and the upstream offers no cursor. For deeper history on a specific account, run `GET /v1/threads/search` with the handle or a distinctive phrase and a date window, or reach for [`/v1/search/everywhere`](/docs/search/everywhere.md), which includes Threads as a source. Endpoints [#endpoints] Notes [#notes] * All endpoints use `GET` method with query parameters * Authentication via `x-api-key` header * Responses follow the unified SocialCrawl schema * Carousel posts return every slide as an array in `post.content.media_urls`; video posts return a playable video URL there, with the cover frame in `post.content.thumbnail_url` * `trim=true` on `user/posts`, `post`, `post/comments`, and `search` returns a lighter payload at the same price — useful when you only need text and counts * A Threads profile only exists if the account opted in. Many well-known Instagram usernames have no Threads account, so a `404` is a genuine "no such profile" rather than an error