
Research
Security News
Lazarus Strikes npm Again with New Wave of Malicious Packages
The Socket Research Team has discovered six new malicious npm packages linked to North Korea’s Lazarus Group, designed to steal credentials and deploy backdoors.
tiktok-live-connector
Advanced tools
Node.js module to receive live stream chat events like comments and gifts from TikTok LIVE
A Node.js module to receive and decode live stream events such as comments and gifts in realtime from TikTok LIVE by connecting to TikTok's internal WebCast push service. The package includes a wrapper that connects to the WebCast service using just the username (uniqueId
). This allows you to connect to your own live chat as well as the live chat of other streamers. No credentials are required. Besides Chat Comments, other events such as Members Joining, Gifts, Viewers, Follows, Shares, Questions, Likes and Battles can be tracked.
Looking for a Python implementation of this library? Check out TikTokLive by @isaackogan
NOTE: This is not an official API. It's a reverse engineering project.
npm i tiktok-live-connector
const { WebcastPushConnection } = require('tiktok-live-connector');
// Username of someone who is currently live
let tiktokUsername = "officialgeilegisela";
// Create a new wrapper object and pass the username
let tiktokChatConnection = new WebcastPushConnection(tiktokUsername);
// Connect to the chat (await can be used as well)
tiktokChatConnection.connect().then(state => {
console.info(`Connected to roomId ${state.roomId}`);
}).catch(err => {
console.error('Failed to connect', err);
})
// Define the events that you want to handle
// In this case we listen to chat messages (comments)
tiktokChatConnection.on('chat', data => {
console.log(`${data.uniqueId} (userId:${data.userId}) writes: ${data.comment}`);
})
// And here we receive gifts sent to the streamer
tiktokChatConnection.on('gift', data => {
console.log(`${data.uniqueId} (userId:${data.userId}) sends ${data.giftId}`);
})
// ...and more events described in the documentation below
To create a new WebcastPushConnection
object the following parameters are required.
WebcastPushConnection(uniqueId, [options])
Param Name | Required | Description |
---|---|---|
uniqueId | Yes | The unique username of the broadcaster. You can find this name in the URL. Example: https://www.tiktok.com/@officialgeilegisela/live => officialgeilegisela |
options | No | Here you can set the following optional connection properties. If you do not specify a value, the default value will be used.processInitialData (default: true ) Define if you want to process the initital data which includes old messages of the last seconds. fetchRoomInfoOnConnect (default: true ) Define if you want to fetch all room information on connect() . If this option is enabled, the connection to offline rooms will be prevented. If enabled, the connect result contains the room info via the roomInfo attribute. You can also manually retrieve the room info (even in an unconnected state) using the getRoomInfo() function.enableExtendedGiftInfo (default: false ) Define if you want to receive extended information about gifts like gift name, cost and images. This information will be provided at the gift event. enableWebsocketUpgrade (default: true ) Define if you want to use a WebSocket connection instead of request polling if TikTok offers it. requestPollingIntervalMs (default: 1000 ) Request polling interval if WebSocket is not used. clientParams (default: {} ) Custom client params for Webcast API. requestHeaders (default: {} ) Custom request headers passed to axios. websocketHeaders (default: {} ) Custom websocket headers passed to websocket.client. requestOptions (default: {} ) Custom request options passed to axios. Here you can specify an httpsAgent to use a proxy and a timeout value. See Example. websocketOptions (default: {} ) Custom websocket options passed to websocket.client. Here you can specify an agent to use a proxy and a timeout value. See Example. |
Example Options:
let tiktokChatConnection = new WebcastPushConnection(tiktokUsername, {
processInitialData: false,
enableExtendedGiftInfo: true,
enableWebsocketUpgrade: true,
requestPollingIntervalMs: 2000,
clientParams: {
"app_language": "en-US",
"device_platform": "web"
},
requestHeaders: {
"headerName": "headerValue"
},
websocketHeaders: {
"headerName": "headerValue"
},
requestOptions: {
timeout: 10000
},
websocketOptions: {
timeout: 10000
}
});
A WebcastPushConnection
object contains the following methods.
Method Name | Description |
---|---|
connect | Connects to the live stream chat. Returns a Promise which will be resolved when the connection is successfully established. |
disconnect | Disconnects the connection. |
getState | Gets the current connection state including the cached room info (see below). |
getRoomInfo | Gets the current room info from TikTok API including streamer info, room status and statistics. Returns a Promise which will be resolved when the API request is done.Note: You can call this function even if you're not connected. Example |
getAvailableGifts | Gets a list of all available gifts including gift name, image url, diamont cost and a lot of other information. Returns a Promise that will be resolved when all available gifts has been retrieved from the API.Note: You can call this function even if you're not connected. Example |
A WebcastPushConnection
object has the following events which can be handled via .on(eventName, eventHandler)
Control Events:
Message Events:
connected
Triggered when the connection gets successfully established.
tiktokChatConnection.on('connected', state => {
console.log('Hurray! Connected!', state);
})
disconnected
Triggered when the connection gets disconnected. In that case you can call connect()
again to have a reconnect logic. Note that you should wait a little bit before attempting a reconnect to to avoid being rate-limited.
tiktokChatConnection.on('disconnected', () => {
console.log('Disconnected :(');
})
streamEnd
Triggered when the live stream gets terminated by the host. Will also trigger the disconnected
event.
tiktokChatConnection.on('streamEnd', () => {
console.log('Stream ended');
})
rawData
Triggered every time a protobuf encoded webcast message arrives. You can deserialize the binary object depending on the use case with protobufjs.
tiktokChatConnection.on('rawData', (messageTypeName, binary) => {
console.log(messageTypeName, binary);
})
websocketConnected
Will be triggered as soon as a websocket connection is established. The websocket client object is passed.
tiktokChatConnection.on('websocketConnected', websocketClient => {
console.log("Websocket:", websocketClient.connection);
})
error
General error event. You should handle this.
tiktokChatConnection.on('error', err => {
console.error('Error!', err);
})
member
Triggered every time a new viewer joins the live stream.
tiktokChatConnection.on('member', data => {
console.log(`${data.uniqueId} joins the stream!`);
})
Data structure:
{
userId: '6776663624629974021',
uniqueId: 'zerodytester',
nickname: 'Zerody One',
profilePictureUrl: 'https://p16-sign-va.tiktokcdn.com/...',
followRole: 1, // 0 = none; 1 = follower; 2 = friends
userBadges: [] // e.g. Moderator badge
}
chat
Triggered every time a new chat comment arrives.
tiktokChatConnection.on('chat', data => {
console.log(`${data.uniqueId} writes: ${data.comment}`);
})
Data structure:
{
comment: 'how are you?',
userId: '6776663624629974121',
uniqueId: 'zerodytester',
nickname: 'Zerody One',
profilePictureUrl: 'https://p16-sign-va.tiktokcdn.com/...',
followRole: 2, // 0 = none; 1 = follower; 2 = friends
userBadges: [
{
type: 'pm_mt_moderator_im',
name: 'Moderator'
}
]
}
gift
Triggered every time a gift arrives. You will receive additional information via the extendedGiftInfo
attribute when you enable the enableExtendedGiftInfo
option.
NOTE: Users have the capability to send gifts in a streak. This increases the
data.gift.repeat_count
value until the user terminates the streak. During this time new gift events are triggered again and again with an increaseddata.gift.repeat_count
value. It should be noted that after the end of the streak, another gift event is triggered, which signals the end of the streak viadata.gift.repeat_end
:1
. This applies only to gifts withdata.gift.gift_type
:1
. This means that even if the user sends agift_type
:1
gift only once, you will receive the event twice. Once withrepeat_end
:0
and once withrepeat_end
:1
. Therefore, the event should be handled as follows:
tiktokChatConnection.on('gift', data => {
if (data.gift.gift_type === 1 && data.gift.repeat_end === 0) {
// Streak in progress => show only temporary
console.log(`${data.uniqueId} is sending gift ${data.giftId} x${data.gift.repeat_count}`);
} else {
// Streak ended or non-streakable gift => process the gift with final repeat_count
console.log(`${data.uniqueId} has sent gift ${data.giftId} x${data.gift.repeat_count}`);
}
})
Data structure:
{
userId: '6776663624629974121',
uniqueId: 'zerodytester',
nickname: 'Zerody One',
profilePictureUrl: 'https://p16-sign-va.tiktokcdn.com/...',
gift: {
gift_id: 5729,
gift_type: 2,
repeat_count: 1,
repeat_end: 0,
to_user_id: 6929592145315251000
},
giftId: 5729,
// Extended info is present if you have enabled the 'enableExtendedGiftInfo' option
extendedGiftInfo: {
describe: 'sent Rose',
diamond_count: 1,
duration: 1000,
icon: {
avg_color: '#A3897C',
is_animated: false,
url_list: [
// Icon URLs...
]
},
id: 5655,
image: {
avg_color: '#FFEBEB',
is_animated: false,
url_list: [
// Image URLs...
]
},
is_broadcast_gift: false,
is_displayed_on_panel: true,
is_effect_befview: false,
item_type: 1,
name: 'Rose',
type: 1
}
}
roomUser
Triggered every time a statistic message arrives. This message currently contains only the viewer count.
tiktokChatConnection.on('roomUser', data => {
console.log(`Viewer Count: ${data.viewerCount}`);
})
like
Triggered when a viewer sends likes to the streamer. For streams with many viewers, this event is not always triggered by TikTok.
tiktokChatConnection.on('like', data => {
console.log(`${data.uniqueId} sent ${data.likeCount} likes, total likes: ${data.totalLikeCount}`);
})
Data structure:
{
likeCount: 5, // likes given by the user (taps on screen)
totalLikeCount: 83033, // likes that this stream has received in total
userId: '6776663624629974121',
uniqueId: 'zerodytester',
nickname: 'Zerody One',
profilePictureUrl: 'https://p16-sign-sg.tiktokcdn.com/...',
displayType: 'pm_mt_msg_viewer',
label: '{0:user} sent likes to the host'
}
social
Triggered every time someone shares the stream or follows the host.
tiktokChatConnection.on('social', data => {
console.log('social event data:', data);
})
Data structure:
{
userId: '6776663624629974121',
uniqueId: 'zerodytester',
nickname: 'Zerody One',
profilePictureUrl: 'https://p16-sign-va.tiktokcdn.com/...',
displayType: 'pm_main_follow_message_viewer_2', // or 'pm_mt_guidance_share' for sharing
label: '{0:user} followed the host'
}
questionNew
Triggered every time someone asks a new question via the question feature.
tiktokChatConnection.on('questionNew', data => {
console.log(`${data.uniqueId} asks ${data.questionText}`);
})
Data structure:
{
questionText: 'Do you know why TikTok has such a complicated API?',
userId: '6776663624629974121',
uniqueId: 'zerodytester',
nickname: 'Zerody One',
profilePictureUrl: 'https://p16-sign-va.tiktokcdn.com/...'
}
linkMicBattle
Triggered every time a battle starts.
tiktokChatConnection.on('linkMicBattle', (data) => {
console.log(`New Battle: ${data.battleUsers[0].uniqueId} VS ${data.battleUsers[1].uniqueId}`);
})
Data structure:
{
battleUsers: [
{
userId: '6761609734837650437', // Host
uniqueId: 'haje_bahjat',
nickname: '𝙃𝙖𝙟𝙚_𝙗𝙖𝙝𝙟𝙖𝙩',
profilePictureUrl: 'https://p77-sign-sg.tiktokcdn.com/...'
},
{
userId: '6994367558246597637', // Guest
uniqueId: 'aborayanelzidicomedy',
nickname: 'ابو ريان الايزيدي الكوميدي',
profilePictureUrl: 'https://p16-sign-va.tiktokcdn.com/....'
}
]
}
linkMicArmies
Triggered every time a battle participant receives points. Contains the current status of the battle and the army that suported the group.
tiktokChatConnection.on('linkMicArmies', (data) => {
console.log('linkMicArmies', data);
})
Data structure:
{
"battleStatus": 1, // 1 = running; 2 = final state
"battleArmies": [
{
"hostUserId": "6761609734837650437", // Streamer Host ID
"points": 17058,
"participants": [ // Top 3 supporters
{
"userId": "6809941952760742917",
"nickname": "Abdulaziz Slivaney"
},
{
"userId": "7062835930043139078",
"nickname": "Dilschad Amedi"
},
{
"userId": "6773657511493977093",
"nickname": "Kahin Guli"
}
]
},
{
"hostUserId": "6994367558246597637", // Streamer Guest ID
"points": 6585,
"participants": [
{
"userId": "7060878425477792773",
"nickname": "ADAM"
},
{
"userId": "7048005772659328006",
"nickname": "كلو"
},
{
"userId": "6818014975869699078",
"nickname": "Karwan###"
}
]
}
]
}
liveIntro
Triggered when a live intro message appears.
tiktokChatConnection.on('liveIntro', (msg) => {
console.log(msg);
})
let tiktokChatConnection = new WebcastPushConnection('@username');
tiktokChatConnection.getRoomInfo().then(roomInfo => {
console.log(roomInfo);
console.log(`Stream started timestamp: ${roomInfo.create_time}, Streamer bio: ${roomInfo.owner.bio_description}`);
console.log(`HLS URL: ${roomInfo.stream_url.hls_pull_url}`); // Can be played or recorded with e.g. VLC
}).catch(err => {
console.error(err);
})
let tiktokChatConnection = new WebcastPushConnection('@username');
tiktokChatConnection.getAvailableGifts().then(giftList => {
console.log(giftList);
giftList.forEach(gift => {
console.log(`id: ${gift.id}, name: ${gift.name}, cost: ${gift.diamond_count}`)
});
}).catch(err => {
console.error(err);
})
proxy-agent supports http
, https
, socks4
and socks5
proxies:
npm i proxy-agent
You can specify if you want to use a proxy for https requests, websockets or both:
const { WebcastPushConnection } = require('tiktok-live-connector');
const ProxyAgent = require('proxy-agent');
let tiktokChatConnection = new WebcastPushConnection('@username', {
requestOptions: {
httpsAgent: new ProxyAgent('https://username:password@host:port'),
timeout: 10000 // 10 seconds
},
websocketOptions: {
agent: new ProxyAgent('https://username:password@host:port'),
timeout: 10000 // 10 seconds
}
});
// Connect as usual
Your improvements are welcome! Feel free to open an issue or pull request.
FAQs
Node.js module to receive live stream chat events like comments and gifts from TikTok LIVE
The npm package tiktok-live-connector receives a total of 903 weekly downloads. As such, tiktok-live-connector popularity was classified as not popular.
We found that tiktok-live-connector demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
The Socket Research Team has discovered six new malicious npm packages linked to North Korea’s Lazarus Group, designed to steal credentials and deploy backdoors.
Security News
Socket CEO Feross Aboukhadijeh discusses the open web, open source security, and how Socket tackles software supply chain attacks on The Pair Program podcast.
Security News
Opengrep continues building momentum with the alpha release of its Playground tool, demonstrating the project's rapid evolution just two months after its initial launch.