TikTok API endpoint
Calls the app's cached-pull feed route - `GET /tiktok/feed/offline/v2` - which answers protobuf, and returns a schema-free decode: field numbers become keys, printable length-delimited fields become strings and nested messages become objects, plus a flat list of every string leaf (`strings`), which is the fastest way to mine video ids and captions. Field numbering is inferred because TikTok publishes no schema for this message. This is the cached/offline pull variant, not the primary `POST /aweme/v2/feed/` feed already exposed as `/tiktok/mobile/feed/post`. The route is signature-validated, so it needs device-backed request signing to be configured for the deployment and fails with an error when it is not.
/tiktok/mobile/feed/offlineCalls the app's cached-pull feed route — GET /tiktok/feed/offline/v2 — and returns a schema-free protobuf
decode: field numbers become keys, printable length-delimited fields become strings, nested messages become
objects and binary leaves become base64. strings is a flat list of every string leaf (video ids, captions,
author names, CDN paths), which is usually the fastest way to consume the page.
This route was captured from the running 47.4.3 app over mitmproxy and then reproduced with the device-backed
signer. It is not the primary feed: POST /aweme/v2/feed/ is already exposed as
/api/v1/tiktok/mobile/feed/post; this is the cached/offline pull variant the app also requests.
Requires device-backed request signing. Without TIKTOK_MOBILE_SIGNER_URL the endpoint fails closed with a
typed error instead of returning an empty page.
Query parameters:
pull_type: optional. Forwarded to the app route; the captured app call used 11 (which is also this
endpoint's default when the parameter is omitted or 0). Measured pull_type=0 also answers a full page
(712,836 B), so both are usable.count: optional. Page size, sanity-bounded at 50. Omitted when unset so the upstream keeps its default;
the captured app call used count=10.Notable response behavior:
items for the
nested decode and strings for the flat text leaves; both are always present.host, fetched_at, pull_type, count and a note are added by this API.Measured 2026-10-21 with the device-backed signer, aggr16-normal.tiktokv.us edge / api16-normal-useast5.tiktokv.us
origin:
pull_type=11&count=10: HTTP 200, 936,352 B, readable aweme_id/desc strings.pull_type=0&count=10: HTTP 200, 712,836 B, a different page.Example request:
GET /api/v1/tiktok/mobile/feed/offline?pull_type=11&count=10
Example response (truncated):
{
"code": 200,
"msg": "OK",
"data": {
"pull_type": 11,
"count": 10,
"items": {
"f1": {"f1": "7691695255472898698", "f3": "This Bread Bowl Melts Perfectly Over Campfire ..."},
"f2": 0
},
"strings": ["7691695255472898698", "This Bread Bowl Melts Perfectly Over Campfire ...", "..."],
"host": "aggr16-normal.tiktokv.us",
"note": "field numbers are inferred; this route answers protobuf with no published schema"
}
}
| Parameter | Type | Required | Default | Description | Example |
|---|---|---|---|---|---|
| x-api-key (header) | string | Yes | API key required | ||
| pull_type | integer | No | Pull type forwarded to the app route (measured 0 and 11; default 11) | 11 | |
| count | integer | No | Page size, bounded at 50 (upstream default when omitted) | 10 |
curl -X GET "https://api.crawlora.net/api/v1/tiktok/mobile/feed/offline?count=10" \ -H "x-api-key: $CRAWLORA_API_KEY"
{
"code": 200,
"msg": "OK",
"data": {
"pull_type": 11,
"count": 10,
"items": {
"f1": {
"f1": "7691695255472898698",
"f3": "This Bread Bowl Melts Perfectly Over Campfire ..."
},
"f2": 0
},
"strings": [
"7691695255472898698",
"This Bread Bowl Melts Perfectly Over Campfire ...",
"..."
],
"host": "aggr16-normal.tiktokv.us",
"note": "field numbers are inferred; this route answers protobuf with no published schema"
}
}Request schema
No body schema
Response schema
#/definitions/tiktokmobile.offlineFeedResponseDoc
| Field | Type | Required | Enum | Bounds | Example | Description |
|---|---|---|---|---|---|---|
| count | integer | No | 10 | |||
| fetched_at | string | No | ||||
| host | string | No | aggr16-normal.tiktokv.us | |||
| items | object | No | ||||
| note | string | No | ||||
| pull_type | integer | No | 11 | |||
| strings | array | 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/feed/offline?count=10" \
-H "x-api-key: $CRAWLORA_API_KEY"