Block annoying and glitchy Google One Tap prompts
// ==UserScript==
// @name Block Google One Tap
// @namespace https://chuyanliu.github.io/
// @version 2026-5-31
// @description Block annoying and glitchy Google One Tap prompts
// @license GNU GPLv3
// @author Chuyan Liu
// @match *://*/*
// @run-at document-start
// @grant none
// ==/UserScript==
(function () {
'use strict';
const logger = (...args) => console.log(`[one tap blocker]`, ...args);
// ------------------------ Block FedCM (modern onetap) ------------------------
// alternatively: chrome://settings/content/federatedIdentityApi
if (typeof navigator?.credentials?.get === 'function') {
const originalGet = navigator.credentials.get;
navigator.credentials.get = function (options) {
if (options?.identity?.providers?.some?.(p => p?.configURL?.includes?.('accounts.google.com'))) {
logger('Blocked FedCM One Tap request');
// standard generic exception returned when user clicks x, tested chrome 148.0.7778.217
// does not use IdentityCredentialError (https://developer.mozilla.org/en-US/docs/Web/API/IdentityCredentialError)
return Promise.reject(new DOMException('Error retrieving a token.', 'NetworkError'));
}
return originalGet.apply(this, arguments);
};
}
// ------------------------ Block window.google API (websites before 2026) ------------------------
function makeAPIBlockLogger(name) {
return function (...args) {
logger(`Blocked API call: "google.accounts.id.${name}"`, ...args);
};
}
const _googleNSAccountsID = {
intermediate: {
verifyParentOrigin: makeAPIBlockLogger('intermediate.verifyParentOrigin'),
notifyParentResize: makeAPIBlockLogger('intermediate.notifyParentResize'),
notifyParentClose: makeAPIBlockLogger('intermediate.notifyParentClose'),
notifyParentDone: makeAPIBlockLogger('intermediate.notifyParentDone'),
notifyParentTapOutsideMode: makeAPIBlockLogger('intermediate.notifyParentTapOutsideMode'),
},
cancel: makeAPIBlockLogger('cancel'),
disableAutoSelect: makeAPIBlockLogger('disableAutoSelect'),
initialize: makeAPIBlockLogger('initialize'),
prompt: function (callback) {
makeAPIBlockLogger('prompt')();
if (typeof callback === 'function') {
setTimeout(() => {
try {
// standard generic dismissal callback value when user clicks x. NOT TESTED, I only added this after FedCM was implemented
callback({
getMomentType: () => 'skipped',
isDisplayMoment: () => false,
isDisplayed: () => false,
isNotDisplayed: () => false,
getNotDisplayedReason: () => void 0,
isSkippedMoment: () => true,
getSkippedReason: () => 'user_cancel',
isDismissedMoment: () => false,
getDismissedReason: () => void 0
});
} catch (err) {
logger('error whilst running callback for prompt() api:', err);
}
}, 1);
}
},
PromptMomentNotification: makeAPIBlockLogger('PromptMomentNotification'),
renderButton: makeAPIBlockLogger('renderButton'),
revoke: makeAPIBlockLogger('revoke'),
storeCredential: makeAPIBlockLogger('storeCredential'),
setLogLevel: makeAPIBlockLogger('setLogLevel')
};
// previous version is bad, this should maintain compatibility
Object.defineProperty(window, 'google', {
value: new Proxy(
{
// if somehow google props load BEFORE this script loads, then they should remain
...window?.google ?? {},
accounts: new Proxy({}, {
...window?.google?.accounts ?? {},
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
get(target, property, receiver) {
if (property === 'id') {
return _googleNSAccountsID;
}
return Reflect.get(target, property, receiver);
},
set(target, property, value, receiver) {
if (property === 'id') {
return true;
}
return Reflect.set(target, property, value, receiver);
},
deleteProperty(target, property) {
if (property === 'id') {
return false;
}
return Reflect.deleteProperty(target,property);
}
})
},
{
get(target, property, receiver) {
return Reflect.get(target, property, receiver);
},
set(target, property, value, receiver) {
return Reflect.set(target, property, value, receiver);
}
}
),
writable: true,
configurable: false,
enumerable: true
});
// ------------------------ Block Legacy Iframe ------------------------
new MutationObserver(function (mutations) {
for (let i = 0; i < mutations.length; i++) {
const addedNodes = mutations[i].addedNodes;
for (let j = 0; j < addedNodes.length; j++) {
const node = addedNodes[j];
if (node.tagName === 'IFRAME') {
if (node.src?.includes?.('accounts.google.com/gsi')) {
node.remove();
logger('Deleted legacy onetap iframe:', node);
}
}
}
}
}).observe(document.documentElement, { childList: true, subtree: true });
})();