Skip to content

Instantly share code, notes, and snippets.

@nvckai
Last active October 31, 2026 01:40
Show Gist options
  • Select an option

  • Save nvckai/b258c253fa00e4300888f5cb13a905b5 to your computer and use it in GitHub Desktop.

Select an option

Save nvckai/b258c253fa00e4300888f5cb13a905b5 to your computer and use it in GitHub Desktop.
Discord Game Time Badge Spoofer

Discord Game Time Badge Spoofer (5000 Hours)

How to use

  1. Open Discord client, press Ctrl + Shift + I to open DevTools (Discord client only, Browser is not supported)
  2. Go to Console tab
  3. Type allow pasting and press Enter
  4. Paste the snippet below and press Enter

Snippet

(async () => {
  'use strict';

  if (typeof window.webpackChunkdiscord_app === 'undefined') {
    console.error('[spoofer] discord desktop client required');
    return;
  }

  const config = {
    totalHours: 6000, // target total playtime hours (e.g. 5000, 10000)
    titles: 250,
    batchSize: 25,
    delay: 450,
    wobble: false,
    dryRun: false
  };

  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
  const randomId = () => crypto.randomUUID();

  const wp = webpackChunkdiscord_app.push([[Symbol()], {}, (r) => r]);
  webpackChunkdiscord_app.pop();

  let rest = null;
  try {
    const entry = Object.entries(wp.m).find(([_, fn]) => fn.toString().includes('HTTPUtils'));
    if (entry) {
      const exp = wp(entry[0]);
      rest = Object.values(exp).find((e) => typeof e?.del === 'function' && typeof e?.get === 'function' && typeof e?.post === 'function') || exp;
    }
  } catch (_) {}

  if (!rest) {
    for (const mod of Object.values(wp.c)) {
      if (!mod?.exports) continue;
      const candidates = [mod.exports, mod.exports.default, ...Object.values(mod.exports)];
      for (const target of candidates) {
        if (target && typeof target?.get === 'function' && typeof target?.del === 'function' && typeof target?.post === 'function') {
          rest = target;
          break;
        }
      }
      if (rest) break;
    }
  }

  if (!rest) {
    console.error('[spoofer] failed to resolve rest module');
    return;
  }

  let analyticsToken = null;
  let username = 'user';
  let userId = '';

  try {
    const me = await rest.get({ url: '/users/@me', query: { with_analytics_token: true } });
    analyticsToken = me.body?.analytics_token;
    username = me.body?.username || 'user';
    userId = me.body?.id || '';
    if (!analyticsToken) throw new Error('token missing');
  } catch (err) {
    console.error('[spoofer] failed to fetch analytics token', err);
    return;
  }

  const generateFingerprint = async (uid) => {
    const enc = new TextEncoder();
    const sha256 = async (data) => new Uint8Array(await crypto.subtle.digest('SHA-256', data));
    const guid = randomId();
    const machineUserHash = await sha256(enc.encode(guid + uid));
    const headerHash = await sha256(enc.encode('pe_header_' + uid));
    const sectionHash = await sha256(enc.encode('pe_section_' + uid));
    const certHash = await sha256(enc.encode('pe_cert_' + uid));

    const buf = new Uint8Array(146);
    const view = new DataView(buf.buffer);
    buf[0] = 1;
    buf[1] = 1;
    view.setBigUint64(2, 65432100n, true);
    view.setUint32(10, 1690000000, true);
    view.setUint32(14, 0x02500000, true);
    buf.set(headerHash, 18);
    buf.set(machineUserHash, 50);
    buf.set(sectionHash, 82);
    buf.set(certHash, 114);

    const key = await sha256(enc.encode(uid + 'https://discord.com/careers'));
    for (let i = 1; i < buf.length; i++) {
      buf[i] ^= key[(i - 1) & 31];
    }

    let binary = '';
    for (let i = 0; i < buf.length; i++) binary += String.fromCharCode(buf[i]);
    return btoa(binary);
  };

  const fingerprint = await generateFingerprint(userId);

  let rawCatalog = [];
  try {
    const res = await rest.get({ url: '/applications/detectable' });
    rawCatalog = res.body || [];
  } catch (_) {
    try {
      const res = await fetch('https://cdn.discordapp.com/detectables/games.json');
      rawCatalog = await res.json();
    } catch (err) {
      console.error('[spoofer] failed to load game catalog', err);
      return;
    }
  }

  const catalog = [];
  const seen = new Set();

  for (const item of rawCatalog) {
    if (!item?.id || seen.has(item.id)) continue;
    const winExe = item.executables?.find((e) => e?.os === 'win32')?.name;
    if (!winExe && (!item.executables || item.executables.length > 0)) continue;
    const exe = winExe || `${item.name.replace(/[^a-zA-Z0-9]/g, '').toLowerCase() || 'game'}.exe`;
    seen.add(item.id);
    catalog.push({ id: String(item.id), name: item.name, exe });
  }

  if (!catalog.length) {
    console.error('[spoofer] no valid win32 games found');
    return;
  }

  const selected = catalog.sort(() => Math.random() - 0.5).slice(0, Math.min(config.titles, catalog.length));
  const hoursPerGame = config.totalHours / Math.max(1, selected.length);

  console.log(`[spoofer] connected as ${username} | fingerprint bound | target: ${config.totalHours}h across ${selected.length} games (~${hoursPerGame.toFixed(1)}h/game)`);

  window.__gameTimeForgeActive = true;
  window.__stopGameTimeForge = () => {
    window.__gameTimeForgeActive = false;
    console.warn('[spoofer] stopped by user');
  };

  const session = {
    heartbeatId: randomId(),
    signature: randomId(),
    seq: 0
  };

  const buildLaunch = (game, timestamp) => ({
    type: 'launch_game',
    properties: {
      client_track_timestamp: timestamp,
      client_heartbeat_session_id: session.heartbeatId,
      event_sequence_number: ++session.seq,
      game: game.name,
      game_id: game.id,
      verified: true,
      elevated: false,
      is_launcher: false,
      game_platform: 'desktop',
      detection_method: 'verified_game',
      is_overlay_enabled: false,
      is_overlay_game_enabled: true,
      is_overlay_game_source: 'OOP_DEFAULT_DATABASE',
      fullscreen_type: 'UNKNOWN',
      hardware_display_count: 1,
      overlay_method: 'Disabled',
      activity_status_enabled: true,
      activity_status_shared_guilds: [],
      current_user_status: 'online',
      game_detection_enabled: true,
      executable_path: game.exe,
      voice_channel_id: null,
      voice_channel_type: null,
      voice_channel_bitrate: null,
      voice_channel_guild_id: null,
      hidden_by_distributor: false,
      game_metadata: null,
      executable_fingerprint: fingerprint,
      client_performance_cpu: null,
      client_performance_memory: null,
      cpu_core_count: null,
      accessibility_features: 0,
      rendered_locale: 'en-US',
      launch_signature: session.signature,
      client_rtc_state: null,
      client_app_state: 'focused',
      client_send_timestamp: timestamp
    }
  });

  const buildHeartbeat = (game, durationMs, sid, initial, final, timestamp) => ({
    type: 'running_game_heartbeat',
    properties: {
      client_track_timestamp: timestamp,
      client_heartbeat_session_id: session.heartbeatId,
      event_sequence_number: ++session.seq,
      game_id: game.id,
      game_name: game.name,
      game_metadata: null,
      game_executable: game.exe,
      game_detection_enabled: true,
      initial_heartbeat: initial,
      final_heartbeat: final,
      game_session_id: sid,
      duration_tracked_ms: durationMs,
      rtc_connection_id: null,
      media_session_id: null,
      launch_signature: session.signature,
      client_app_state: 'focused',
      client_send_timestamp: timestamp
    }
  });

  const buildTriplet = (game, baseHours) => {
    const drift = config.wobble ? 1 + (Math.random() * 0.06 - 0.03) : 1;
    const hours = Math.max(0.1, baseHours * drift);
    const durationMs = Math.floor(hours * 3600 * 1000);
    const now = Date.now();
    const start = now - durationMs;
    const sid = randomId();

    return {
      hours,
      events: [
        buildHeartbeat(game, 0, sid, true, false, start),
        buildLaunch(game, now),
        buildHeartbeat(game, durationMs, sid, false, true, now)
      ]
    };
  };

  let loggedHours = 0;
  let forgedCount = 0;
  const totalBatches = Math.ceil(selected.length / config.batchSize);

  for (let i = 0; i < totalBatches; i++) {
    if (!window.__gameTimeForgeActive) break;

    const chunk = selected.slice(i * config.batchSize, (i + 1) * config.batchSize);
    const events = [];
    let chunkHours = 0;

    for (const game of chunk) {
      const triplet = buildTriplet(game, hoursPerGame);
      events.push(...triplet.events);
      chunkHours += triplet.hours;
    }

    if (config.dryRun) {
      forgedCount += chunk.length;
      loggedHours += chunkHours;
      console.log(`[spoofer] [dry-run] batch ${i + 1}/${totalBatches} (${chunkHours.toFixed(1)}h)`);
    } else {
      try {
        const res = await rest.post({
          url: '/science',
          body: { token: analyticsToken, events }
        });

        if (res?.status === 204 || res?.status === 200 || res?.ok) {
          forgedCount += chunk.length;
          loggedHours += chunkHours;
          console.log(`[spoofer] batch ${i + 1}/${totalBatches} sent (+${chunkHours.toFixed(1)}h)`);
        } else {
          console.warn(`[spoofer] batch ${i + 1}/${totalBatches} response: ${res?.status}`);
        }
      } catch (err) {
        console.error(`[spoofer] batch ${i + 1}/${totalBatches} failed`, err);
        if (err?.status === 429) {
          console.warn('[spoofer] rate limited, cooling down 5s...');
          await sleep(5000);
        }
      }
    }

    const jitter = config.delay + Math.floor((Math.random() - 0.5) * 150);
    await sleep(Math.max(100, jitter));
  }

  delete window.__gameTimeForgeActive;
  console.log(`[spoofer] done: ${forgedCount}/${selected.length} games forged | total playtime: ${loggedHours.toFixed(1)}h`);
})();

Notes

  • Breaks Discord ToS — your account, your risk

Support Server

@b1n90v

b1n90v commented Oct 30, 2026

Copy link
Copy Markdown

almost 4 days later and still nothing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment