Skip to content

Some chat messages are missing when listening to TikTok live with TikTok-Live-Connector #280

@22vipzona22

Description

@22vipzona22

Hello,

I'm using the tiktok-live-connector library to listen to chat messages and gifts from TikTok live streams. However, I noticed that some chat messages visible in the TikTok live chat are not received or logged by the connector.

I tested with the username edwardshow9 and implemented the following code (see below). While gifts and some messages are received, many chat messages that are clearly visible on the live stream do not come through.

I suspect this might be related to:

TikTok filtering or limiting messages for third-party clients

Some internal API limitations or protocol changes

Possibly account restrictions (like age) or authorization issues

Could you please help me understand why some messages are missing and how to reliably get all chat messages?

Thank you in advance!

const WebSocket = require('ws');
const { WebcastPushConnection } = require('tiktok-live-connector');
const fs = require('fs');
const path = require('path');
const { normalizeNick, verbalizeNick, numberToWords } = require('./normalizer');
const giftGrammar = require('./giftGrammar');

const tiktokUsername = 'edwardshow9';
const minichatWS = new WebSocket('ws://localhost:4848/Chat');

const giftsMerged = JSON.parse(
fs.readFileSync(path.join(__dirname, 'gifts_merged.json'), 'utf8')
);

function getGiftTranslation(giftName) {
const entry = giftsMerged.find(g => g.giftName_en === giftName);
return entry ? entry.giftName_ru : giftName;
}

function declineGift(giftName, count) {
const forms = giftGrammar[giftName];
if (!forms) return ${count} ${giftName};

const n = count % 100;
const n1 = count % 10;

let wordForm;
if (n > 10 && n < 20) {
wordForm = forms[3];
} else if (n1 === 1) {
wordForm = forms[1];
} else if (n1 >= 2 && n1 <= 4) {
wordForm = forms[2];
} else {
wordForm = forms[3];
}

return ${count} ${wordForm};
}

function verbalDeclineGift(giftName, count) {
const forms = giftGrammar[giftName];
if (!forms) return ${numberToWords(count)} ${giftName};

const n = count % 100;
const n1 = count % 10;

let wordForm;
if (n > 10 && n < 20) {
wordForm = forms[3];
} else if (n1 === 1) {
wordForm = forms[1];
} else if (n1 >= 2 && n1 <= 4) {
wordForm = forms[2];
} else {
wordForm = forms[3];
}

const numberWord = count === 1 ? forms[0] : numberToWords(count);
return ${numberWord} ${wordForm};
}

minichatWS.on('open', () => {
console.log('✅ Connected to Minichat');

const tiktok = new WebcastPushConnection(tiktokUsername);
let isConnected = false;
let ignoreUntil = 0;

const giftBuffer = new Map();
const recentGifts = [];

function flushGiftBuffer() {
const now = Date.now();
for (const [key, gift] of giftBuffer.entries()) {
if (now - gift.lastUpdated >= 1500) {
const duplicate = recentGifts.find(g =>
g.userId === gift.userId &&
g.giftId === gift.giftId &&
g.count === gift.count &&
now - g.time < 20000
);

    if (duplicate) {
      giftBuffer.delete(key);
      continue;
    }

    recentGifts.push({
      userId: gift.userId,
      giftId: gift.giftId,
      count: gift.count,
      time: now
    });
    if (recentGifts.length > 100) recentGifts.shift();

    const ruGift = getGiftTranslation(gift.giftName);
    const readableGift = declineGift(ruGift, gift.count);
    const verbalGift = verbalDeclineGift(ruGift, gift.count);
    const voiceLine = `${verbalizeNick(gift.nickname)} дарит ${verbalGift}`;

    const msg = {
      Type: "Live",
      Data: {
        ShowInChat: false,
        Type: "Donation",
        CurrencyType: "TikTok",
        Currency: "TikTok",
        Tag: 101,
        Service: "MiniChat",
        UserID: gift.userId,
        UserName: "Подарок",
        Meta: { Login: gift.uniqueId },
        Message: `${gift.nickname} дарит ${readableGift}`,
        VoiceText: voiceLine
      }
    };

    minichatWS.send(JSON.stringify(msg));
    console.log(`🎁 Donation from ${gift.nickname}: ${readableGift}`);
    giftBuffer.delete(key);
  }
}

}

setInterval(flushGiftBuffer, 1000);

tiktok.connect()
.then(() => {
console.log(📡 Connected to TikTok @${tiktokUsername});
isConnected = true;
ignoreUntil = Date.now() + 3000;
})
.catch(err => console.error('❌ TikTok error:', err));

tiktok.on('chat', data => {
if (!isConnected || minichatWS.readyState !== WebSocket.OPEN) return;
if (Date.now() < ignoreUntil) return;

const comment = data.comment?.trim();
if (!comment) return;

const rawNick = data.nickname || data.uniqueId || '';

const msg = {
  Type: "Message",
  Data: {
    ShowInChat: true,
    UserID: data.userId?.toString() || "0",
    UserName: rawNick,
    Message: comment,
    Service: "MiniChat"
  }
};

try {
  minichatWS.send(JSON.stringify(msg));
  console.log(`💬 Chat: ${rawNick}: ${comment}`);
} catch (err) {
  console.error('❌ Error sending message to Minichat:', err.message);
}

});

tiktok.on('gift', data => {
if (minichatWS.readyState !== WebSocket.OPEN) return;

const userId = data.userId?.toString() || "0";
const giftId = data.giftId?.toString() || "0";
const key = `${userId}_${giftId}`;

const nickname = data.nickname || data.uniqueId || '';
const giftName = data.giftName || "gift";
const giftCount = data.repeatCount || 1;

if (!giftBuffer.has(key)) {
  giftBuffer.set(key, {
    userId,
    uniqueId: data.uniqueId,
    giftId,
    nickname,
    giftName,
    count: giftCount,
    lastUpdated: Date.now()
  });
} else {
  const entry = giftBuffer.get(key);
  entry.count = giftCount;
  entry.lastUpdated = Date.now();
}

});
});

minichatWS.on('error', err => {
console.error('❌ Minichat WebSocket error:', err.message);
});

minichatWS.on('close', () => {
console.log('⚠️ Minichat WebSocket closed');
});

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions