## Complete Recent Discord Quest > [!NOTE] > This does not works in browser for non-video, non-activity quests! For stream/play quests use the desktop app! > [!NOTE] > When doing stream quests, you need at least 1 other account in the vc! How to use this script: 1. Accept a quest under User Settings -> Gift Inventory 2. Press Ctrl+Shift+I to open DevTools 3. Go to the `Console` tab 4. Paste the following code and hit enter:
Click to expand ```js delete window.$; let wpRequire; window.webpackChunkdiscord_app.push([[ Math.random() ], {}, (req) => { wpRequire = req; }]); let ApplicationStreamingStore = Object.values(wpRequire.c).find(x => x?.exports?.Z?.getStreamerActiveStreamMetadata).exports.Z; let RunningGameStore = Object.values(wpRequire.c).find(x => x?.exports?.ZP?.getRunningGames).exports.ZP; let QuestsStore = Object.values(wpRequire.c).find(x => x?.exports?.Z?.getQuest).exports.Z; let ChannelStore = Object.values(wpRequire.c).find(x => x?.exports?.Z?.getAllThreadsForParent).exports.Z; let GuildChannelStore = Object.values(wpRequire.c).find(x => x?.exports?.ZP?.getSFWDefaultChannel).exports.ZP; let FluxDispatcher = Object.values(wpRequire.c).find(x => x?.exports?.Z?.flushWaitQueue).exports.Z; let api = Object.values(wpRequire.c).find(x => x?.exports?.tn?.get).exports.tn; let quest = [...QuestsStore.quests.values()].find(x => x.id !== "1248385850622869556" && x.userStatus?.enrolledAt && !x.userStatus?.completedAt && new Date(x.config.expiresAt).getTime() > Date.now()) let isApp = navigator.userAgent.includes("Electron/") if(!quest) { console.log("You don't have any uncompleted quests!") } else { const pid = Math.floor(Math.random() * 30000) + 1000 const applicationId = quest.config.application.id const applicationName = quest.config.application.name const taskName = ["WATCH_VIDEO", "PLAY_ON_DESKTOP", "STREAM_ON_DESKTOP", "PLAY_ACTIVITY"].find(x => quest.config.taskConfig.tasks[x] != null) const secondsNeeded = quest.config.taskConfig.tasks[taskName].target const secondsDone = quest.userStatus?.progress?.[taskName]?.value ?? 0 if(taskName === "WATCH_VIDEO") { const tolerance = 2, speed = 10 const diff = Math.floor((Date.now() - new Date(quest.userStatus.enrolledAt).getTime())/1000) const startingPoint = Math.min(Math.max(Math.ceil(secondsDone), diff), secondsNeeded) let fn = async () => { for(let i=startingPoint;i<=secondsNeeded;i+=speed) { try { await api.post({url: `/quests/${quest.id}/video-progress`, body: {timestamp: Math.min(secondsNeeded, i + Math.random())}}) } catch(ex) { console.log("Failed to send increment of", i, ex.message) } await new Promise(resolve => setTimeout(resolve, tolerance * 1000)) } if((secondsNeeded-secondsDone)%speed !== 0) { await api.post({url: `/quests/${quest.id}/video-progress`, body: {timestamp: secondsNeeded}}) } console.log("Quest completed!") } fn() console.log(`Spoofing video for ${applicationName}. Wait for ${Math.ceil((secondsNeeded - startingPoint)/speed*tolerance)} more seconds.`) } else if(taskName === "PLAY_ON_DESKTOP") { if(!isApp) { console.log("This no longer works in browser for non-video quests. Use the desktop app to complete the", applicationName, "quest!") } api.get({url: `/applications/public?application_ids=${applicationId}`}).then(res => { const appData = res.body[0] const exeName = appData.executables.find(x => x.os === "win32").name.replace(">","") const games = RunningGameStore.getRunningGames() const fakeGame = { cmdLine: `C:\\Program Files\\${appData.name}\\${exeName}`, exeName, exePath: `c:/program files/${appData.name.toLowerCase()}/${exeName}`, hidden: false, isLauncher: false, id: applicationId, name: appData.name, pid: pid, pidPath: [pid], processName: appData.name, start: Date.now(), } games.push(fakeGame) FluxDispatcher.dispatch({type: "RUNNING_GAMES_CHANGE", removed: [], added: [fakeGame], games: games}) let fn = data => { let progress = quest.config.configVersion === 1 ? data.userStatus.streamProgressSeconds : Math.floor(data.userStatus.progress.PLAY_ON_DESKTOP.value) console.log(`Quest progress: ${progress}/${secondsNeeded}`) if(progress >= secondsNeeded) { console.log("Quest completed!") const idx = games.indexOf(fakeGame) if(idx > -1) { games.splice(idx, 1) FluxDispatcher.dispatch({type: "RUNNING_GAMES_CHANGE", removed: [fakeGame], added: [], games: []}) } FluxDispatcher.unsubscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn) } } FluxDispatcher.subscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn) console.log(`Spoofed your game to ${applicationName}. Wait for ${Math.ceil((secondsNeeded - secondsDone) / 60)} more minutes.`) }) } else if(taskName === "STREAM_ON_DESKTOP") { if(!isApp) { console.log("This no longer works in browser for non-video quests. Use the desktop app to complete the", applicationName, "quest!") } let realFunc = ApplicationStreamingStore.getStreamerActiveStreamMetadata ApplicationStreamingStore.getStreamerActiveStreamMetadata = () => ({ id: applicationId, pid, sourceName: null }) let fn = data => { let progress = quest.config.configVersion === 1 ? data.userStatus.streamProgressSeconds : Math.floor(data.userStatus.progress.STREAM_ON_DESKTOP.value) console.log(`Quest progress: ${progress}/${secondsNeeded}`) if(progress >= secondsNeeded) { console.log("Quest completed!") ApplicationStreamingStore.getStreamerActiveStreamMetadata = realFunc FluxDispatcher.unsubscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn) } } FluxDispatcher.subscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn) console.log(`Spoofed your stream to ${applicationName}. Stream any window in vc for ${Math.ceil((secondsNeeded - secondsDone) / 60)} more minutes.`) console.log("Remember that you need at least 1 other person to be in the vc!") } else if(taskName === "PLAY_ACTIVITY") { const channelId = ChannelStore.getSortedPrivateChannels()[0]?.id ?? Object.values(GuildChannelStore.getAllGuilds()).find(x => x != null && x.VOCAL.length > 0).VOCAL[0].channel.id const streamKey = `call:${channelId}:1` let fn = async () => { console.log("Completing quest", applicationName, "-", quest.config.messages.questName) while(true) { const res = await api.post({url: `/quests/${quest.id}/heartbeat`, body: {stream_key: streamKey, terminal: false}}) const progress = res.body.progress.PLAY_ACTIVITY.value console.log(`Quest progress: ${progress}/${secondsNeeded}`) await new Promise(resolve => setTimeout(resolve, 20 * 1000)) if(progress >= secondsNeeded) { await api.post({url: `/quests/${quest.id}/heartbeat`, body: {stream_key: streamKey, terminal: true}}) break } } console.log("Quest completed!") } fn() } } ```
5. Follow the printed instructions depending on what type of quest you have - If your quest says to "play" the game, you can just wait and do nothing - If your quest says to "stream" the game, join a vc with a friend or alt and stream any window 7. Wait for 15 minutes 8. You can now claim the reward in User Settings -> Gift Inventory! You can track the progress by looking at the `Quest progress:` prints in the Console tab, or by reopening the Gift Inventory tab in settings. ## FAQ **Q: Ctrl + Shift + I doesn't work** A: Either download the [ptb client](https://discord.com/api/downloads/distributions/app/installers/latest?channel=ptb&platform=win&arch=x64), or use [this](https://www.reddit.com/r/discordapp/comments/sc61n3/comment/hu4fw5x/) to enable DevTools on stable **Q: I get an error saying "Unauthorized"** A: Discord has patched the script from working in browsers. Use the desktop app, or alternatively find some extension which lets you change your User-Agent and append the string `Electron/` anywhere in it. They have also started checking how many people are in the vc, so make sure you join it on at least 1 other account. **Q: I get a syntax error/unexpected token error** A: Make sure your browser isn't auto-translating this website before copying the script. Turn off any translator extensions and try again. **Q: I get the error `Cannot read properties of undefined (reading 'nativeModules')`** A: You're on a modded client which is a browser wrapper (i.e. Vesktop). Use an actual desktop app. **Q: I get a different error** A: Make sure you're copy/pasting the script correctly and that you've have done all the steps. **Q: Can you make the script auto accept the quest/reward?** A: No. Both of those actions may show a captcha, so automating them is not a good idea. Just do the two clicks yourself. ___ Side note: Please don't post your "fixed" or "improved" versions of the script in the comments. It creates unnecessary confusion, often doesn't fix anything, and sometimes puts other people's accounts at risk. I might redact/delete such comments without notice. Thank you for understanding.