dm / commit
feat: send player and game IDs as API metadata for analytics
public/index.html | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/public/index.html b/public/index.html index 910edca..94e0a64 100644 --- a/public/index.html +++ b/public/index.html @@ -1281,6 +1281,21 @@ let gameState = null; let conversationHistory = []; let isBusy = false; +// ── IDs ─────────────────────────────────────────────── +// player_id persists across games; game_id is fresh each adventure. +// Both are sent as metadata.user_id so they appear in the Anthropic +// usage dashboard for usage analytics. + +function randomId() { + return Array.from(crypto.getRandomValues(new Uint8Array(8)), b => b.toString(16).padStart(2, '0')).join(''); +} + +function getOrCreatePlayerId() { + let id = localStorage.getItem('dm_player_id'); + if (!id) { id = randomId(); localStorage.setItem('dm_player_id', id); } + return id; +} + // Pricing in USD per 1M tokens — verify at anthropic.com/pricing const MODEL_PRICING = { 'claude-haiku-4-5-20251001': { input: 0.80, output: 4.00 }, @@ -1505,6 +1520,7 @@ async function beginAdventure() { gameState = { apiKey, + gameId: randomId(), character: { name, race: selectedRace.name, @@ -1804,6 +1820,7 @@ async function sendMessage(text, showAsPlayer = true) { system: buildSystemPrompt(gameState.character, gameState.theme), tools: [UPDATE_TOOL], messages: apiMessages, + metadata: { user_id: `p_${getOrCreatePlayerId()}:g_${gameState.gameId}` }, }; console.group(`🎲 DM API call #${loopIteration} (turn ${conversationHistory.length})`);