Guides
How safe am I?
Test your detection footprint in real-time. Our educational scanner mimics The West's 3-layer anti-cheat system to show you exactly what gets logged:
- Global variables exposed by your scripts
- CSS fingerprints from injected stylesheets
- WebDriver automation detection
- Script identification with confidence scores
Run scanTWScripts() in console. Get instant results. Learn what's being tracked about you—before the admins do. Educational demonstration tool.
Install, scan, understand.
JavaScript
js
// ==UserScript==
// @name TW Scripts Scanner
// @namespace TW-Cheats
// @author TW-Cheats
// @description Checks for globals, injected styles and webdriver usage
// @include https://*.the-west.*/game.php*
// @version 3.1
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// @grant GM_setClipboard
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
const initialVarCount = Object.keys(unsafeWindow).length;
// Browser / engine noise we don't care about
const ignoreList = new Set([
'addEventListener',
'removeEventListener',
'dispatchEvent',
'setTimeout',
'setInterval',
'clearTimeout',
'clearInterval',
'requestAnimationFrame',
'cancelAnimationFrame',
'fetch',
'XMLHttpRequest',
'Promise',
'console',
'localStorage',
'sessionStorage',
'getDefaultComputedStyle',
'scrollByLines',
'scrollByPages',
'updateCommands',
'dump',
'setResizable',
'requestIdleCallback',
'cancelIdleCallback',
'external',
'mozInnerScreenX',
'mozInnerScreenY',
'scrollMaxX',
'scrollMaxY',
'fullScreen',
'ondevicemotion',
'ondeviceorientation',
'ondeviceorientationabsolute',
'InstallTrigger',
'originAgentCluster',
'onbeforematch',
'oncontextlost',
'oncommand',
'oncontextrestored',
'ondragexit',
'onscrollend',
'onpointerrawupdate',
'onmozfullscreenchange',
'onmozfullscreenerror',
'scheduler'
]);
let allowedVariables = null;
let lastScanResults = null;
GM_xmlhttpRequest({
method: 'GET',
url: 'https://tw-cheats.com/files/vars.json',
onload(res) {
try {
allowedVariables = JSON.parse(res.responseText);
} catch {
console.error('[Scanner] Invalid allowed vars list');
return;
}
setTimeout(() => {
console.log('[Scanner] Auto scan');
console.log(
'Globals:',
initialVarCount,
'→',
Object.keys(unsafeWindow).length
);
runScan('auto');
}, 10000);
},
onerror() {
console.error('[Scanner] Failed to load allowed vars list');
}
});
// exposed only through console, no globals
console.scan = function () {
if (!allowedVariables) {
console.warn('[Scanner] Not ready yet');
return;
}
runScan('manual');
};
console.export = function () {
if (!lastScanResults) {
console.warn('[Scanner] No scan data');
return;
}
GM_setClipboard(buildTextReport(lastScanResults));
console.log('[Scanner] Report copied');
};
console.report = function () {
if (!lastScanResults) {
console.warn('[Scanner] No scan data');
return;
}
printReport(lastScanResults);
};
function scanStyles() {
return Array.from(document.styleSheets)
.filter(s => {
if (!s.href) return true;
const h = s.href.toLowerCase();
return !h.includes('the-west') && !h.includes('innogames');
})
.map(s => {
if (s.href) {
return `external: ${s.href}`;
}
try {
return `inline (${s.cssRules.length} rules)`;
} catch {
return 'inline (blocked)';
}
});
}
function runScan(label) {
const vars = Object.keys(unsafeWindow)
.slice(unsafeWindow.Chat.Router.varPos);
const allowed = new Set(allowedVariables);
const illegal = vars.filter(v =>
!allowed.has(v) && !ignoreList.has(v)
);
const varInfo = illegal.map(name => {
const val = unsafeWindow[name];
const type = typeof val;
let preview;
if (type === 'function') preview = 'function';
else if (Array.isArray(val)) preview = `array(${val.length})`;
else if (type === 'object' && val) preview = 'object';
else preview = String(val).slice(0, 50);
return { name, type, preview };
});
const styles = scanStyles();
const webdriver = navigator.webdriver === true;
lastScanResults = {
time: new Date().toISOString(),
label,
illegal: varInfo,
styles,
webdriver
};
console.log('[Scanner]', label);
console.log('globals:', illegal.length);
console.log('styles:', styles.length);
console.log('webdriver:', webdriver);
}
function buildTextReport(r) {
let out = '';
out += 'TW Scripts Scanner\n\n';
out += `Time: ${r.time}\n`;
out += `Scan: ${r.label}\n\n`;
out += `Globals: ${r.illegal.length}\n`;
out += `Styles: ${r.styles.length}\n`;
out += `WebDriver: ${r.webdriver}\n\n`;
if (r.illegal.length) {
out += 'Globals:\n';
r.illegal.forEach((v, i) => {
out += `${i + 1}. ${v.name} (${v.type}) ${v.preview}\n`;
});
out += '\n';
}
if (r.styles.length) {
out += 'Styles:\n';
r.styles.forEach((s, i) => {
out += `${i + 1}. ${s}\n`;
});
out += '\n';
}
if (r.webdriver) {
out += 'navigator.webdriver = true\n';
}
return out;
}
function printReport(r) {
console.clear();
console.log('TW Scripts Scanner');
console.log('Time:', r.time);
console.log('Scan:', r.label);
console.log('');
if (r.webdriver) {
console.log('webdriver detected');
}
if (r.styles.length) {
console.log('styles:');
r.styles.forEach(s => console.log(' -', s));
}
if (r.illegal.length) {
console.log('globals:');
r.illegal.forEach(v =>
console.log(` - ${v.name} (${v.type})`, v.preview)
);
}
if (!r.webdriver && !r.styles.length && !r.illegal.length) {
console.log('clean');
}
}
console.log('[Scanner] Loaded (10 seconds)');
})();