Skip to content

Instantly share code, notes, and snippets.

@masonwan
Last active October 20, 2025 15:06
Show Gist options
  • Save masonwan/b33c5d4d6179112d3c7a170411cdaf27 to your computer and use it in GitHub Desktop.
Save masonwan/b33c5d4d6179112d3c7a170411cdaf27 to your computer and use it in GitHub Desktop.
Better way to manage Chrome's search engines

Problem

Chrome has the feature to automatically add search engine when it detects an input field on websites. After using Chrome months, it often resutls a bunch of search engines stayed in the settings. And the setting page does not provide a convinient way to remove them.

Updates on 2024-11-21

The editting the Web Data as SQLite file did not seem to work anymore. Chrome seems to revert all the changes when restart.

To make it even worse, it seems that the DOM tree is not accessable from the development console on the setting page, so even a bookmarklet could not work. Neighter does Chrome provide an API to access the search engines.

Updates on 2024-09-17

Please note tha the following solution did not seem to work anymore in 2024. I now recommend to update the SQLite file related to search engines setting directly. Probably use DB Browser for SQLite. And the file related to the search engine is %LOCALAPPDATA%\Google\Chrome\User Data\Default\Web Data on Windows (other platforms).

Solution

Stop auto-add search engines

Use Don't add custom search engines.

Delete auto created search engines

Note that in order to run the script, execute the code in the console of Developer Tool (⌘⌥J).

  1. Use export-search-engines.js to dump the current search engines, generating backup.json.
  2. Optionally use remove-auto-search-engines.js to remove the search engines which has more than 6 charcters for keyword from backup.json, generating output.json.
  3. Use clear-search-engines.js to remove all current search engines from Chrome.
  4. Import output.json back to Chrome.
settings.SearchEnginesBrowserProxyImpl.prototype.getSearchEnginesList()
.then(function (val) {
val.others.sort(function (a, b) { return b.modelIndex - a.modelIndex; });
val.others.forEach(function (engine) {
settings.SearchEnginesBrowserProxyImpl.prototype.removeSearchEngine(engine.modelIndex);
});
});
(function exportSEs() {
/* Auxiliary function to download a file with the exported data */
function downloadData(filename, data) {
const file = new File([data], { type: 'text/json' });
const elem = document.createElement('a');
elem.href = URL.createObjectURL(file);
elem.download = filename;
elem.click();
}
/* Actual search engine export magic */
settings.SearchEnginesBrowserProxyImpl.prototype.getSearchEnginesList()
.then((searchEngines) => {
downloadData('search_engines.json', JSON.stringify(searchEngines.others));
});
}());
(async function importSEs() {
/* Auxiliary function to open a file selection dialog */
function selectFileToRead() {
return new Promise((resolve) => {
const input = document.createElement('input');
input.setAttribute('type', 'file');
input.addEventListener('change', (e) => {
resolve(e.target.files[0]);
}, false);
input.click();
});
}
/* Auxiliary function to read data from a file */
function readFile(file) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.addEventListener('load', (e) => {
resolve(e.target.result);
});
reader.readAsText(file);
});
}
const file = await selectFileToRead();
const content = await readFile(file);
const searchEngines = JSON.parse(content);
searchEngines.forEach(({ name, keyword, url }) => {
/* Actual search engine import magic */
chrome.send('searchEngineEditStarted', [-1]);
chrome.send('searchEngineEditCompleted', [name, keyword, url]);
});
}());
import { createRequire } from 'module'
import fs from 'fs'
const require = createRequire(import.meta.url)
const searchEngines = require('./backup.json')
let map = searchEngines
.reduce((map, e) => {
if (map[e.keyword.length] === undefined) {
map[e.keyword.length] = []
}
map[e.keyword.length].push(e)
return map
}, {})
let newSearchEngines = Object.entries(map)
.filter(entry => parseInt(entry[0], 10) <= 6)
.reduce((list, entry) => {
list.push(...entry[1])
return list
}, [])
fs.writeFileSync('output.json', JSON.stringify(newSearchEngines))
@dot3dash4dot
Copy link

Thanks!

@k-yle
Copy link

k-yle commented Feb 28, 2025

chrome v133 now provides an API to export search engines:

const { sendWithPromise } = await import('chrome://resources/js/cr.js');
const { actives } = await sendWithPromise('getSearchEnginesList');

actives; // array

This snippet can be pasted into the devtools console on chrome://settings/searchEngines

@masonwan
Copy link
Author

masonwan commented Mar 1, 2025

@k-yle Thanks. As far as I research, it seems that it only allows reading the search engine list, but not edit them.

@iGerman00
Copy link

iGerman00 commented May 7, 2025

I recently had Microsoft Edge, once again, reset all my keywords and default itself to Bing. I investigated a bit and ended up with this script to import and export them. I've only tested it on Edge - not sure if the chrome object is exposed to window anywhere apart from Edge. Paste it into the console on chrome://settings/searchEngines and call the options it will print out. I successfully transferred over 100 keywords between my laptop and desktop this way:

(async function() {
  try {
    const { sendWithPromise } = await import('chrome://resources/js/cr.js');
    
    const searchEngineManager = {
      async exportAll() {
        const data = await sendWithPromise('getSearchEnginesList');
        const exportData = {
          defaults: data.defaults,
          others: data.others,
          extensions: data.extensions,
          timestamp: new Date().toISOString()
        };
        
        this.downloadJson(exportData, 'edge_search_engines.json');
        console.log('Exported search engines:', exportData);
        return exportData;
      },
      
      async exportCustom() {
        const data = await sendWithPromise('getSearchEnginesList');
        const exportData = {
          others: data.others.filter(engine => !engine.isPrepopulated && !engine.isStarterPack),
          timestamp: new Date().toISOString()
        };
        
        this.downloadJson(exportData, 'edge_custom_search_engines.json');
        console.log('Exported custom search engines:', exportData);
        return exportData;
      },
      
      async clearCustom() {
        const data = await sendWithPromise('getSearchEnginesList');
        const customEngines = data.others.filter(engine => 
          !engine.isPrepopulated && !engine.isStarterPack && engine.canBeRemoved);
          
        for (const engine of customEngines) {
          chrome.send('removeSearchEngine', [engine.modelIndex]);
          console.log(`Removed search engine: ${engine.name}`);
        }
        
        console.log(`Removed ${customEngines.length} custom search engines`);
        return customEngines.length;
      },
      
      async import() {
        try {
          const file = await this.selectFile();
          const content = await this.readFile(file);
          const data = JSON.parse(content);
          
          const searchEngines = data.others || data;
          
          for (const engine of searchEngines) {
            if (engine.name && engine.keyword && engine.url) {
              chrome.send('searchEngineEditStarted', [-1]);
              // race conditions
              await new Promise(resolve => setTimeout(resolve, 10));
              chrome.send('searchEngineEditCompleted', [
                engine.name, 
                engine.keyword, 
                engine.url
              ]);
              await new Promise(resolve => setTimeout(resolve, 10));
              console.log(`Added search engine: ${engine.name}`);
            }
          }
          
          console.log(`Imported ${searchEngines.length} search engines`);
          return searchEngines.length;
        } catch (error) {
          console.error('Import failed:', error);
          return 0;
        }
      },
      
      addSearchEngine(name, keyword, url) {
        chrome.send('searchEngineEditStarted', [-1]);
        chrome.send('searchEngineEditCompleted', [name, keyword, url]);
        console.log(`Added search engine: ${name}`);
      },
      
      downloadJson(data, filename) {
        const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = filename;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
      },
      
      selectFile() {
        return new Promise((resolve) => {
          const input = document.createElement('input');
          input.type = 'file';
          input.accept = '.json';
          
          input.onchange = (event) => {
            resolve(event.target.files[0]);
          };
          
          input.click();
        });
      },
      
      readFile(file) {
        return new Promise((resolve, reject) => {
          const reader = new FileReader();
          reader.onload = (event) => resolve(event.target.result);
          reader.onerror = (error) => reject(error);
          reader.readAsText(file);
        });
      }
    };
    
    window.searchEngineManager = searchEngineManager;
    
    console.log('Search Engine Manager loaded! Available commands:');
    console.log('- searchEngineManager.exportAll() - Export all search engines');
    console.log('- searchEngineManager.exportCustom() - Export only custom search engines');
    console.log('- searchEngineManager.clearCustom() - Remove all custom search engines');
    console.log('- searchEngineManager.import() - Import search engines from a JSON file');
    console.log('- searchEngineManager.addSearchEngine(name, keyword, url) - Add a single search engine');
    
  } catch (error) {
    console.error('Failed to initialize Search Engine Manager:', error);
  }
})();

@masonwan
Copy link
Author

@iGerman00 That works perfectly. Thanks for the awesome sharing!

@thethakuriservicenow
Copy link

thethakuriservicenow commented Aug 29, 2025

HI,

import-search-engines.js is no longer working. After I select the JSON file from the prompt, nothing is added to the search engines.

In the console, I see the following:

Promise {<pending>}
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: undefined

I tried opening Chrome with --allow-file-access-from-files

Is there any resolution?

@thethakuriservicenow
Copy link

Figured it out. You have to browse to the chrome://settings/searchEngines before importing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment