Skip to content

Ranking User Data

Use ranking for an open-ended question whose result is the frequency of each exact text response. For a given ranking ID, the service keeps one current answer per viewer identity and returns matching strings with a numeric score.

Ranking does not normalize spelling, capitalization, whitespace, aliases, or unsafe text. Your application owns input rules and display safety.

Define one round

Give every question run a distinct ID. A stable pattern such as next-game-2026-07-14-round-3 prevents late requests from one round changing another round's results.

Normalize only the differences your product wants to collapse:

function normalizeAnswer(value) {
  return value.trim().replace(/\s+/g, " ").toLocaleLowerCase("en-US");
}

If DOTA, dota, and Dota should be separate answers, submit the original string instead. Apply a length limit and reject empty input before making the request.

Submit an answer

After MEDKit is ready, call rank(rankID, value) from the viewer context:

const rankID = "next-game-2026-07-14-round-3";
const answer = normalizeAnswer(answerInput.value);

if (!answer || answer.length > 80) {
  throw new Error("Enter an answer between 1 and 80 characters.");
}

const result = await medkit.rank(rankID, answer);
if (!result.accepted) {
  throw new Error("The ranking service did not accept the answer.");
}

if (result.original !== undefined) {
  console.log(`Previous answer replaced: ${result.original}`);
}

original is optional and contains the viewer's previous value when the new submission replaces it. Do not treat a repeated submission as an extra vote.

Read and display results

getRankData(rankID) requires a privileged broadcaster, admin, or backend context. MEDKit 2.4.18 resolves with an object whose data property contains the scored values:

const { data } = await medkit.getRankData(rankID);

const results = data.map(({ key, score }) => ({
  label: key,
  responses: score,
}));

renderRanking(results);

Treat every key as untrusted viewer text. Render it with textContent or your framework's escaped text binding, not innerHTML. The API returns scores in service order; preserve that order unless your product defines and documents its own tie-break.

End or recover a round

A broadcaster can clear the selected buffer with clearRankData(rankID):

await medkit.clearRankData(rankID);

Clearing is destructive. Prefer a new round ID when you need an audit trail or when late clients may still submit to the previous question. If a read fails, keep the last known result on screen, show that it is stale, and retry with backoff instead of clearing the buffer.

Identity and retention constraints

  • Ranking uniqueness follows the identity in the caller's JWT. A shared Twitch ID and an opaque ID are different identifiers, so identity changes can affect one-response-per-viewer behavior.
  • Require shared identity only when your product needs stronger cross-session identity, and explain that requirement to viewers.
  • The service compares submitted strings; moderation, normalization, profanity handling, and localization are application responsibilities.
  • The pinned MEDKit declarations and OpenAPI contract do not guarantee a top-N size or automatic retention period. Do not build correctness around legacy claims of 100 results or one-day expiry.
  • The pinned sources do not define an extension-wide global ID prefix. Treat IDs as ordinary buffer names unless the API owner confirms additional deployment behavior.

For raw HTTP requests and role requirements, see Basic Ranking.