Quick start · TikTok
TikTok WebSocket API quick start
Connect to your TikTok stream with your WebSocket key and receive uploads, reposts and LIVE starts and ends from the creators you track. This page gets a consumer running; the API reference holds every field.
- WebSocket
wss://tiktok.1322.io{ws_path}- REST base
https://tiktok.1322.io- Auth
- API key (REST) + separate WebSocket key
- Updated
What you get
New uploads (video, photo and carousel), reposts, and LIVE start and end events from the TikTok creators on your list, plus a tiktok.media.ready frame with a signed download link once a tracked video's file is ready. Content frames carry kind, the description with parsed hashtags and mentions, the duration and the sound.
Events arrive in under a second.
Price: From $200/month for 5 creators; WebSocket +$100/month. Plans: Lite $200/month (5 creators), Standard $350/month (15 creators), Premium $550/month (30 creators). Pay monthly, or prepay 3 months (10% off), 6 months (15% off) or a year (25% off). See TikTok pricing.
Authentication
- TikTok uses two separate keys. REST takes your API key:
X-API-Key: <api_key>orAuthorization: Bearer <api_key>. - The WebSocket takes your WebSocket key:
X-WS-Key: <ws_key>orAuthorization: Bearer <ws_key>. Sending the API key there returns 401, and there is no?key=option. - Your stream path is account-specific (
/ws/<32 hex>):GET /v1/ws/statusreturns it aspath. Reveal or generate the WebSocket key on the API access page in your dashboard. - Up to 16 concurrent WebSocket connections per account and 8 per IP.
Connect to the WebSocket
Set these environment variables, then run either consumer from your server:
TIKTOK_WS_PATH: path from GET /v1/ws/statusTIKTOK_WS_KEY: your WebSocket key (not the API key)TIKTOK_API_KEY: your API key (REST only)
# pip install "websockets>=13" (Python 3.9+)
import asyncio, json, os
from websockets.asyncio.client import connect
# Path: GET /v1/ws/status -> "path". Key: the WebSocket key, NOT the API key.
WS_URL = "wss://tiktok.1322.io/" + os.environ["TIKTOK_WS_PATH"].strip("/")
HEADERS = {"X-WS-Key": os.environ["TIKTOK_WS_KEY"]}
def handle(event):
kind = event.get("type") or ""
obj = event.get("object") or {}
if kind == "tiktok.media.ready":
# Same event_id as an earlier upload: attach the file, do not post again.
print("media ready", event.get("event_id"), obj.get("media_url"))
return
account = event.get("account") or {}
print(kind, account.get("username"), obj.get("kind"), obj.get("url"))
async def main():
backoff = 1
while True:
try:
async with connect(WS_URL, additional_headers=HEADERS) as ws:
backoff = 1
async for raw in ws:
try:
event = json.loads(raw)
except ValueError:
continue
if isinstance(event, dict):
handle(event)
except Exception as exc:
print("disconnected:", exc)
await asyncio.sleep(backoff)
backoff = min(backoff * 2, 30)
asyncio.run(main())// npm install ws, save as consumer.mjs, run: node consumer.mjs (Node 18+)
import WebSocket from "ws"
// Path: GET /v1/ws/status -> "path". Key: the WebSocket key, NOT the API key.
const WS_PATH = (process.env.TIKTOK_WS_PATH ?? "").split("/").filter(Boolean).join("/")
const WS_KEY = process.env.TIKTOK_WS_KEY
if (!WS_PATH || !WS_KEY) throw new Error("Set TIKTOK_WS_PATH and TIKTOK_WS_KEY")
const WS_URL = "wss://tiktok.1322.io/" + WS_PATH
function handle(event) {
if (event.type === "tiktok.media.ready") {
// Same event_id as an earlier upload: attach the file, do not post again.
console.log("media ready", event.event_id, event.object?.media_url)
return
}
console.log(event.type, event.account?.username, event.object?.kind, event.object?.url)
}
let backoff = 1000
function connect() {
const ws = new WebSocket(WS_URL, { headers: { "X-WS-Key": WS_KEY } })
ws.on("open", () => { backoff = 1000 })
ws.on("message", (raw) => {
let event
try { event = JSON.parse(raw.toString()) } catch { return }
if (event && typeof event === "object" && !Array.isArray(event)) handle(event)
})
ws.on("error", (err) => console.error("socket error:", err.message))
ws.on("close", () => {
setTimeout(connect, backoff)
backoff = Math.min(backoff * 2, 30000)
})
}
connect()- Handshake failures return before the upgrade: 401 wrong or missing key, 403 expired account or WebSocket disabled, 404 wrong path, 429 connection limit. Success is 101.
- Delivery is live only (
delivery.modeislive_only): nothing is queued while you are disconnected.
One example frame
Illustrative values for fictional accounts, trimmed to the fields most consumers read first. A real frame carries the full set for your tracked accounts.
{
"schema": "1322.tiktok.event.v1",
"event_id": "01J9Z8QX4T7C2V1M0K3R5B6N7P",
"sequence": 4821,
"type": "tiktok.upload.created",
"platform": "tiktok",
"account": {
"username": "examplecreator",
"display_name": "Example Creator",
"sec_uid": "MS4wLjABAAAA-example"
},
"object": {
"video_id": "7300000000000000000",
"url": "https://www.tiktok.com/@examplecreator/video/7300000000000000000",
"kind": "video",
"description": "studio day @friendcreator #launch",
"hashtags": [
"launch"
],
"mentions": [
"friendcreator"
],
"duration": 27
},
"occurred_at": "2026-10-15T14:03:11Z",
"observed_at": "2026-10-15T14:03:12Z",
"delivery": {
"mode": "live_only"
}
}- Dedupe on
event_id.verifiedappears onaccountonly when the creator is verified, so test for presence, not forfalse. - A repost carries
object.original_authoras an object (readoriginal_author.username). There is noplay_url; download fromobject.media_urlon thetiktok.media.readyframe, which needs no API key.
Manage the list over REST
REST base https://tiktok.1322.io. Each call below sends X-API-Key with your API key.
| Method | Path | What it does |
|---|---|---|
| GET | /v1/ws/status | Your WebSocket path and current connections. |
| GET | /v1/list | Tracked creators, their events and delivery routes. |
| POST | /v1/track | Add a creator by username or sec_uid. |
| POST | /v1/untrack | Remove a creator by username, sec_uid or track_id. |
| GET | /v1/limits | Creator slots and WebSocket connection ceilings. |
curl "https://tiktok.1322.io/v1/ws/status" \
-H "X-API-Key: $TIKTOK_API_KEY"
curl "https://tiktok.1322.io/v1/list" \
-H "X-API-Key: $TIKTOK_API_KEY"
curl -X POST "https://tiktok.1322.io/v1/track" \
-H "Content-Type: application/json" \
-H "X-API-Key: $TIKTOK_API_KEY" \
-d '{ "username": "examplecreator" }'
curl -X POST "https://tiktok.1322.io/v1/untrack" \
-H "Content-Type: application/json" \
-H "X-API-Key: $TIKTOK_API_KEY" \
-d '{ "username": "examplecreator" }'
curl "https://tiktok.1322.io/v1/limits" \
-H "X-API-Key: $TIKTOK_API_KEY"GET /v1/dashboardreturns everything in one nested call (client,limits,tracks,websocket)./health,/healthzand/readyzare public probes that take no key.
Full reference
Every field, endpoint and edge case for TikTok lives in the API reference. Jump straight to the part you need:
Common questions
Why does the TikTok WebSocket return 401?
Usually the API key was sent where the WebSocket key belongs. The stream only accepts the separate WebSocket key, as X-WS-Key or Authorization: Bearer.
Can I put the TikTok key in the WebSocket URL?
No. Query-string keys are not enabled. Connect to wss://tiktok.1322.io plus your /ws/<32 hex> path and send the key in a header.
How do I download a tracked video?
Wait for the tiktok.media.ready frame with the same event_id and fetch its signed object.media_url. No API key is needed; a 503 with Retry-After: 1 means the file is not ready yet.
Other quick starts
- X (Twitter) WebSocket quick start: Tweets, deletes, profile and follow events
- Truth Social WebSocket quick start: Posts, retruths, quotes and media
- Instagram WebSocket quick start: Posts, Reels, carousels and Stories
- YouTube WebSocket quick start: Uploads, Shorts and deletions
- Binance Square WebSocket quick start: Posts, pin changes and sentiment
- News WebSocket quick start: Full-text articles from news feeds
Related: