Discord datamining experiment modified: 2026-02-longer-group-dm-invites. Extends the tested expiration time for new group-DM invite links from one day to 28 day...
2026-02-longer-group-dm-invites{
"inviteMaxAgeSeconds": 86400
}{
"0": {
"inviteMaxAgeSeconds": 86400
},
"1": {
"inviteMaxAgeSeconds": 2419200
}
}{
"inviteMaxAgeSeconds": 86400
}{
"0": {
"inviteMaxAgeSeconds": 86400
},
"1": {
"inviteMaxAgeSeconds": 604800
}
}Rollout information unavailable — no public source provides overall rollout for user or Apex experiments. You can check your own assignment from a file below.
Paste the result copied by the console command below, or choose an experiment assignment response (JSON) Discord received. It is read only inside this browser to show this experiment's assignment, and the pasted text or file is never sent or stored. The result reflects when Discord received the assignment and is not the overall rollout.
Supported: the result copied by the console command below, the /api/v9/experiments response (assignments), and a single-user /api/v9/apex/experiments response. Do not choose HAR files, files containing tokens, or full account exports.
// Discord Archive assignment check: reads only the experiment assignments Discord already has and copies them to the clipboard. It does not read login data or send anything.
(() => {
const target = {"apex":true,"hash":1466818723,"unit":"user","text":{"noStore":"Could not find Discord's assignment store. Reload Discord, wait until you are logged in, and run it again.","found":"Assignment for this experiment:","missing":"This account has no assignment for this experiment.","notEligible":"Not eligible","unassigned":"no variant assigned","noApex":"No Apex assignments could be read.","unitCounts":"user units {user}, installation units {installation}","multipleUnits":"Apex assignments mixing several accounts or devices were left out.","empty":"Discord has not received any assignments yet. Run it again once Discord has fully loaded.","skipped":"{count} assignments with an unexpected shape were left out.","copied":"Copied {count} assignments to the clipboard. Paste them into \"Paste result\" on Discord Archive.","notCopied":"Clipboard copy is unavailable. Select and copy the result below."}};
const requires = [];
webpackChunkdiscord_app.push([[Symbol()], {}, (require) => { requires.push(require); }]);
webpackChunkdiscord_app.pop();
// 스토어 이름(displayName)이 정확히 같은 것만 모은다. 아무 속성이나 함수로 돌려주는 객체를 저장소로 오인하지 않는다.
const found = { ExperimentStore: [], ApexExperimentStore: [], AuthenticationStore: [] };
for (const require of requires) {
for (const module of Object.values(require.c || {})) {
try {
for (const value of Object.values(module.exports || {})) {
const name = value && value.constructor && value.constructor.displayName;
if (typeof name === "string" && Object.prototype.hasOwnProperty.call(found, name) && !found[name].includes(value)) found[name].push(value);
}
} catch {}
}
}
const size = (object) => (object && typeof object === "object" ? Object.keys(object).length : 0);
const measure = (read) => { try { return read(); } catch { return -1; } };
// 같은 이름이 여럿이면 자료가 가장 많은 것을 쓴다.
const pick = (list, amount) => list
.map((store) => [store, measure(() => amount(store))])
.filter(([, value]) => value >= 0)
.sort((left, right) => right[1] - left[1])
.map(([store]) => store)[0] || null;
const apexRows = (store) => Object.values((store.getState() || {}).evaluatedExperiments || {})
.reduce((sum, units) => sum + Object.values(units || {}).reduce((total, unit) => total + size(unit && unit.assignments), 0), 0);
const userStore = pick(found.ExperimentStore.filter((store) => typeof store.getAllUserExperimentDescriptors === "function"), (store) => size(store.getAllUserExperimentDescriptors()));
const apexStore = pick(found.ApexExperimentStore.filter((store) => typeof store.getState === "function"), apexRows);
const authStore = found.AuthenticationStore.find((store) => typeof store.getId === "function") || null;
const env = window.GLOBAL_ENV || {};
const channel = ["stable", "ptb", "canary"].includes(env.RELEASE_CHANNEL) ? env.RELEASE_CHANNEL : undefined;
// 데스크톱 앱은 DiscordNative를 둔다. 있는지만 보고 호출하지 않는다.
const platform = typeof window.DiscordNative === "undefined" ? "web" : "desktop";
const result = { platform, release_channel: channel, assignments: null };
let message;
let count = 0;
let skipped = 0;
if (!target.apex) {
if (!userStore) return target.text.noStore;
const all = userStore.getAllUserExperimentDescriptors() || {};
const entries = Object.entries(all);
// 이 사이트의 파서가 받는 모양만 넣고, 뺀 수는 결과에 알린다.
result.assignments = entries
.filter(([hash, item]) => item && Number.isInteger(Number(hash)) && Number.isInteger(item.revision) && Number.isInteger(item.bucket))
.map(([hash, item]) => [Number(hash), item.revision, item.bucket, item.override ? 0 : null, null, null, item.aaMode ? 1 : 0]);
count = result.assignments.length;
skipped = entries.length - count;
const mine = all[String(target.hash)];
const label = !mine ? "" : mine.bucket === -1 ? target.text.notEligible : mine.bucket === 0 ? "Control" : "Treatment " + mine.bucket;
message = mine
? target.text.found + " " + label + " · revision " + mine.revision + (mine.override ? " · override" : "") + (mine.aaMode ? " · A/A" : "")
: target.text.missing;
} else {
if (!apexStore) return target.text.noStore;
const evaluated = (apexStore.getState() || {}).evaluatedExperiments || {};
// Discord처럼 user 단위는 현재 계정 ID로 고른다. 보존된 이전 세션 단위가 남을 수 있기 때문이다. ID는 결과에 넣지 않는다.
let currentId = null;
try { currentId = authStore ? authStore.getId() : null; } catch {}
const surfaces = {};
const unitCounts = {};
let mine = null;
let mixed = false;
for (const [unitType, surface] of [["user", "1"], ["installation", "2"]]) {
const units = evaluated[unitType] || {};
const keys = Object.keys(units);
unitCounts[unitType] = keys.length;
let unit = null;
if (unitType === "user" && currentId != null) unit = units[String(currentId)] || null;
else if (keys.length === 1) unit = units[keys[0]];
else if (keys.length > 1) mixed = true;
if (!unit) continue;
const rows = unit.assignments || {};
const entries = Object.entries(rows);
const list = entries
.filter(([hash, item]) => item && Number.isInteger(Number(hash)))
.map(([hash, item]) => [Number(hash), item.variantId ?? null, item.isOverride ? 1 : 0, item.revision ?? null]);
skipped += entries.length - list.length;
// 계정·기기 ID 대신 고정 이름을 쓴다.
surfaces[surface] = { self: { assignments: list } };
count += list.length;
const hit = rows[String(target.hash)];
if (hit && (target.unit === null || target.unit === unitType)) mine = hit;
}
if (Object.keys(surfaces).length === 0) {
const counts = target.text.unitCounts.replace("{user}", String(unitCounts.user)).replace("{installation}", String(unitCounts.installation));
return target.text.noApex + " (" + counts + ")" + (mixed ? " " + target.text.multipleUnits : "");
}
result.assignments = surfaces;
message = mine
? target.text.found + " " + (mine.variantId == null ? target.text.unassigned : "Variant " + mine.variantId) + " · revision " + (mine.revision ?? "?") + (mine.isOverride ? " · override" : "")
: target.text.missing;
if (mixed) message += " " + target.text.multipleUnits;
}
const skippedNote = skipped > 0 ? " " + target.text.skipped.replace("{count}", String(skipped)) : "";
// 아직 배정을 받지 않은 탭이면 빈 결과를 복사하지 않는다.
if (count === 0) return target.text.empty + skippedNote;
const text = JSON.stringify(result);
if (typeof copy === "function") {
copy(text);
return message + "\n" + target.text.copied.replace("{count}", String(count)) + skippedNote;
}
return message + "\n" + target.text.notCopied + skippedNote + "\n" + text;
})()The command only reads the experiment assignments Discord already received and copies them to the clipboard. It does not read tokens or messages and sends nothing anywhere. It uses the current account ID only to pick this account's Apex assignments and leaves account and device IDs out of the result. Never paste commands from elsewhere or anything that asks for your token. Before pasting, asking an AI chatbot whether the code reads your token or sends data anywhere is an easy extra check.
For a logged-in account Discord receives assignments over its live gateway connection, so filtering the Network tab for experiments shows nothing. The /api/v9/experiments and /api/v9/apex/experiments responses you see while logged out are assignments for this browser, not an account; you can save a response body as .json and choose it.
Do not use request headers, Copy as cURL, Copy as fetch, or Save all as HAR. While logged in they contain your account token (authorization), and anyone who gets it can take over your account.
Add your result
Contributing is optional. A sanitized preview is built from the file above first, and nothing is sent until you review it and consent. Without a file or consent nothing is sent.
Read your assignment result above first to contribute.
If you contributed from this browser you can withdraw right away. If you cleared cookies, enter the deletion key you received.
Daily counts of the assignments submitted by browsers that consented. This is not Discord's rollout across all users or a user count, and file authenticity and the actual assignment time are not verified. Submission time is not when the assignment was observed, and withdrawal does not change counts already added.
Window: submissions from 2026-10-12 to 2026-10-18 (UTC) · updated daily
Not enough volunteer sample to publish for this experiment yet.