TikTok API endpoint
Returns the hashtag suggestions the app shows while typing in the search box, keyed by `keyword`. The upstream is `/aweme/v1/search/challengesug/`; each `sug_list` row carries `cha_name` (hashtag name), `view_count`, `use_count` and `cid` (the numeric hashtag id), so this is the discovery step for the hashtag endpoints (`hashtag info` is name-keyed). Measured 2026-10-21 with the pure-Go (device-free) signer: `keyword=lofi` returned 10 rows (`lofi` 18.2B views / 1.9M uses, then `lofiasmr`, `lofihiphop`, ...), `coffee` and `ラーメン` also returned 10 rows, and a keyword with no suggestions is a valid empty page (`sug_list: []`). `count` is accepted for shape parity but the server was measured to ignore it (5/20/100 all returned 10 rows), and the route has no paging. The route is not signature-gated, so it does not need the device-backed signer.
/tiktok/mobile/search/hashtagsThe hashtag suggestions the app shows while you type in the search box, keyed by keyword. The upstream is
GET /aweme/v1/search/challengesug/, captured from the running 47.4.3 app and reproduced end-to-end against the
live gateway. It is the hashtag counterpart of the shipped user typeahead (/api/v1/tiktok/mobile/search/sug).
What a suggestion row carries. Each sug_list row is the app's hashtag object:
{cha_name, view_count, use_count, cid} — the hashtag name (use it directly with the hashtag endpoints, which are
name-keyed: hashtag info, hashtag posts, hashtag search), its lifetime view count, its video-use count, and
cid, the numeric hashtag id. Ten rows are returned for a prefix query; a keyword with no suggestions is a valid
empty page (sug_list: []), not an error.
One-shot. The route has no paging field, and count is only shape parity: the server was measured to ignore
it (5, 20 and 100 all returned the same 10 rows), so suggestions are one page and the count parameter is not a
page-size control.
Device-free. The pure-Go placeholder signer returned the same suggestions, so a deployment needs
TIKTOK_MOBILE_PARAMS but not the device-backed signer (TIKTOK_MOBILE_SIGNER_URL). It answers on the core
aggr16-normal.tiktokv.us / api16-normal-useast5.tiktokv.us pair.
Query parameters:
keyword: required. The text typed so far; prefixes and non-Latin scripts both work.count: optional. Accepted for shape parity and validated, but the server was measured to ignore it.Errors:
keyword is missing or blank, or count is out of range.| call | result |
|---|---|
keyword=lofi | 1,226 B; 10 rows; first lofi (18,273,876,528 views / 1,926,700 uses / cid 4602873), then lofiasmr, lofihiphop, lofivibes, lofichill, … |
keyword=coffee | 1,248 B; 10 rows, first coffee |
keyword=coffee shop | 1,274 B; 10 rows (multi-word prefix) |
keyword=ラーメン | 1,332 B; 10 rows (non-Latin script) |
| bare / empty keyword | 358 B; valid empty page (sug_list: []) |
count=5 / 20 / 100 | identical 10-row page (count ignored) |
| shipped-service canary | rows=10 first="lofi" |
Example request:
GET /api/v1/tiktok/mobile/search/hashtags?keyword=lofi
Example response (truncated):
{
"code": 200,
"msg": "OK",
"data": {
"sug_list": [
{"cha_name": "lofi", "view_count": 18273876528, "use_count": 1926700, "cid": "4602873"},
{"cha_name": "lofiasmr", "view_count": 12793337489, "use_count": 315507, "cid": "1626680631018501"},
{"cha_name": "lofihiphop", "view_count": 833720221, "use_count": 285739, "cid": "30107753"}
],
"rid": "20261021173213477CE85B8289CE303E4D",
"words_query_record": {"words_source": "sug", "query_id": ""},
"status_code": 0,
"status_msg": ""
}
}
Notes for callers:
cha_name straight into /api/v1/tiktok/mobile/hashtag/info or the hashtag post endpoints; they are
name-keyed, so no id translation is needed. cid is useful for de-duplicating suggestions across queries.| Parameter | Type | Required | Default | Description | Example |
|---|---|---|---|---|---|
| x-api-key (header) | string | Yes | API key required | ||
| keyword | string | Yes | Text typed so far; the server also accepts prefixes (e.g. lofi -> lofihiphop) | lofi | |
| count | integer | No | Accepted for shape parity; the server was measured to ignore it (always up to 10 rows) | 10 |
curl -X GET "https://api.crawlora.net/api/v1/tiktok/mobile/search/hashtags?keyword=lofi&count=10" \ -H "x-api-key: $CRAWLORA_API_KEY"
{
"code": 200,
"msg": "OK",
"data": {
"sug_list": [
{
"cha_name": "lofi",
"view_count": 18273876528,
"use_count": 1926700,
"cid": "4602873"
},
{
"cha_name": "lofiasmr",
"view_count": 12793337489,
"use_count": 315507,
"cid": "1626680631018501"
},
{
"cha_name": "lofihiphop",
"view_count": 833720221,
"use_count": 285739,
"cid": "30107753"
}
],
"rid": "20261021173213477CE85B8289CE303E4D",
"words_query_record": {
"words_source": "sug",
"query_id": ""
},
"status_code": 0,
"status_msg": ""
}
}Request schema
No body schema
Response schema
#/definitions/tiktokmobile.hashtagSuggestionsResponseDoc
| Field | Type | Required | Enum | Bounds | Example | Description |
|---|---|---|---|---|---|---|
| extra | unknown | No | ||||
| log_pb | unknown | No | ||||
| rid | string | No | 20261021173213477CE85B8289CE303E4D | |||
| status_code | integer | No | 0 | |||
| status_msg | string | No | ||||
| sug_list | array | No | ||||
| words_query_record | unknown | No |
| Status | Description | Schema |
|---|---|---|
| 400 | Invalid input | #/definitions/app.Response |
| 429 | Rate limit exceeded | #/definitions/app.Response |
| 500 | Internal server error | #/definitions/app.Response |
Use environment variables for secrets and keep Crawlora API keys server-side.
curl -X GET "https://api.crawlora.net/api/v1/tiktok/mobile/search/hashtags?keyword=lofi&count=10" \
-H "x-api-key: $CRAWLORA_API_KEY"