TokElementsDOCS
SDK DE WIDGETS / V1
01

Primeiros passos

1
Escreva o markup e o estilo

As abas HTML e CSS desenham seu widget. A caixa é transparente e flutua sobre o vídeo — nunca pinte um fundo opaco em tela cheia.

2
Reaja a eventos

Na aba JS, assine com TE.on('gift', fn). O window.TE já está carregado — sem imports, sem configuração.

3
Teste e adicione

Use Simular ou os botões Disparar para ver a prévia offline, depois Adicionar ao overlay — ou deixe o Claude criar via MCP.

Seu primeiro widget — um agradecimento por presente· edite o JS, a prévia reage ao vivo
var box = document.getElementById('box');
TE.on('gift', function (ev) {
  box.textContent = ev.user.name + ' sent ' + ev.gift.name + '!';
  box.classList.remove('pop'); void box.offsetWidth; box.classList.add('pop');
});
Prévia ao vivo
02

Conectar o Claude (MCP)

Crie e edite estes widgets direto do Claude Desktop ou do Claude Code. Gere um token, adicione o conector, e o Claude pode chamar estas ferramentas na sua conta:

get_docsO guia completo de criação + todos os gatilhos e ações (o Claude lê isto primeiro).
list_widgetsLista seus widgets salvos com os ids.
get_widgetBusca o html / css / js de um widget.
create_widgetCria um novo widget HTML a partir de nome + html/css/js.
update_widgetEdita um widget existente.
delete_widgetApaga um widget pelo id.
list_templatesLista os templates embutidos para copiar.
get_templateLê o html/css/js de um template.
create_from_templateCopia um template para um novo widget.
list_community_templatesNavega pelos widgets publicados pela comunidade.
install_community_templateInstala um fork privado e editável de um template da comunidade.
Carregando…
03

O SDK TE

Tudo o que um widget faz passa pelo objeto global window.TE.

TE.on(type, fn)

Assina um evento ao vivo. `type` é qualquer gatilho abaixo; `fn(ev)` roda toda vez que ele acontece.

TE.on('*', fn)

Pega todos os eventos. `fn(ev, type)` recebe o payload e o nome do evento.

TE.off(type, fn)

Remove um handler registrado antes.

TE.onGift(name, fn)

Dispara só para presentes cujo nome bate (trecho, sem diferenciar maiúsculas). Omita `name` para pegar todos os presentes.

TE.onSticker(idOrUrl, fn)

Dispara só para um emote / sticker de assinante específico — identificado pelo id do TikTok, URL da imagem ou origem.

TE.rules.allowUser / allowGift

Filtros de elegibilidade reutilizáveis para cargos, listas de permissão/bloqueio, nome do presente e valor mínimo em moedas.

TE.metrics

O objeto com o snapshot mais recente da live (viewers, likes, coins, followers, topGifters…). Também entregue via TE.on('metrics', fn).

TE.demo

Verdadeiro onde o widget está em exibição (galeria, miniaturas de prévia, a chave Demo do builder). Falso num overlay ao vivo e enquanto você testa no builder ou no editor de overlay, onde só aparece o que você dispara ou o que chega ao vivo. Todo widget se mostra ali: coloque exemplos que parecem eventos reais (arte real dos presentes, nomes, avatares) num bloco if (TE.demo), pelo caminho de código real do widget. Um widget com esse bloco não recebe eventos de prévia do host, então nada dispara duas vezes.

TE.defineSettings([...])

Declara controles que o streamer pode ajustar; retorna os valores atuais (padrões mesclados com as escolhas do streamer).

TE.settings

O objeto com os valores atuais das configurações (mesmo formato que defineSettings retornou).

TE.on('settings', fn)

Roda quando o streamer muda uma configuração ao vivo — renderize de novo com os novos valores.

TE.state.get/set/increment

Valores atômicos baseados em Promise para totais e estado compartilhado de jogos.

TE.collection.*

Participantes de entrada única e tabelas de pontuação guardados no servidor: join, increment, list, count, remove e clear.

TE.queue.*

Filas FIFO limitadas no servidor para mídia, pedidos e ações disparadas por viewers.

TE.shared.*

Coloca vários widgets num mesmo namespace de estado do canal; widgets não relacionados continuam isolados.

TE.random.draw(name, opts)

Sorteia com segurança um ou mais vencedores de uma coleção e registra o resultado.

TE.cooldown.claim(scope, user, ms)

Reivindica atomicamente um cooldown global ou por usuário; retorna claimed e retryAfterMs.

TE.timer.*

Inicia, pausa, reinicia e lê um timer de relógio persistente que sobrevive a recarregamentos.

TE.points.trySpend(user, amount, reason)

Verifica e debita pontos numa única transação; sempre confira result.ok antes de rodar uma interação paga.

04

Gatilhos

Eventos ao vivo que você pode escutar. Todo user contém { id, name, username, avatar, roles }.

TE.on('gift')

Um viewer enviou um presente. coins = total do combo; streakEnd marca o fim do combo.

{ user, gift: { name, image|null, coins, repeat, combo, streakEnd } }
TE.on('follow')

Um viewer seguiu a conta.

{ user }
TE.on('subscribe')

Um viewer assinou. months = quantos meses seguidos.

{ user, months }
TE.on('share')

Um viewer compartilhou a live.

{ user }
TE.on('chat')

Uma mensagem do chat. emotes = URLs das imagens de emotes de assinante nesta mensagem.

{ user, comment, emotes:[url,…] }
TE.on('like')

Um viewer mandou likes. count = esta rajada; total = total acumulado.

{ user, count, total }
TE.on('join')

Um viewer entrou na sala. isTop = entrou um dos maiores doadores.

{ user, isTop }
TE.on('sticker')

Um emote de assinante ou sticker na tela enviado ao vivo. url = a imagem do emote; id = o id dele no TikTok.

{ user|null, id|null, url, source }
TE.on('metrics')

O snapshot mais recente da live. TE.metrics guarda ele; o evento dispara sempre que atualiza. hostNick e hostAvatar são o nome e a foto de perfil do próprio streamer.

{ live, viewers, likes, followers, coins, hostNick, hostAvatar, topGifters:[…], … }
TE.on('milestone')

Um marco redondo foi ultrapassado (likes, moedas, seguidores, assinantes).

{ metric, value, label }
TE.on('poll')

A enquete nativa da live do TikTok — votos reais, do início ao fim.

{ state:'start'|'update'|'end', title, options:[{text,votes}], endsAt }
TE.on('battle')

Atualizações de batalha LinkMic: cartas de batalha, fan tickets, tamanho dos exércitos.

{ card|null, tickets|null, armies|null, battleId|null }
TE.on('rank')

Posição no ranking por hora e momentos de subida.

{ rank|null, from|null, to|null, countdown|null }
TE.on('envelope')

Um envelope vermelho / baú do tesouro caiu na live.

{ }
TE.on('pinned')

O host fixou um comentário.

{ text }
TE.on('deleted')

Um moderador removeu uma mensagem do chat (id bate com o evento de chat anterior).

{ id }
TE.on('streamState')

A live ficou online ou offline.

{ live }
TE.on('apiEvent')

Um evento personalizado enviado pela Event API. Escute apiEvent ou direto o nome personalizado dele.

{ name, data }
TE.on('nowPlaying')

A música atual do Spotify do streamer MAIS a fila do que vem a seguir. Dispara ao conectar e sempre que a música, o estado de reprodução, o progresso ou a fila mudam. playback é null quando nada está tocando; queue são as próximas faixas.

{ connected, playback: { isPlaying, progressMs, durationMs, title, artists:[…], album, artwork|null } | null, queue:[{ title, artist, artwork|null, durationMs }] }
Só um presente ou emote específico
TE.onGift('Rose', function (ev) { /* … */ });
TE.onSticker('<sticker id>', function (ev) { /* … */ });

Os emotes do seu canal ficam no criador de widgets: abra Simular eventos, escolha Sticker e selecione um. O evento de teste traz o id e a URL da imagem reais, então um handler baseado em qualquer um dos dois é testado com a coisa real.

05

Ações

O que o seu widget pode fazer em resposta — APIs comuns do navegador, prontas para colar.

Mostrar uma imagem

Coloque uma imagem na tela — a arte do presente/emote, um arquivo enviado ou qualquer URL. Some sozinha depois de alguns segundos.

// Show an image, then fade it out
TE.on('gift', function (ev) {
  var img = document.createElement('img');
  img.src = ev.gift.image;                 // ← any image URL works
  img.style.cssText = 'position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);max-width:60%';
  document.body.appendChild(img);
  setTimeout(function () { img.remove(); }, 4000);   // ← how long it stays
});
Tocar um som

Toque um áudio num evento. Exponha uma configuração de som para o streamer escolher o próprio arquivo — sem editar código.

// Play a sound the streamer chose in settings
var s = TE.defineSettings([{ key: 'sfx', label: 'Alert sound', type: 'sound', default: '' }]);
TE.on('settings', function (ns) { s = ns; });
TE.on('gift', function (ev) {
  if (s.sfx) { var a = new Audio(s.sfx); a.volume = 0.8; a.play(); }
});
Mostrar / animar texto

Escreva texto dinâmico e dispare de novo uma animação CSS alternando uma classe.

// Announce the event with a CSS pop animation
var box = document.getElementById('box');   // your element in the HTML tab
TE.on('follow', function (ev) {
  box.textContent = ev.user.name + ' followed!';
  box.classList.remove('pop'); void box.offsetWidth; box.classList.add('pop');
});
Mostrar uma estatística ao vivo

Ligue um número na tela a uma métrica ao vivo — viewers, likes, moedas, seguidores — atualizado automaticamente.

// Keep a number in sync with the live stream
TE.on('metrics', function (m) {
  document.getElementById('count').textContent = m.viewers.toLocaleString();
});
Ler em voz alta (TTS)

Fale um evento com o texto para fala do navegador. Ótimo para agradecer presentes ou follows.

// Text-to-speech shout-out
TE.on('gift', function (ev) {
  var u = new SpeechSynthesisUtterance(ev.user.name + ' sent ' + ev.gift.name);
  speechSynthesis.speak(u);
});
Prévia (TE.demo)

Todo widget se mostra na galeria e no builder: exemplos que parecem eventos reais, com arte real dos presentes, nomes e avatares. Ao vivo, TE.demo é falso e só aparecem eventos reais.

// Preview samples through the real code path. Never on a live overlay.
if (TE.demo) {
  var GIFTS = [
    { name: 'Rose', coins: 1, image: 'https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/eba3a9bb85c33e017f3648eaf88d7189~tplv-obj.png' },
    { name: 'Perfume', coins: 20, image: 'https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/20b8f61246c7b6032777bb81bf4ee055~tplv-obj.png' }
  ];
  var NAMES = ['lunaa', 'nightowl_gaming_official'], n = 0;
  function sample() {
    n++;
    onGift({ user: { name: NAMES[n % 2], avatar: window.__TE_AVATAR }, gift: GIFTS[n % 2] });
  }
  sample();
  setInterval(sample, 6000);
}
Guardar coisas (TE.store)

Persistência síncrona simples para estado visual. Use o runtime transacional para participantes, compras e pontuações compartilhadas.

// Persistent state: survives OBS reloads
var total = TE.store.get('total', 0);          // read (with default)
TE.on('gift', function (ev) {
  total += ev.gift.coins;
  TE.store.set('total', total);                 // write (auto-saved)
  render();
});
Reagir a comandos do chat

Comandos de chat com correspondência exata mais coleções atômicas permitem inscrições, votos e giros seguros.

// One server-authoritative entry per viewer.
// A function keyword reads s.command on every message, so the
// streamer can change the command in settings without a reload.
TE.onCommand(function () { return s.command || '!join'; }, function (c) {
  TE.collection.join('entrants', c.user.id, c.user).then(function (result) {
    if (result.joined) renderCount(result.count);
  });
});
Disparar ações na live (TE.act)

Peça alertas do overlay, sons, TTS, contadores, tempo de subathon ou troca de cena no OBS direto de um widget.

// One call, one stream action
TE.act({ id: 'tts', message: 'New high score!' });
TE.act({ id: 'points', user: ev.user, amount: 50 });
Dar pontos aos viewers

Verifique, gaste ou dê pontos de fidelidade de forma transacional e receba o saldo resultante.

// Only spin after the points were really debited
TE.onCommand(function () { return s.command || '!spin'; }, function (ev) {
  TE.points.trySpend(ev.user, 50, 'Wheel spin').then(function (result) {
    if (result.ok) spin();
    else showMissing(result.missing);
  });
});
Criar jogos justos

Estado atômico, coleções, sorteios seguros, cooldowns e timers persistentes — seguros mesmo com fontes de navegador duplicadas.

// Fair draw from a server-owned entrant collection
TE.random.draw('entrants', { count: 1 }).then(function (result) {
  if (result.ok) reveal(result.winners[0].value);
});
Adicionar controles do streamer

Exponha textos, cores, números, chaves — o streamer ajusta ao vivo no editor de overlay, sem código.

// No-code controls for whoever uses the widget
var s = TE.defineSettings([
  { key: 'title',  label: 'Title', type: 'text',  default: 'Goal' },
  { key: 'accent', label: 'Color', type: 'color', default: '#FF2E4D' },
]);
document.body.style.setProperty('--accent', s.accent);
TE.on('settings', function (ns) { s = ns; /* re-render with new values */ });
06

Configurações do streamer

Declare controles com TE.defineSettings([...]) e quem usar o widget ajusta ao vivo no editor de overlay — sem código. Cada campo:

Um widget posicionado com um ou mais campos 'button' expõe essas ações nas configurações dele dentro do Editor de overlay. O Widget Builder mostra os mesmos botões para testar a prévia com segurança enquanto você programa.

typerenderizavalor
'text'Campo de texto de uma linhastring
'number'Campo numériconumber
'color'Seletor de corstring hex, ex. "#FF2E4D"
'select'Lista suspensa (precisa de options: [...])uma das opções
'toggle'Chave liga/desligaboolean
'range'Slider (min / max / step)number
'button'Botão de ação declarativoincrement, set ou toggle — JSON validado, nunca código do painel
'sound'Seletor dos sons enviados pelo streamer + Uploada URL do arquivo escolhido ("" = nenhum)
'image'Seletor das imagens enviadas pelo streamer + Uploada URL do arquivo escolhido ("" = nenhum)
var s = TE.defineSettings([
  { key: 'title',  label: 'Title', type: 'text',   default: 'Follower goal' },
  { key: 'target', label: 'Goal',  type: 'number', default: 100 },
  { key: 'accent', label: 'Color', type: 'color',  default: '#FF2E4D' },
  { key: 'reset',  label: 'Reset', type: 'button', default: 0,
    action: { type: 'increment', step: 1 }, confirm: true, tone: 'danger' },
]);
// re-render when the streamer changes something live
var lastReset = s.reset;
TE.on('settings', function (ns) {
  s = ns;
  if (ns.reset !== lastReset) { lastReset = ns.reset; resetCounter(); }
  render();
});

As definições de controles são dados validados. O action de um botão aceita só increment, set ou toggle. HTML, código de callback e URLs arbitrárias são rejeitados ou ignorados pelo renderizador do painel.

07

Sandbox e limites

Os widgets rodam num iframe isolado com uma política de segurança de conteúdo rígida, então um widget quebrado ou malicioso nunca consegue tocar na sua conta ou no resto da página.

Permitido
  • Imagens e GIFs remotos (arte de presentes do TikTok, avatares, qualquer URL)
  • Google Fonts + seu próprio @font-face
  • Áudio via new Audio(url)
  • Requisições às APIs do próprio TokElements (ex. /api/files/…)
  • Animações CSS, SVG, canvas, Web Audio
Bloqueado
  • Tags <script> externas / CDNs
  • fetch / XHR / WebSocket para outros hosts
  • Cookies, localStorage, acesso à página pai
  • Carregar pacotes npm
08

Exemplos

Widgets completos, para copiar e colar. Cada prévia é ao vivo — eventos de demo disparam para você ver a reação.

Reação a emote· mostra o emote quando ele é enviado no chat
var img = document.getElementById('emote');
// fires for every emote — use TE.onSticker('<id>', …) for one specific one
TE.on('sticker', function (ev) {
  img.src = ev.url;
  img.classList.remove('show'); void img.offsetWidth; img.classList.add('show');
});
Prévia ao vivo
Barra de meta de seguidores· liga uma barra a uma métrica ao vivo
var target = 200;                       // ← your goal
TE.on('metrics', function (m) {
  var pct = Math.min(100, m.follows / target * 100);
  document.getElementById('fill').style.width = pct + '%';
  document.getElementById('txt').textContent = m.follows + ' / ' + target;
});
Prévia ao vivo