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

@Aethe3r

Aethe3r commented Oct 25, 2026

Copy link
Copy Markdown

question, when you input the script for the game variety badge did it also show you this message after putting it in..? "rpc-spoofer] Browser is not supported. Please use Discord client :wilted_rose:." and if it didnt what am i doing wrong? 😭

it literally tells you what to do: the script doesn't work in a browser, so you have to use an actual discord client (vesktop doesn't count)

how do i input that into the discord app client, when i use the same key shortcut that it says on the page it doesnt open anything

@Ultrason11

Copy link
Copy Markdown

how do i input that into the discord app client, when i use the same key shortcut that it says on the page it doesnt open anything

use the discord ptb or use a tool to unlock the dev console on the normal build

@Aethe3r

Aethe3r commented Oct 25, 2026

Copy link
Copy Markdown

how do i input that into the discord app client, when i use the same key shortcut that it says on the page it doesnt open anything

use the discord ptb or use a tool to unlock the dev console on the normal build

alright thanks a ton!!

@Meolsei

Meolsei commented Oct 25, 2026

Copy link
Copy Markdown

Ran it yesterday, no result. Activity sharing is enabled, and the data sharing thing that it requests to allow the badge to go up is also enabled. Trying it again today.

@tomatotg1-arch

Copy link
Copy Markdown

I used it and it turned my playtime from 1682 to 1000???

@YoundLord

Copy link
Copy Markdown

how long does it usually takes for it to update

@tomatotg1-arch

Copy link
Copy Markdown

I used it and it turned my playtime from 1682 to 1000???

okay apparently it did happen then it reverted itself back, I am not trying this script again

@YoundLord

Copy link
Copy Markdown

ma shii works now lets hope we don't get hammered

@tschau3000

Copy link
Copy Markdown

for me it works

@BloodSplashx

Copy link
Copy Markdown

when running the script do i need a game opened?

@DeadGhost77

Copy link
Copy Markdown

when running the script do i need a game opened?

Nah, just leave discord open for a bit until the script ends (though I didn't try it idk what happens next) but it doesn't need any game opened

@akshitnot6-code

akshitnot6-code commented Oct 27, 2026 •

Copy link
Copy Markdown
{1FE24D18-A0C5-4D48-B6FC-DD7779C98009}

mine worked,took around 2 days :)

@majedrora9

Copy link
Copy Markdown

Hello please help I used it too much times , like 10 times, so How to stop it the hours now is 50k please some help..

@ImPotsu

ImPotsu commented Oct 28, 2026

Copy link
Copy Markdown

and what about streamed hours? i used this but only game time and variety of games change, the streamed hours keeped the same. any solution to this or another script?

@ichipaws

Copy link
Copy Markdown

does this set your game time to the hours you specified or does it just add that time to your current hours?

it will add

I accidently ran it 2 time.. lets see what happens tmrw.. lol (i dont wanna get suspended again 😭 )

u will get double the hours

make one for streaming and game collecting

if ur talking abt the game variety batch there already is one https://gist.wumpus.tools/wavedev/game-badge-spoofer

how do you change the amount of it, which line?

line 8

where in line 8?

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

if you are talking about hours its totalHours: 6000 if its about game verity its titles:250 ^ this will add more games to the badge

does the ammount of games add to the game variety badge or no?

@batsgal0re

Copy link
Copy Markdown

make one for streaming and game collecting

if ur talking abt the game variety batch there already is one https://gist.wumpus.tools/wavedev/game-badge-spoofer

where do you input the amount of game titles you want, which line?

@offxev

offxev commented Oct 30, 2026

Copy link
Copy Markdown

working

@offxev

offxev commented Oct 30, 2026

Copy link
Copy Markdown

is there a way to do this for the stream badge too

@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