Threads Keyword Search: 75% On-Topic for 1 Credit
Live 2026-09-08: cari ai automation returned 20 posts, 75% multi-term hits, 1 credit (was 3). Pair-only expansion; expand=false stayed empty and free.
A Threads keyword search on an unknown three-word phrase now stays on the words you typed. Live 2026-09-08 UTC, GET /v1/threads/search?query=cari+ai+automation returned 20 posts, 15/20 (75%) whole-word multi-term hits, 1 credit (cache-cold, 5,604 ms client wall-clock). The warning named two adjacent pairs (cari ai, ai automation); 1 of 2 returned posts. Same query with expand=false: 0 posts, 0 credits.
Ship note 07/09/2026 on that query: 59 posts / 25% multi-term / 3 credits, then 20 / 75% / 1 credit. Live matches the after. We did not re-measure the before.
Official meta threads search is GET graph.threads.net/v1.0/keyword_search — 2,200 queries per rolling 24 hours, App Review required. This post is the public-read envelope on the SocialCrawl API — matching behaviour Meta never documents. For OAuth and App Review, see Threads API in 2026. This is not the comments, carousel, or yield tour — that threads search api post lives at Scrape Threads.
Stack: curl · Python requests · GET https://www.socialcrawl.dev/v1/threads/search · header x-api-key. Print len(items) and credits_used. Free plan: 100 credits, no card. Catalogue: /docs/threads · /platforms/threads. Five live envelopes billed 4 credits (1 + 0 + 1 + 1 + 1). Pair-only expansion, exact-phrase opt-out, unsplit known phrases, and a short-term word-boundary check.
How does pair expansion change Threads keyword search results?
Threads does not score your query like a search index. It matches against topic tags it already knows. An unrecognised phrase used to come back empty — or, on the pre-07/09 default path, fall back to single words and fill the page with whatever those tokens happened to hit. The threads keyword search api is still GET /v1/threads/search. What changed is the fallback: an unknown phrase now expands into adjacent word pairs only — 1 credit per pair that returned posts — and the merge ranks by how many of your terms each caption still carries.
curl -s -H "x-api-key: $SOCIALCRAWL_API_KEY" \
"https://www.socialcrawl.dev/v1/threads/search?query=cari%20ai%20automation"Live (req-B1nKGNBEA20fk0U2, HTTP 200, cached: false, 5,604 ms): 20 posts, 1 credit, pagination.has_more=false, no pagination.next_cursor. Expanded pages do not paginate. The warning, verbatim:
No Threads post matched "cari ai automation" as a phrase, so the query was expanded into 2 narrower searches (cari ai, ai automation) and 1 of them returned posts. Results are merged, de-duplicated and ordered by how many of your terms each post contains. You are billed 1 credit per search that returned posts, and an expanded response is a single page with no pagination cursor. Send expand=false to search the exact phrase only.
| Ship note 07/09/2026 (before → after) | Live 08/09/2026 | |
|---|---|---|
| Posts | 59 → 20 | 20 |
| Multi-term (≥2 of cari / ai / automation in caption) | 15 → 15 (25% → 75%) | 15 / 20 = 75% |
| Credits | 3 → 1 | 1 |
| Relaxed searches | up to 4 → at most 2 pairs | 2 named; 1 returned |
A post counts as a multi-term hit only if at least two of the typed terms appear as whole words in post.content.text. Whole word means a left and right boundary ((?<![A-Za-z0-9_])term(?![A-Za-z0-9_]), case-insensitive). Topic tags and quoted-post text are not in the 75%. automations (plural) is not automation.
Term split on this page — the headline can lie: cari 0/20, ai 17/20, automation 15/20. Every multi-term hit is ai + automation. Buckets: 3-term 0, 2-term 15, 1-term 2, 0-term 3. The pair that returned posts is ai automation. cari as a whole word never appears. Do not read this page as Indonesian "cari" (search) jobs — the first word of the query contributed nothing to the captions.
Trimmed envelope from that call. Two on-topic rows, then one zero-term row that is still on the page:
{
"success": true,
"platform": "threads",
"endpoint": "/v1/threads/search",
"credits_used": 1,
"cached": false,
"request_id": "req-B1nKGNBEA20fk0U2",
"pagination": {
"has_more": false,
"page_size": 20
},
"data": {
"_warnings": [
"No Threads post matched \"cari ai automation\" as a phrase, so the query was expanded into 2 narrower searches (cari ai, ai automation) and 1 of them returned posts. Results are merged, de-duplicated and ordered by how many of your terms each post contains. You are billed 1 credit per search that returned posts, and an expanded response is a single page with no pagination cursor. Send expand=false to search the exact phrase only."
],
"items": [
{
"post": {
"id": "3966216076262486892",
"url": "https://www.threads.com/@zvka.x/post/DcK1IHoEbNs",
"author": { "username": "zvka.x" },
"engagement": { "likes": 411 },
"content": {
"text": "This FREE AI + Automation course can take you from beginner → advanced."
}
}
},
{
"post": {
"id": "3956306857446971863",
"url": "https://www.threads.com/@sassysaaraa/post/DbnoCAckZnX",
"author": { "username": "sassysaaraa" },
"engagement": { "likes": 369 },
"content": {
"text": "Started learning AI automation a few weeks ago. Today I finished my first complete project in Make."
}
}
},
{
"post": {
"id": "3802132888955666052",
"url": "https://www.threads.com/@theromanknox/post/DTD47fLCD6E",
"author": { "username": "theromanknox" },
"engagement": { "likes": 873 },
"content": {
"text": "Most automations look good. Very few actually work. These are real n8n workflows — not demos."
}
}
}
]
}
}@zvka.x and @sassysaaraa carry whole-word ai and automation. @sassysaaraa also has topic tag AI automation. @theromanknox matches automations and adjacent n8n talk, not whole-word automation. It is still on the expanded page because the pair search is ai automation, not a client-side filter. Including topic tags would raise some 1-term rows — @vlad.ushakov.ai has ai in the caption and topic tag AI automation — which is why the 75% is caption-only.
Each item is a canonical Post (dev.socialcrawl.post.v1) under the unified schema: language when detected, ext.topic_tag when Threads filed the post under one. Relevance is term-overlap, not row count. This change did not touch other Threads endpoints (profile, user posts, post detail, comments, user search).
When should you send expand=false instead of relaxing the phrase?
Default expand=true is the recall path: if Threads has never heard the phrase, search the adjacent pairs. Send expand=false when you want the exact phrase Threads already files as a topic — empty is fine.
curl -s -H "x-api-key: $SOCIALCRAWL_API_KEY" \
"https://www.socialcrawl.dev/v1/threads/search?query=cari%20ai%20automation&expand=false"Live (req-9e5zpulaoFDfH4WE, HTTP 200, cached: false, 1,147 ms):
{
"success": true,
"platform": "threads",
"endpoint": "/v1/threads/search",
"credits_used": 0,
"cached": false,
"request_id": "req-9e5zpulaoFDfH4WE",
"pagination": {
"has_more": false,
"page_size": 0
},
"data": {
"items": [],
"total": 0,
"dropped": 0
}
}0 posts, 0 credits. Threads has never heard of cari ai automation as a phrase. An empty exact-phrase call does not bill. Same empty-and-free behaviour was already true on 04/09; what changed on 07/09 is the default path stopped falling back to single tokens. Leave expand at default when you want recall of an unknown phrase. Set expand=false when a pair-merge would mix in posts that only share a neighbouring pair, not the phrase you typed.
Does word count decide whether a Threads query splits?
No. Three words is not a split trigger. A phrase Threads already knows returns one window, 1 credit, no _warnings, and pagination stays on. A phrase it does not know expands into pairs. This harvest called two recognised three-word phrases; neither split.
curl -s -H "x-api-key: $SOCIALCRAWL_API_KEY" \
"https://www.socialcrawl.dev/v1/threads/search?query=machine%20learning%20engineer"query=machine learning engineer (req-XBrnbaOt9ttLTeJF, 3,195 ms, cached: false): 20 posts, 1 credit, no _warnings, has_more=true. Multi-term: 16 / 20 = 80% (11 of 20 carry all three of machine / learning / engineer).
{
"success": true,
"platform": "threads",
"endpoint": "/v1/threads/search",
"credits_used": 1,
"cached": false,
"request_id": "req-XBrnbaOt9ttLTeJF",
"pagination": {
"has_more": true,
"page_size": 20
},
"data": {
"items": [
{
"post": {
"id": "3296195738167477136",
"url": "https://www.threads.com/@codingmermaid.ai/post/C2-cI9ToQOQ",
"author": { "username": "codingmermaid.ai" },
"engagement": { "likes": 324 },
"content": {
"text": "Are you looking to become a machine learning engineer?"
}
}
}
]
}
}query=ai automation agency (req-Sc5znEt3HlrQblbl, 3,689 ms, cached: false): 20 posts, 1 credit, no _warnings, has_more=true. Multi-term: 14 / 20 = 70% (3 of 20 carry all three).
{
"success": true,
"platform": "threads",
"endpoint": "/v1/threads/search",
"credits_used": 1,
"cached": false,
"request_id": "req-Sc5znEt3HlrQblbl",
"pagination": {
"has_more": true,
"page_size": 20
},
"data": {
"items": [
{
"post": {
"id": "3970395697807160969",
"url": "https://www.threads.com/@buildwithmano/post/DcZrdnhiPaJ",
"author": { "username": "buildwithmano" },
"engagement": { "likes": 27 },
"content": {
"text": "Starting my AI automation agency from scratch."
}
}
}
]
}
}@papoush_nd_ is another 3-term row: "I'm looking to connect with more AI Automation Agency owners." @stanleywangg is a 1-term row — "My first successful automation on n8n." — still a recognised-phrase hit, not an expanded merge.
A threads api search splits when Threads does not recognise the phrase, not when the query has three tokens. Docs also list new york city as a recognised phrase; this harvest did not call it. cari ai automation is the counterexample: same word count, expanded, no cursor.
Does a short query still match ai inside email?
Ship note 07/09/2026: very short Latin/digit terms (length 1–3) used to score as substrings, so ai hit inside email, rain, and said. The product now requires a left word boundary for those short terms. The live page does not contain those false hosts. We cannot show the pre-ship failure — we did not re-measure it.
curl -s -H "x-api-key: $SOCIALCRAWL_API_KEY" \
"https://www.socialcrawl.dev/v1/threads/search?query=ai"Live (req-9tKz9dPbgkYe1CL0, 3,900 ms, cached: false): 17 posts, 1 credit, has_more=true.
| Check (n=17) | Live |
|---|---|
Whole-word ai in post.content.text | 10 / 17 |
Whole-word email / rain / said in caption | 0 |
Caption where ai exists only inside those three hosts | 0 |
Caption-misses with topic tag AI Threads or AI team | 6 |
| Caption-miss with neither | 1 (@beewilson_) |
One other caption still has ai as a substring: @meor.store contains ai only inside Aiman / maintain, and also carries topic_tag=AI team. That is a topic-tag retrieval, not evidence the short term matched inside those tokens. Same host check on the cari ai automation page: 0/20 for whole-word email / rain / said.
{
"success": true,
"platform": "threads",
"endpoint": "/v1/threads/search",
"credits_used": 1,
"cached": false,
"request_id": "req-9tKz9dPbgkYe1CL0",
"pagination": {
"has_more": true,
"page_size": 17
},
"data": {
"items": [
{
"post": {
"id": "3981272493298417111",
"url": "https://www.threads.com/@matthew_zorich_author/post/DdAUj0tFf3X",
"author": { "username": "matthew_zorich_author" },
"engagement": { "likes": 7 },
"content": {
"text": "So attended a book con recently at let me just say, a lot of authors are leaning Into AI & it's gross."
}
}
}
]
}
}@matthew_zorich_author is a whole-word ai hit. @beewilson_ is the honest miss: "alright , it's Labor Day who house are u going to first ?" — no whole-word ai, no AI … topic tag. Topic tags named AI Threads or AI team still retrieve captions that never say ai. Longer terms and glued particles (커피를 for 커피, mesinnya for mesin) still match as substrings; this harvest did not re-prove those.
What timeout do you need if you raise limit on Threads search?
This harvest used the default window only. Every number in this section is ship note 07/09/2026, cache-cold — not re-measured on 08/09.
limit (1–100) is a collection target, not Meta's page size (official default 25 / max 100 on keyword_search). The walk stops at the first whole window that reaches N, so the response usually overshoots. Values outside 1–100 return a free 400. Windows run sequentially at roughly 3.4 seconds each. Ship note 07/09 cache-cold: no limit 3.5s / 20 posts; limit=30 7.3s / 37; limit=50 10.2s / 55; limit=100 19.5s / 111.
HTTPX's default is a TimeoutException after 5 seconds of network inactivity. Python Requests documents that omitting timeout can hang indefinitely. A limit=50 call at 10.2s misses HTTPX's 5s default. The 07/09 fan-out has a 6 second phase budget so an empty-phrase expansion still returns inside a ~10s client. Set timeout at 15s or more on a threads api python client, or skip the long walk and page with pagination.next_cursor for the same credits.
limit is for recognised phrases. Expanded responses have no cursor — the cari ai automation page in the first example is one shot, has_more=false. Params live on /docs/threads.
How do you reproduce these calls in Python?
- Create a key (100 free credits, no card) and send it as
x-api-key. Auth is header-only:/docs/authentication. - Hit the unknown-phrase call from the first example, or
machine learning engineerif you want a paginated known phrase. - Python 3.10+
requests,timeout=15. Print page length andcredits_used. Optionally score multi-term hits with the same whole-word rule.
import os
import re
import requests
BASE = "https://www.socialcrawl.dev"
r = requests.get(
f"{BASE}/v1/threads/search",
params={"query": "cari ai automation"},
headers={"x-api-key": os.environ["SOCIALCRAWL_API_KEY"]},
timeout=15,
)
r.raise_for_status()
payload = r.json()
items = payload["data"]["items"]
print(len(items), payload.get("credits_used"))
TERMS = ("cari", "ai", "automation")
boundary = lambda t: re.compile(
rf"(?<![A-Za-z0-9_]){re.escape(t)}(?![A-Za-z0-9_])", re.I
)
hits = 0
for it in items:
text = ((it.get("post") or {}).get("content") or {}).get("text") or ""
if sum(1 for t in TERMS if boundary(t).search(text)) >= 2:
hits += 1
print(hits, "multi-term")One API key, one parser. The envelope is always success, platform, endpoint, data, credits_used, credits_remaining, request_id, cached. Canonical Post on every item.
Next: the visual explorer at /explorer (see the same query before writing a single line) · /docs/threads · /platforms/threads · density sibling TikTok API: 150 followers per credit.
Reproduce the five GETs with your own key. Expect the post set to drift; a re-run will not return the same 20 ids. Expect the expansion warning, the 1-credit pair-billing, and the unsplit three-word pages to hold.
Frequently asked questions
How many credits does a Threads keyword search cost after 7 September 2026?
1 credit per returning ~15–20 post window. Empty exact-phrase (expand=false on an unknown query) bills 0. Live 08/09: five calls billed 4 (1 + 0 + 1 + 1 + 1). Cache hits bill 0. Failed calls and empty results are refunded. Other Threads endpoints are unchanged. Metering: /docs/credits.
What does expand=false do on GET /v1/threads/search?
Exact phrase only. Live 08/09: query=cari ai automation&expand=false returned 0 posts, 0 credits, HTTP 200 (req-9e5zpulaoFDfH4WE). Default expand=true relaxes an unknown phrase into adjacent pairs, bills 1 credit per pair that returned posts, and returns a single page with no pagination cursor.
Does Threads keyword search still match short terms inside longer words?
Live 08/09 query=ai: 0/17 captions with whole-word email / rain / said, and 0 captions where ai exists only inside those three hosts. Ship note 07/09: Latin/digit terms of length 1–3 need a left word boundary. That is an absence claim — the pre-ship baseline was not re-measured. Topic tags named AI … still retrieve captions that never say ai. One caption (@beewilson_, Labor Day) had neither whole-word ai nor an AI … tag.
What timeout should I set if I pass limit=50 or limit=100?
Ship note 07/09 cache-cold: limit=50 10.2s / 55 posts; limit=100 19.5s / 111. HTTPX's 5s default will miss both. Set 15s or more, or page with pagination.next_cursor instead. Not re-measured on 08/09. Expanded responses have no cursor, so limit is for recognised phrases.
Does pair expansion change other Threads endpoints?
No. Search only (GET /v1/threads/search). Profile, user posts, post detail, comments, and user search are untouched.
Related posts
Google Trends API: Empty Searches Cost 0 Credits
Empty Google Trends API searches now return 404 with 0 credits charged. Live production curls cover Trends empties, News ranks, and app filter refusals.
Google Trends API Python: ~4.6s Typical (Was ~9s)
A Google Trends API Python GET is ~4.6s typical (was ~9s on 22 billed calls). Live interest-over-time and related queries, same 5 credits, 2026-09-08 UTC.
Instagram API: About is back, 1 credit, named 404s
/v1/instagram/profile/about is back: United States, February 2012, 1 credit. Wrong Instagram API paths return did_you_mean at 0 credits. Checked 2026-09-08.
