Connect to any TikTok Live stream and receive real-time events in Lua — chat, gifts, likes, joins, viewer counts, and 64 decoded event types. Poll-based API for game engine integration. No signing server, no API keys, no authentication required.
local PirateTok = require "piratetok"
-- Create client with builder pattern — cdn("eu") picks the EU endpoint
local client = PirateTok.builder("username_here")
:cdn("eu")
:build()
-- Register event callbacks — poll-based, ideal for game engines (Love2D, Defold)
client:on("chat", function(msg)
local name = msg.user and msg.user.nickname or "?"
print("[chat] " .. name .. ": " .. (msg.comment or ""))
end)
client:on("gift", function(msg)
local name = msg.user and msg.user.nickname or "?"
local gift = msg.gift and msg.gift.name or "gift"
local diamonds = PirateTok.events.diamond_total(msg)
print("[gift] " .. name .. " sent " .. gift .. " (" .. diamonds .. " diamonds)")
end)
client:on("like", function(msg)
local name = msg.user and msg.user.nickname or "?"
print("[like] " .. name .. " (" .. (msg.total_likes or 0) .. " total)")
end)
-- Blocks until disconnected — heartbeat and reconnection handled internally
client:run()Requires LuaJIT and luarocks:
luarocks --lua-version=5.1 install luasocket
luarocks --lua-version=5.1 install luasec
luarocks --lua-version=5.1 install lua-protobuf
luarocks --lua-version=5.1 install lua-zlib
luarocks --lua-version=5.1 install lua-cjsonCopy the piratetok/ directory into your project.
| Language | Install | Repo |
|---|---|---|
| Rust | cargo add piratetok-live-rs |
live-rs |
| Go | go get github.com/PirateTok/live-go |
live-go |
| Python | pip install piratetok-live-py |
live-py |
| JavaScript | npm install piratetok-live-js |
live-js |
| C# | dotnet add package PirateTok.Live |
live-cs |
| Java | com.piratetok:live |
live-java |
| Elixir | {:piratetok_live, "~> 0.1"} |
live-ex |
| Dart | dart pub add piratetok_live |
live-dart |
| C | #include "piratetok.h" |
live-c |
| PowerShell | Install-Module PirateTok.Live |
live-ps1 |
| Shell | bpkg install PirateTok/live-sh |
live-sh |
Poll-based API — call client:poll() in your game loop instead of client:run():
local PirateTok = require "piratetok"
local messages = {}
local client = PirateTok.builder("username_here"):build()
client:on("chat", function(msg)
local name = msg.user and msg.user.nickname or "?"
table.insert(messages, name .. ": " .. (msg.comment or ""))
end)
client:connect()
function love.update(dt)
client:poll() -- non-blocking, reads available frames
end
function love.draw()
for i, line in ipairs(messages) do
love.graphics.print(line, 10, i * 20)
end
end- Zero signing dependency — no API keys, no signing server, no external auth
- 64 decoded event types — chat, gifts, likes, joins, follows, shares, battles, polls, envelopes, and more
- Poll-based API —
client:poll()for game loops,client:run()for standalone scripts - Auto-reconnection — stale detection, exponential backoff, self-healing auth
- Enriched User data — badges, gifter level, moderator status, follow info, fan club
- Sub-routed convenience events —
follow,share,join,live_endedfire alongside raw events - No protoc — protobuf schemas defined inline via lua-protobuf, no codegen, no build tools
local client = PirateTok.builder("username_here")
:cdn("eu") -- "eu" / "us" / "global" (default)
:timeout(15) -- HTTP timeout in seconds (default 10)
:heartbeat_interval(10) -- seconds between heartbeats (default 10)
:stale_timeout(90) -- reconnect after N seconds of silence (default 60)
:max_retries(10) -- reconnect attempts (default 5)
:proxy("socks5://host:port") -- proxy URL (HTTP/HTTPS/SOCKS5)
:build()| Event | Callback data |
|---|---|
chat |
.user, .comment |
gift |
.user, .gift_details, .repeat_count, .repeat_end, .combo_count |
like |
.user, .count, .total |
join |
.user (sub-routed from MemberMessage) |
follow |
.user (sub-routed from SocialMessage) |
share |
.user (sub-routed from SocialMessage) |
room_user_seq |
.viewer_count, .total_user |
live_ended |
.reason (sub-routed from ControlMessage) |
connected |
.room_id |
reconnecting |
.attempt, .max_retries, .delay_secs, .reason |
disconnected |
.reason |
error |
error table (use PirateTok.errors.format(err)) |
unknown |
.method, .payload (raw bytes for unhandled types) |
Plus 50+ more decoded types: emote_chat, poll, envelope, rank_update, link_mic_battle, etc.
local PirateTok = require "piratetok"
local result, err = PirateTok.check_online("username_here")
if not result then
print(PirateTok.errors.format(err)) -- "not found" / "not online" / "blocked"
else
print("LIVE — room_id: " .. result.room_id)
end-- Normal rooms — no cookies needed
local info, err = PirateTok.fetch_room_info("ROOM_ID")
-- 18+ rooms — pass session cookies from browser DevTools
local info, err = PirateTok.fetch_room_info("ROOM_ID", 10, "sessionid=abc; sid_tt=abc")client:on("gift", function(msg)
local events = PirateTok.events
if events.is_combo_gift(msg) then
if events.is_streak_over(msg) then
print("x" .. msg.repeat_count .. " = " .. events.diamond_total(msg) .. " diamonds")
end
else
print(events.diamond_total(msg) .. " diamonds")
end
end)- Resolves username to room ID via TikTok JSON API
- Authenticates and opens a direct WSS connection
- Sends protobuf heartbeats every 10s to keep alive
- Decodes protobuf event stream into Lua tables
- Auto-reconnects on stale/dropped connections with fresh credentials
All protobuf schemas are defined inline via lua-protobuf — no .proto files, no codegen, no build-time dependencies.
Requires LuaJIT with unrestricted system access (raw TCP sockets, FFI). Works in:
- Love2D — poll-based API designed for game loops
- Defold — with native extension packaging for C deps
- Standalone LuaJIT — scripts, bots, monitoring tools
Does not work in sandboxed Lua environments (Roblox, Neovim, FiveM, OpenResty) — these restrict socket access and/or use incompatible Lua variants.
luajit examples/basic_chat.lua <username> # connect + print chat events
luajit examples/online_check.lua <username> # check if user is live
luajit examples/stream_info.lua <username> # fetch room metadata + stream URLsSee examples/love2d/ for Love2D game engine integration.
- Explicit
DEVICE_BLOCKEDhandshake handling not implemented yet. .proxy()exists on the builder, but proxy transport is not wired into WebSocket/HTTP yet.
0BSD
