TokElementsDOCS
SDK WIDGETS / V1
01

Premiers pas

1
Écris le balisage et le style

Les onglets HTML et CSS dessinent ton widget. La zone est transparente et flotte au-dessus de la vidéo : ne peins jamais un fond opaque sur toute la surface.

2
Réagis aux événements

Dans l’onglet JS, abonne-toi avec TE.on('gift', fn). window.TE est déjà chargé : pas d’import, pas de configuration.

3
Teste et ajoute

Utilise Simuler ou les boutons Déclencher pour prévisualiser hors ligne, puis Ajouter à l’overlay, ou laisse Claude le créer via MCP.

Ton premier widget : un shout-out pour les cadeaux· modifie le JS, l’aperçu réagit en direct
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');
});
Aperçu live
02

Connecter Claude (MCP)

Crée et modifie ces widgets directement depuis Claude Desktop ou Claude Code. Génère un jeton, ajoute le connecteur, et Claude peut appeler ces outils sur ton compte :

get_docsLe guide complet de création + chaque déclencheur et action (Claude le lit en premier).
list_widgetsListe tes widgets enregistrés avec leurs ids.
get_widgetRécupère le html / css / js d’un widget.
create_widgetCrée un nouveau widget HTML à partir d’un nom + html/css/js.
update_widgetModifie un widget existant.
delete_widgetSupprime un widget par son id.
list_templatesListe les modèles intégrés à copier.
get_templateLit le html/css/js d’un modèle.
create_from_templateCopie un modèle dans un nouveau widget.
list_community_templatesParcourt les widgets publiés par la communauté.
install_community_templateInstalle un fork privé et modifiable d’un modèle de la communauté.
Chargement…
03

Le SDK TE

Tout ce que fait un widget passe par l’objet global window.TE.

TE.on(type, fn)

S’abonne à un événement live. `type` est l’un des déclencheurs ci-dessous ; `fn(ev)` s’exécute à chaque fois.

TE.on('*', fn)

Capte tous les événements. `fn(ev, type)` reçoit le contenu et le nom de l’événement.

TE.off(type, fn)

Retire un handler enregistré précédemment.

TE.onGift(name, fn)

Ne se déclenche que pour les cadeaux dont le nom correspond (sous-chaîne, sans tenir compte de la casse). Omets `name` pour capter tous les cadeaux.

TE.onSticker(idOrUrl, fn)

Ne se déclenche que pour une emote / un sticker d’abonné précis, identifié par son id TikTok, l’URL de son image ou sa source.

TE.rules.allowUser / allowGift

Filtres d’éligibilité réutilisables pour les rôles, listes d’autorisation/de blocage, nom du cadeau et valeur minimale en pièces.

TE.metrics

Le dernier instantané du stream (viewers, likes, coins, followers, topGifters…). Également envoyé via TE.on('metrics', fn).

TE.demo

Vrai là où le widget est mis en vitrine (galerie, vignettes d’aperçu, interrupteur Démo du builder). Faux sur un overlay live et pendant tes tests dans le builder ou l’éditeur d’overlay, où n’apparaît que ce que tu déclenches ou ce qui arrive en direct. Chaque widget s’y présente lui-même : place des exemples qui ressemblent à de vrais événements (vrais visuels de cadeaux, noms, avatars) dans un bloc if (TE.demo), en passant par le vrai code du widget. Un widget qui a un tel bloc ne reçoit aucun événement d’aperçu de l’hôte, donc rien ne se déclenche deux fois.

TE.defineSettings([...])

Déclare des contrôles réglables par le streamer ; renvoie les valeurs actuelles (valeurs par défaut fusionnées avec les choix du streamer).

TE.settings

L’objet des valeurs de réglages actuelles (même forme que ce que renvoie defineSettings).

TE.on('settings', fn)

S’exécute quand le streamer modifie un réglage en direct : réaffiche avec les nouvelles valeurs.

TE.state.get/set/increment

Valeurs atomiques basées sur des Promises, pour les totaux et l’état de jeu partagé.

TE.collection.*

Participants inscrits une seule fois et tableaux de scores gérés côté serveur : join, increment, list, count, remove et clear.

TE.queue.*

Files FIFO bornées gérées côté serveur pour les médias, les demandes et les actions déclenchées par les viewers.

TE.shared.*

Fait partager à plusieurs widgets un même espace d’état de chaîne nommé ; les widgets sans lien restent isolés.

TE.random.draw(name, opts)

Tire au sort un ou plusieurs gagnants dans une collection de façon sécurisée et enregistre le résultat.

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

Réserve de façon atomique un cooldown global ou par utilisateur ; renvoie claimed et retryAfterMs.

TE.timer.*

Démarre, met en pause, réinitialise et lit un minuteur persistant en temps réel qui survit aux rechargements.

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

Vérifie et débite des points en une seule transaction ; vérifie toujours result.ok avant de lancer une interaction payante.

04

Déclencheurs

Les événements live que tu peux écouter. Chaque user contient { id, name, username, avatar, roles }.

TE.on('gift')

Un viewer a envoyé un cadeau. coins = total du combo ; streakEnd indique la fin du combo.

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

Un viewer a suivi le compte.

{ user }
TE.on('subscribe')

Un viewer s’est abonné. months = nombre de mois consécutifs.

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

Un viewer a partagé le live.

{ user }
TE.on('chat')

Un message du chat. emotes = URL des images d’emotes d’abonné présentes dans ce message.

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

Un viewer a envoyé des likes. count = cette rafale ; total = total cumulé.

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

Un viewer est entré dans le live. isTop = un top donateur est arrivé.

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

Une emote d’abonné ou un sticker à l’écran envoyé en live. url = l’image de l’emote ; id = son id TikTok.

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

Le dernier instantané du stream. TE.metrics le contient ; l’événement se déclenche à chaque mise à jour. hostNick et hostAvatar sont le nom et la photo de profil du streamer.

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

Un palier rond a été franchi (likes, pièces, followers, abonnés).

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

Le sondage live natif de TikTok : de vrais votes, du début à la fin.

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

Mises à jour des battles LinkMic : cartes de battle, tickets de fans, taille des armées.

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

Position dans le classement horaire et moments de montée au classement.

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

Une enveloppe rouge / un coffre au trésor lâché dans le live.

{ }
TE.on('pinned')

L’hôte a épinglé un commentaire.

{ text }
TE.on('deleted')

Un modérateur a supprimé un message du chat (l’id correspond à l’événement chat précédent).

{ id }
TE.on('streamState')

Le stream est passé en ligne ou hors ligne.

{ live }
TE.on('apiEvent')

Un événement personnalisé envoyé via l’Event API. Écoute apiEvent ou directement son nom personnalisé.

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

Le morceau Spotify actuel du streamer PLUS la file des prochains titres. Se déclenche à la connexion et dès que le morceau, l’état de lecture, la progression ou la file change. playback vaut null quand rien ne joue ; queue contient les prochains titres.

{ connected, playback: { isPlaying, progressMs, durationMs, title, artists:[…], album, artwork|null } | null, queue:[{ title, artist, artwork|null, durationMs }] }
Un seul cadeau ou une seule emote précise
TE.onGift('Rose', function (ev) { /* … */ });
TE.onSticker('<sticker id>', function (ev) { /* … */ });

Les emotes de ta chaîne se trouvent dans le créateur de widgets : ouvre Simuler des événements, choisis Sticker et sélectionnes-en une. L’événement de test contient son vrai id et l’URL de sa vraie image, donc un handler basé sur l’un ou l’autre est testé avec la vraie emote.

05

Actions

Ce que ton widget peut faire en réponse : de simples API du navigateur, prêtes à coller.

Afficher une image

Fais apparaître une image à l’écran : le visuel du cadeau / de l’emote, un fichier uploadé ou n’importe quelle URL. Disparaît automatiquement après quelques secondes.

// 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
});
Jouer un son

Joue un son sur un événement. Expose un réglage sound pour que le streamer choisisse son propre fichier, sans toucher au code.

// 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(); }
});
Afficher / animer du texte

Écris du texte dynamique et relance une animation CSS en basculant une 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');
});
Afficher une stat live

Relie un nombre à l’écran à une métrique live (viewers, likes, pièces, followers), mise à jour automatiquement.

// Keep a number in sync with the live stream
TE.on('metrics', function (m) {
  document.getElementById('count').textContent = m.viewers.toLocaleString();
});
Lire à voix haute (TTS)

Fais lire un événement par la synthèse vocale du navigateur. Idéal pour les shout-outs de cadeaux ou de 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);
});
Aperçu (TE.demo)

Chaque widget se présente lui-même dans la galerie et le builder : des exemples qui ressemblent à de vrais événements, avec de vrais visuels de cadeaux, noms et avatars. En live, TE.demo vaut false et seuls les vrais événements apparaissent.

// 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);
}
Mémoriser des choses (TE.store)

Persistance synchrone simple pour l’état visuel. Utilise le runtime transactionnel pour les participants, les achats et les scores partagés.

// 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();
});
Réagir aux commandes du chat

Des commandes de chat en correspondance exacte et des collections atomiques permettent des inscriptions, votes et tirages fiables.

// 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);
  });
});
Déclencher des actions de stream (TE.act)

Demande des alertes d’overlay, des sons, du TTS, des compteurs, du temps de subathon ou des changements de scène OBS directement depuis un widget.

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

Vérifie, dépense ou attribue des points de fidélité en transaction et reçois le solde qui en résulte.

// 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);
  });
});
Créer des jeux équitables

État atomique, collections, tirages aléatoires sécurisés, cooldowns et minuteurs persistants, fiables même avec des sources navigateur en double.

// 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);
});
Ajouter des contrôles streamer

Expose du texte, des couleurs, des nombres, des interrupteurs : le streamer les règle en direct dans l’éditeur d’overlay, sans code.

// 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

Réglages streamer

Déclare des contrôles avec TE.defineSettings([...]) et la personne qui utilise le widget les règle en direct dans l’éditeur d’overlay, sans code. Chaque champ :

Un widget placé avec un ou plusieurs champs 'button' expose ces actions dans ses réglages, dans l’Éditeur d’overlay. Le Widget Builder affiche les mêmes boutons pour tester l’aperçu en toute sécurité pendant que tu codes.

typeaffichevaleur
'text'Champ de texte sur une lignechaîne
'number'Champ numériquenombre
'color'Sélecteur de couleurchaîne hex, ex. "#FF2E4D"
'select'Liste déroulante (nécessite options: [...])l’une des options
'toggle'Interrupteur on/offbooléen
'range'Curseur (min / max / step)nombre
'button'Bouton d’action déclaratifincrement, set ou toggle : JSON validé, jamais de code du tableau de bord
'sound'Sélecteur parmi les sons uploadés par le streamer + Uploadl’URL du fichier choisi ("" = aucun)
'image'Sélecteur parmi les images uploadées par le streamer + Uploadl’URL du fichier choisi ("" = aucune)
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();
});

Les définitions de contrôles sont des données validées. L’action d’un bouton n’accepte que increment, set ou toggle. Le HTML, le code de callback et les URL arbitraires sont rejetés ou ignorés par le rendu du tableau de bord.

07

Bac à sable et limites

Les widgets tournent dans une iframe isolée avec une politique de sécurité du contenu stricte : un widget cassé ou malveillant ne peut jamais toucher à ton compte ni au reste de la page.

Autorisé
  • Images et GIF distants (visuels de cadeaux TikTok, avatars, n’importe quelle URL)
  • Google Fonts + tes propres @font-face
  • Audio via new Audio(url)
  • Requêtes vers les propres API de TokElements (ex. /api/files/…)
  • Animations CSS, SVG, canvas, Web Audio
Bloqué
  • Balises <script> externes / CDN
  • fetch / XHR / WebSocket vers d’autres hôtes
  • Cookies, localStorage, accès à la page parente
  • Chargement de paquets npm
08

Exemples

Des widgets complets, à copier-coller. Chaque aperçu est live : des événements de démo se déclenchent pour que tu le voies réagir.

Réaction aux emotes· affiche l’emote quand elle est envoyée dans le 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');
});
Aperçu live
Barre d’objectif de followers· relie une barre à une métrique live
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;
});
Aperçu live