Skip to content

Instantly share code, notes, and snippets.

@tomfleet
Created July 1, 2025 21:03
Show Gist options
  • Select an option

  • Save tomfleet/cae3bf4e75266edc0cc69bebb29606ad to your computer and use it in GitHub Desktop.

Select an option

Save tomfleet/cae3bf4e75266edc0cc69bebb29606ad to your computer and use it in GitHub Desktop.
Google AI-less Search
// ==UserScript==
// @name Google AI-less Search
// @namespace http://tampermonkey.net/
// @version 1.1
// @description Appends "-ai" to your Google search queries to help filter out AI-generated content.
// @author You
// @match *://*.google.com/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
const appendix = " -ai";
/**
* This function checks the URL of the current search results page.
* If the query parameter 'q' doesn't end with our appendix, it adds it
* and reloads the page. This acts as a fallback for any searches
* that aren't caught by the form submission listener.
*/
const checkAndUpdateURL = () => {
// We only want to run this on search results pages
if (window.location.pathname !== '/search') {
return;
}
const url = new URL(window.location.href);
const query = url.searchParams.get('q');
// Check if a query exists and if it does NOT already end with the appendix
if (query && !query.trim().toLowerCase().endsWith(appendix.toLowerCase())) {
const newQuery = query + appendix;
url.searchParams.set('q', newQuery);
// Redirect to the new URL with the modified query
window.location.href = url.href;
}
};
/**
* This function intercepts the submission of a search form.
* It finds the search input field within that form and appends our
* text before the form is sent to Google's servers.
* @param {Event} e The form submission event.
*/
const handleFormSubmit = (e) => {
try {
// The form element that triggered the submit event
const form = e.target;
// Find the search input within that specific form
const searchInput = form.querySelector('input[name="q"]');
if (searchInput && searchInput.value) {
// Check if the value already ends with the appendix to avoid duplicates
if (!searchInput.value.trim().toLowerCase().endsWith(appendix.toLowerCase())) {
searchInput.value += appendix;
}
}
} catch (error) {
console.error("Greasemonkey Script Error (handleFormSubmit):", error);
}
// The script does not prevent the default submission.
// It modifies the value in-place, and the browser submits the modified form.
};
/**
* Google's page can load elements dynamically. A MutationObserver is the
* most reliable way to find the search form(s) as soon as they are
* added to the page, whenever that may be.
*/
const observeDOM = () => {
const observer = new MutationObserver((mutations, obs) => {
// Find all search forms on the page. Usually there's one, but it's good to be robust.
const searchForms = document.querySelectorAll('form[action="/search"]');
if (searchForms.length > 0) {
searchForms.forEach(form => {
// We add a custom attribute to mark that we've already attached a listener,
// preventing us from attaching multiple listeners to the same form.
if (!form.hasAttribute('data-modified-by-script')) {
form.setAttribute('data-modified-by-script', 'true');
form.addEventListener('submit', handleFormSubmit);
}
});
}
});
// Start observing the entire document for changes to the element tree.
observer.observe(document.documentElement, {
childList: true,
subtree: true
});
};
// --- Script Execution ---
// Run the URL check immediately. This is our fallback.
checkAndUpdateURL();
// Start observing the DOM to catch forms as they appear. This is our primary method.
observeDOM();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment