Bypasses CrazyGames ad wait/loading stages via SDK faking, network blocking, and DOM cleanup
// ==UserScript==
// @name CrazyGames Ad Bypass Helper
// @namespace http://tampermonkey.net/
// @version 3.4.0
// @description Bypasses CrazyGames ad wait/loading stages via SDK faking, network blocking, and DOM cleanup
// @match https://www.crazygames.com/game/*
// @match https://*.crazygames.com/*
// @grant unsafeWindow
// @run-at document-start
// ==/UserScript==
(function () {
'use strict';
// Guard against double-injection (e.g. multiple @match patterns firing)
if (unsafeWindow.__cgBypassInstalled) return;
unsafeWindow.__cgBypassInstalled = true;
const win = unsafeWindow || window;
const LOG = '[CG-Bypass]';
const log = (...a) => console.log(LOG, ...a);
const warn = (...a) => console.warn(LOG, ...a);
// -----------------------------------------------------------
// CONFIG
// -----------------------------------------------------------
const CFG = {
REWARD_DELAY_MS: 50, // fake ad play duration before callbacks fire
MAX_HOOK_ATTEMPTS: 100,
HOOK_INTERVAL_MS: 200,
};
// Native timer references used internally (no overrides)
const _setTimeout = win.setTimeout.bind(win);
const _setInterval = win.setInterval.bind(win);
// -----------------------------------------------------------
// 1. AD URL PATTERN LIST
// -----------------------------------------------------------
const AD_PATTERNS = [
'googlesyndication', 'doubleclick', 'googleads',
'adservice', 'pagead', 'adserver',
'prebid', 'amazon-adsystem', 'ad-delivery',
'imasdk.googleapis.com', 'securepubads',
];
function isAdUrl(url) {
const u = String(url);
return AD_PATTERNS.some(p => u.includes(p));
}
// -----------------------------------------------------------
// 2. NETWORK BLOCKING (fetch + XHR)
// -----------------------------------------------------------
const _fetch = win.fetch.bind(win);
win.fetch = function (input, options) {
const url = (input instanceof Request) ? input.url : String(input);
if (isAdUrl(url)) {
log('Blocked fetch:', url.substring(0, 100));
return Promise.resolve(new Response('{}', {
status: 200,
headers: { 'Content-Type': 'application/json' },
}));
}
return _fetch(input, options);
};
const _xhrOpen = XMLHttpRequest.prototype.open;
const _xhrSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function (method, url, ...args) {
this._cgBlocked = isAdUrl(String(url));
if (this._cgBlocked) log('Blocked XHR:', String(url).substring(0, 100));
return _xhrOpen.call(this, method, url, ...args);
};
XMLHttpRequest.prototype.send = function (...args) {
if (this._cgBlocked) {
Object.defineProperty(this, 'readyState', { value: 4, configurable: true });
Object.defineProperty(this, 'status', { value: 200, configurable: true });
Object.defineProperty(this, 'responseText', { value: '{}', configurable: true });
this.dispatchEvent(new Event('load'));
return;
}
return _xhrSend.apply(this, args);
};
// -----------------------------------------------------------
// 3. SDK FAKING
// -----------------------------------------------------------
const hookState = {
instance: false,
sdkAd: false,
adsModule: false,
calls: 0,
};
// -- 3a. Singleton fake instance (event-listener pattern) ----
let _fakeInstance = null;
function getFakeInstance() {
if (_fakeInstance) return _fakeInstance;
const listeners = {};
function fireEvent(name, data = {}) {
(listeners[name] || []).forEach(cb => {
try { cb(data); } catch (e) { warn(`Listener error [${name}]:`, e); }
});
}
let _initDone = false;
_fakeInstance = {
init() {
log('instance.init()');
_initDone = true;
_setTimeout(() => fireEvent('initialized', {
userInfo: {
countryCode: 'US',
browser: { name: 'Chrome', version: '124' },
os: { name: 'Windows', version: '10' },
device: { type: 'desktop' },
},
}), 50);
},
addEventListener(event, cb) {
if (!listeners[event]) listeners[event] = [];
listeners[event].push(cb);
if (event === 'initialized' && _initDone) {
_setTimeout(() => cb({
userInfo: {
countryCode: 'US',
browser: { name: 'Chrome', version: '124' },
os: { name: 'Windows', version: '10' },
device: { type: 'desktop' },
},
}), 10);
}
},
removeEventListener(event, cb) {
if (listeners[event])
listeners[event] = listeners[event].filter(fn => fn !== cb);
},
async requestAd(type = 'midgame') {
hookState.calls++;
log(`instance.requestAd("${type}")`);
fireEvent('adStarted', { adType: type });
return new Promise(resolve => {
_setTimeout(() => {
fireEvent('adFinished', { adType: type });
log(`adFinished for "${type}"`);
resolve();
}, CFG.REWARD_DELAY_MS);
});
},
gameplayStart() {},
gameplayStop() {},
happytime() {},
sdkGameLoadingStart() {},
sdkGameLoadingStop() {},
async requestBanner(containers) {
(containers || []).forEach(c =>
_setTimeout(() => fireEvent('bannerRendered', { containerId: c.containerId }), 50));
},
async requestResponsiveBanner(containers) {
(containers || []).forEach(c =>
_setTimeout(() => fireEvent('bannerRendered', { containerId: c.id || c.containerId }), 50));
},
clearBanner() {},
clearAllBanners() {},
get hasAdblock() { return false; },
adblockDetectionExecuted: true,
inviteLink(params = {}) {
const base = win.location.href.split('?')[0];
return `${base}?czy_invite=true&utm_source=invite&${new URLSearchParams(params)}`;
},
};
return _fakeInstance;
}
// -- 3b. Legacy callback-based ad module ---------------------
function createFakeAdModule() {
const REWARD_EVENTS = [
'rewardedComplete', 'rewardGranted', 'adComplete',
'crazy_ad_finished', 'adReward', 'adFinished',
];
function dispatchRewardEvents() {
REWARD_EVENTS.forEach(ev => {
try { win.dispatchEvent(new CustomEvent(ev)); } catch (_) {}
});
}
function falsyFn() { return Promise.resolve(false); }
falsyFn.valueOf = () => false;
falsyFn.toString = () => 'false';
return {
get isAdPlaying() { return false; },
get requestInProgress() { return false; },
hasAdblock: falsyFn,
hasAdblockEnabled: falsyFn,
isAdblockActive: falsyFn,
async prefetchAd(type) {
hookState.calls++;
log(`prefetchAd("${type}")`);
},
async requestAd(type = 'midgame', cbs = {}) {
hookState.calls++;
log(`requestAd("${type}")`);
try { cbs.adStarted?.(); } catch (_) {}
return new Promise(resolve => {
_setTimeout(() => {
try { cbs.adFinished?.(); } catch (_) {}
dispatchRewardEvents();
log(`reward granted for "${type}"`);
resolve();
}, CFG.REWARD_DELAY_MS);
});
},
addAdblockPopupListener() {},
removeAdblockPopupListener() {},
};
}
// -- 3c. Hook helper -----------------------------------------
function trapProperty(obj, prop, onSet) {
if (obj[prop]) { onSet(obj[prop]); return; }
let _val;
Object.defineProperty(obj, prop, {
configurable: true,
enumerable: true,
get() { return _val; },
set(v) { _val = v; if (v) onSet(v); },
});
}
// -- 3d. Individual SDK hooks --------------------------------
function hookInstance() {
if (hookState.instance) return;
const apply = (sdk) => {
if (!sdk?.CrazySDK) return;
sdk.CrazySDK.getInstance = () => {
log('CrazyGames.CrazySDK.getInstance() intercepted');
return getFakeInstance();
};
hookState.instance = true;
log('CrazySDK.getInstance() hooked');
};
if (win.CrazyGames) { apply(win.CrazyGames); return; }
trapProperty(win, 'CrazyGames', apply);
}
function hookSdkAd() {
if (hookState.sdkAd) return;
const apply = (cg) => {
if (!cg?.SDK || hookState.sdkAd) return;
const fakeAd = createFakeAdModule();
Object.defineProperty(cg.SDK, 'ad', { configurable: true, enumerable: true, get: () => fakeAd });
hookState.sdkAd = true;
log('CrazyGames.SDK.ad hooked');
};
if (win.CrazyGames) { apply(win.CrazyGames); return; }
trapProperty(win, 'CrazyGames', apply);
}
function hookAdsModule() {
if (hookState.adsModule) return;
const AD_METHODS = [
'requestAd', 'requestAds', 'showAd', 'showRewardedAd',
'displayAd', 'displayRewardedAd', 'displayMidrollAd',
'requestRewardedAd', 'showRewardedVideo', 'requestRewardedVideo',
'showInterstitial', 'requestOnly', 'render', 'preloadAd',
];
const apply = (target) => {
if (!target || hookState.adsModule) return;
const proxy = new Proxy(target, {
get(obj, prop) {
const orig = obj[prop];
if (AD_METHODS.includes(prop) && typeof orig === 'function') {
return function (...args) {
hookState.calls++;
log(`CrazygamesAds.${prop}()`);
let onStart = null, onFinish = null;
for (const a of args) {
if (a && typeof a === 'object') {
onStart = a.adStarted || a.onAdStarted || a.onStart;
onFinish = a.adFinished || a.onAdFinished || a.onComplete || a.onReward;
}
}
try { onStart?.(); } catch (_) {}
if (prop === 'requestOnly' || prop === 'preloadAd')
return Promise.resolve({ success: true });
return new Promise(resolve => {
_setTimeout(() => {
try { onFinish?.(); } catch (_) {}
['rewardedComplete', 'adComplete', 'crazy_ad_finished'].forEach(ev => {
try { win.dispatchEvent(new CustomEvent(ev)); } catch (_) {}
});
resolve({ success: true, completed: true });
}, CFG.REWARD_DELAY_MS);
});
};
}
const lower = String(prop).toLowerCase();
if (['hasadblock', 'hasadblockenabled', 'isadblockactive'].includes(lower)) {
return async () => false;
}
return orig;
},
});
hookState.adsModule = true;
return proxy;
};
if (win.CrazygamesAds) {
win.CrazygamesAds = apply(win.CrazygamesAds);
log('CrazygamesAds hooked (existing)');
return;
}
let _ads;
Object.defineProperty(win, 'CrazygamesAds', {
configurable: true, enumerable: true,
get() { return _ads; },
set(v) { _ads = apply(v) || v; if (_ads) log('CrazygamesAds hooked (deferred)'); },
});
}
// -- 3e. Orchestration ---------------------------------------
let _hookAttempts = 0;
let _hookTimer = null;
function attemptAllHooks() {
_hookAttempts++;
hookInstance();
hookSdkAd();
hookAdsModule();
const done = hookState.instance || (hookState.sdkAd && hookState.adsModule);
if (done || _hookAttempts >= CFG.MAX_HOOK_ATTEMPTS) {
if (_hookTimer) { clearInterval(_hookTimer); _hookTimer = null; }
log(`Hooks finalised after ${_hookAttempts} attempt(s). State:`, hookState);
}
}
_hookTimer = _setInterval(attemptAllHooks, CFG.HOOK_INTERVAL_MS);
attemptAllHooks();
// -----------------------------------------------------------
// 4. DOM AD OVERLAY REMOVAL + AUTO-SKIP
// -----------------------------------------------------------
function removeAdOverlays() {
const SELECTORS = [
'[class*="ad-overlay"]', '[class*="ad-container"]', '[class*="ad-wrapper"]',
'[class*="preroll"]', '[class*="midroll"]', '[id*="ad-container"]',
'[class*="loading-ad"]', '[class*="ad-loading"]', '.ad-blocker-message',
'[class*="rewarded"]',
];
const obs = new MutationObserver(() => {
SELECTORS.forEach(sel => {
document.querySelectorAll(sel).forEach(el => {
const s = getComputedStyle(el);
const isOverlay = (s.position === 'fixed' || s.position === 'absolute')
&& parseFloat(s.zIndex) > 100;
if (isOverlay) { el.style.display = 'none'; log('Hid overlay:', sel); }
});
});
document.querySelectorAll('button, [class*="skip"], [class*="close"]').forEach(btn => {
const text = (btn.textContent || '').toLowerCase();
if (['skip', 'close', 'continue'].some(w => text.includes(w)) && btn.offsetParent) {
btn.click();
log('Auto-clicked:', btn.textContent.trim());
}
});
});
obs.observe(document.documentElement, { childList: true, subtree: true, attributes: true });
}
// -----------------------------------------------------------
// 5. SUPPRESS AD ERROR postMessages
// -----------------------------------------------------------
win.addEventListener('message', function (e) {
try {
const d = (typeof e.data === 'string') ? JSON.parse(e.data) : e.data;
if (d?.type === 'adError' || d?.event === 'adError') {
log('Suppressed adError postMessage');
e.stopImmediatePropagation();
}
} catch (_) {}
}, true);
// -----------------------------------------------------------
// INIT
// -----------------------------------------------------------
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', removeAdOverlays);
} else {
removeAdOverlays();
}
log('v3.4.0 loaded — all modules active');
})();