62

I have created some search entries in Google Chrome using 'Edit search engines'.

How can I share some of these entries with my colleagues?

Shekhar
  • 5,009
  • 4
  • 33
  • 49
Lazer
  • 17,227
  • 43
  • 116
  • 141
  • This is such a great question. I found https://ludovic.chabant.com/devblog/2010/12/29/poor-mans-search-engines-sync-for-google-chrome/ but don't want to bother trying it since it's from 2010-2011. 5 to 6 years on the internet is an eternity. I wish there were a convenient (updated) way to share across Google accounts and across profiles within the same Chrome installation. – Ryan Jul 12 '16 at 16:03
  • Can someone create a feature request to Google so we all can upvote it there? – userJT Feb 03 '20 at 17:31
  • It seems Google have done this now, as part of their data-portability promise they made with facebook about a decade ago. see the new answer for a super-simple export: https://superuser.com/a/1641015/148251 – Hicsy Mar 01 '22 at 00:15
  • Wait, why is no one mentioning Google's [Programmable Search Engine](https://programmablesearchengine.google.com/)? Or am I missing something? – Arctiic Jun 08 '22 at 05:58

15 Answers15

28

Edit 2020-07-27:

The export part of this solution does not work anymore in Chrome 84 (the settings object used in the script is no longer available). The import script is not very useful without the export part but it should still work for importing an existing JSON file with the settings or for transfering search engine settings from an older version of Chrome/Chromium to the current version.

Here is a simple solution to export and import Chrome search engine settings without using any external tools or editing the registry:

  1. Open the Search Engine Settings page in Chrome (chrome://settings/searchEngines).
  2. Open Chrome Developer Tools.
  • Shortcut: F12 or Ctrl+Shift+I (on Windows, shortcuts on other platforms may differ).
  • Manual navigation: Three-dot menu in upper-right corner > More Tools > Developer Tools.
  1. Click Console in the top menu bar of Chrome Developer Tools.
  2. Paste one of the following scripts into the console and press Enter.

To download a JSON file with search engine settings:

(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));
    });
}());

To import settings from a JSON file created using the script above:

(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]);
  });
}());

Notes

  • I tested the scripts in Chrome 75.0.3770.100 on Windows 8.1.
  • The scripts export and import search enines in the Other Search Engines section only but they can easily be tweaked to include default search engines as well.
  • Do not try to distribute the scripts as bookmarklets, bookmarklets do not execute on chrome:// URLs (been there, done that).
sferencik
  • 194
  • 8
Petr Srníček
  • 389
  • 3
  • 5
  • These instructions worked perfectly well for me, chrome version 74. – Jason Aug 05 '19 at 13:52
  • Brilliant, still works on v78 windows. – junvar Nov 26 '19 at 21:25
  • 1
    I used this to transfer my Chrome search engine settings to Chromium Edge! Brilliant. – Scott Rhee Jan 08 '20 at 23:23
  • **Clipboard** copy variant: `settings.SearchEnginesBrowserProxyImpl.prototype.getSearchEnginesList() .then((searchEngines) => { /* in one line */ result = JSON.stringify(searchEngines.others); /* with linebreaks and indentation */ result = searchEngines.others; }); copy(result); ` (I added and activated an option to leave the linebreaks and indentation.) Paste just this into the console (++). – Aaron Thoma Feb 08 '20 at 21:20
  • I can download the JSON from Chrome, but not from Chromium Edge. `VM277:12 Uncaught ReferenceError: settings is not defined at exportSEs (:12:3) at :16:2` – JinSnow Apr 24 '20 at 13:44
  • This sweet script is still working in v81 – Ahmed May 06 '20 at 18:30
  • Not working anymore in v83: after running the import script in console I get the error `Uncaught (in promise) TypeError: chrome.send is not a function` – Marco Lackovic Jun 24 '20 at 11:55
  • 1
    @MarcoLackovic Both scripts still work in my Chrome 83.0.4103.116 (64-bit) on Windows 8.1. Are you sure you ran the script in the console of the search engine settings page (`chrome://settings/searchEngines`)? The `chrome.send()` method is not available in the console for ordinary pages. – Petr Srníček Jun 24 '20 at 17:13
  • @PetrSrníček that was it, thanks a lot! Somehow I missed that step, my bad :/ – Marco Lackovic Jun 25 '20 at 05:35
  • Brilliant. Please consider extending this answer to allow for save and restore (erasing and replacing totally) default engines as well. – Olivier Cailloux Jul 26 '20 at 15:22
  • 4
    @OlivierCailloux Thanks for the suggestion. Unfortunately, the export script ceased to work in the latest stable version of Chrome (84). Since the script now only works in legacy versions, I don't think that extending it is worth the effort. I will update my answer if I ever find a way to support current Chrome. – Petr Srníček Jul 27 '20 at 14:46
  • Importing my JSON (which I'd previously exported from Windows Chrome) worked for me just now in Windows Brave (Version 1.14.84 Chromium: 85.0.4183.121 (Official Build) (64-bit)). Thanks! – Ryan Oct 07 '20 at 14:21
  • 2
    @PetrSrníček I made a fairly gross DOM traversal to get the export working again for Chrome 88 https://superuser.com/a/1626575/55621. Feel free to improve on this and update this answer. This saved me an enormous amount of time (I use Chrome search engines as hotkeys...and tend to have 50-100 of them). – Jacob Dalton Feb 16 '21 at 20:51
  • so simple! Thanks google – Hicsy Mar 01 '22 at 00:04
  • When trying to run the import on Mac Chrome 113.0.5672.63 (Official Build) (x86_64), I get: VM62:30 Uncaught (in promise) TypeError: chrome.send is not a function – Ryan May 08 '23 at 18:18
  • Ahh, it was because I forgot to run it from the tab that was open to chrome://settings/searchEngines . This answer still works. Thanks! – Ryan May 08 '23 at 21:55
14

Here's a single command to export your chrome search engines as CSV on linux:

sqlite3 -csv ~/.config/chromium/Default/Web\ Data 'select short_name,keyword,url from keywords' > ~/search-engines.csv

You need sqlite3 installed. Replace ~/.config/chrome with the corresponding Windows path if you're on Windows. Should be something like %AppData%\Local\Google\Chrome\User Data

Exporting as SQL for re-importing elsewhere

Instead of exporting to CSV, you could export to sqlite insert statements:

(printf 'begin transaction;\n'; sqlite3 ~/.config/chromium/Default/Web\ Data 'select short_name,keyword,url,favicon_url from keywords' | awk -F\| '{ printf "insert into keywords (short_name, keyword, url, favicon_url) values ('"'"%s"'"', '"'"%s"'"', '"'"%s"'"', '"'"%s"'"');\n", $1, $2, $3, $4 }'; printf 'end transaction;\n') > ~/search-engine-export.sql

Then copy ~/search-engine-export.sql to the other machine, and import with this command:

sqlite3 ~/.config/chromium/Default/Web\ Data < search-engine-export.sql

Making sure to replace the Web Data path with the one on your machine as described above.

William Casarin
  • 990
  • 1
  • 8
  • 15
  • Worked great for me! And I'd like to give a plug for WSL on Windows 10, which essentially makes this a Windows-native solution. Would you also share the command to import? – tbc0 Sep 12 '18 at 19:11
  • 1
    @tbc0 I've added import instructions as well. I haven't tested on WSL but it should work in theory... – William Casarin Sep 13 '18 at 19:41
  • 2
    You may have to handle the ' character. You can add this in your awk `function esc(s){gsub("\x27","\x27\x27",s);return s}` for $1 and $2 ====> esc($1), esc($2) – Yzmir Ramirez Mar 03 '19 at 06:31
  • 1
    FWIW, for the Mac, I wanted to introspect on the values, and used the SQLIte Manager add-on to read the SQLite file at path `~/Library/Application Support/Google/Chrome/Default/Web Data`. – Brett Zamir Dec 30 '20 at 14:14
  • This still works for the export but not the import because Chrome overwrites `Web Data` on restart. – sferencik May 03 '22 at 11:07
11

...piggybacking off of https://superuser.com/a/1458616/55621 but trying to update it to work with current versions of Chrome. This worked circa Chrome 88 on a Mac.

To download a JSON file with search engine settings:

(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();
  }

  let searchEngines = [];
  document.querySelector('settings-ui').shadowRoot
    .querySelector('settings-main').shadowRoot
    .querySelector('settings-basic-page').shadowRoot
    .querySelector('settings-search-page').shadowRoot
    .querySelector('settings-search-engines-page').shadowRoot
    .querySelector('settings-search-engines-list#otherEngines').shadowRoot
    .querySelectorAll('settings-search-engine-entry')
    .forEach($el => searchEngines.push(
      {
        name: $el.shadowRoot.querySelector('#name-column').textContent,
        keyword: $el.shadowRoot.querySelector('#keyword-column').textContent,
        url: $el.shadowRoot.querySelector('#url-column').textContent
      })
    )

  downloadData('search_engines.json', JSON.stringify(searchEngines));
}());

To import settings from a JSON file created using the script above:

(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]);
  });
}());

This is highly likely to break with succeeding versions of Chrome, and there's probably a better way to traverse the dom.

sferencik
  • 194
  • 8
Jacob Dalton
  • 221
  • 2
  • 5
  • Poggers. Thank you so much. – Raymo111 Mar 15 '21 at 15:24
  • @Jacob Dalton Trying the import function on Firefox give me the following error: ` picker was blocked due to lack of user activation.`. I am using Firefox 87.0 – Swaranga Sarma Apr 05 '21 at 08:53
  • @SwarangaSarma this an import process for Chrome. Complete the import process in Chrome, the export bookmarks (generates an html file, and then import into Firefox. – Jacob Dalton Apr 05 '21 at 14:10
  • @JacobDalton - I see. Thank you. When I run this on Chrome. I do get the dialog box to select the search_engines.json file but once I complete that what should I expect? It just seems to exit. No errors on the console. – Swaranga Sarma Apr 05 '21 at 17:16
  • This only works if there are very few bookmarks. The Sqlite answers appear to work with more. – Raymo111 Apr 12 '21 at 00:42
  • Amazing. Thank you so much. Worked like a charm on Chrome 94.0.4606.81 with Mac OS 11.4 and saved me endless frustration. – shiri Oct 27 '21 at 15:15
  • Still working on Chrome 100, with a huge number of search engines. Thanks a lot!! – Adam Spiers Apr 12 '22 at 23:38
  • 1
    Export snippet updated for Chrome v 112.0.5615.49 on macOS below : https://superuser.com/a/1779104/44976 – Ashutosh Jindal Apr 15 '23 at 11:54
  • @AshutoshJindal Great job it worked. Your export script is still working and it's compatible with this import script. – Martin Braun May 07 '23 at 03:50
  • When trying to run the import on Mac Chrome 113.0.5672.63 (Official Build) (x86_64), I get: VM62:30 Uncaught (in promise) TypeError: chrome.send is not a function – Ryan May 08 '23 at 18:18
  • Never mind! https://superuser.com/questions/280694/how-can-i-share-my-google-chrome-search-engine-entries/1641015#comment2785304_1458616 – Ryan May 08 '23 at 21:56
6

Use Google Takeout https://takeout.google.com to export your Chrome Search Engines to a json file.

Select Chrome, and either select All Chrome data included, or SearchEngines.

The export will contain a SearchEngines.json file.

enter image description here enter image description here enter image description here

Rob Bednark
  • 173
  • 1
  • 5
  • 1
    OMG this is SO easy!! I was then able to prune and filter them as i felt comfortable, and best yet, i didnt need any tools! Is there a recommended way to import them into a new profile? – Hicsy Mar 01 '22 at 00:13
6

It's possible, but it's enough of a pain that you won't want to.

  1. Find the Web Data file in your Chrome profile. In Windows 7 it will be here: "%USERPROFILE%\AppData\Local\Google\Chrome\User Data\Default\Web Data"

  2. Open the file with an SQLite program like SQLite Studio or sqlite in Ubuntu (sudo apt-get install sqlite) and export the keywords table in SQLite Studio or run this command in Linux: sqlite3 "Web Data" ".dump keywords" > keywords.sql SQLite Studio export dialog

  3. Have your colleagues import the keywords, doing the reverse of this process.

Like I said, possible, but painful.

I wrote a Javascript parser to convert the SQL from Web Data into the nearly universal Netscape Bookmark File Format in HTML (ironic that the definitive standard for that format seems to be Microsoft) if you're interested in getting the keywords into other browsers like Firefox or Opera.

If you're interested in an alternative solution, I created Shortmarks to allow you to use the same set of custom search engines in any browser, and I plan to implement the ability to share with others soon. The upcoming release in a few days will have the import code I mentioned above as soon as I'm finished testing the new features.

Dan H
  • 2,104
  • 14
  • 15
  • 1
    Although I wish Google made it easier, I didn't personally feel "it's enough of a pain that I won't want to try". Patrick's answer was very helpful for me: https://superuser.com/a/688270/74576 – Ryan May 21 '17 at 16:22
  • William's answer https://superuser.com/a/1350144/92959 was totally easy. I found Patrick's answer to be very complex compared with William's. – tbc0 Sep 12 '18 at 19:15
  • Would you be open to sharing the JS parser? It sounds like it's exactly what I need! – Marcus Mangelsdorf Nov 25 '20 at 15:32
5

Based on https://superuser.com/a/1626575/44976

This covers exporting only (since for my use-case I was looking to export search engines from Chrome to Firefox)

For Chrome 112.0.5615.49 the following snippets worked on macOS. Execute in DevTools console after navigating to chrome://settings/searchEngines

Export Search Engines

(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();
  }

  let searchEngines = [];
  document.querySelector('settings-ui').shadowRoot
    .querySelector('settings-main').shadowRoot
    .querySelector('settings-basic-page').shadowRoot
    .querySelector('settings-search-page').shadowRoot
    .querySelector('settings-search-engines-page').shadowRoot
    .querySelector('settings-search-engines-list').shadowRoot
    .querySelectorAll('settings-search-engine-entry')
    .forEach($el => searchEngines.push(
      {
        name: $el.shadowRoot.querySelector('#name-column').textContent,
        keyword: $el.shadowRoot.querySelector('#shortcut-column').textContent,
        url: $el.shadowRoot.querySelector('#url-column-padded').textContent
      })
    )

  downloadData('search_engines.json', JSON.stringify(searchEngines));
}());

Export Site Search

The only difference between the following snippet and the one above is the target for iterating has #activeEngines (which results in Site Search being exported and not Search Engines)

(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();
  }

  let searchEngines = [];
  document.querySelector('settings-ui').shadowRoot
    .querySelector('settings-main').shadowRoot
    .querySelector('settings-basic-page').shadowRoot
    .querySelector('settings-search-page').shadowRoot
    .querySelector('settings-search-engines-page').shadowRoot
    .querySelector('settings-search-engines-list#activeEngines').shadowRoot
    .querySelectorAll('settings-search-engine-entry')
    .forEach($el => searchEngines.push(
      {
        name: $el.shadowRoot.querySelector('#name-column').textContent,
        keyword: $el.shadowRoot.querySelector('#shortcut-column').textContent,
        url: $el.shadowRoot.querySelector('#url-column-padded').textContent
      })
    )

  downloadData('search_engines.json', JSON.stringify(searchEngines));
}());
Ashutosh Jindal
  • 1,011
  • 8
  • 13
  • 1
    Nice. Even worked today to migrate from Chrome (`112.0.5615.49 (Official Build) (arm64)`) to Arc (`Version 0.98.2 (38335); Chromium Engine Version 112.0.5615.121`) due to them [finally adding site search to the latter](https://resources.arc.net/en/articles/7183263-site-search-directly-search-any-website). – ijoseph Apr 19 '23 at 23:03
  • @ijoseph Which one of these many scripts did you use to import _into_ Arc? – NReilingh May 22 '23 at 13:21
  • 1
    nvm -- was able to use the [import section of this answer](https://superuser.com/a/1720565/4782) in Arc successfully. – NReilingh May 22 '23 at 13:26
  • @NReilingh great question. Don't remember tbh, and I should have listed it; I'm glad you did. – ijoseph May 22 '23 at 22:06
  • Thank you. The code you wrote is very user-friendly – if_ok_button Jun 23 '23 at 01:27
4

An update for June 7th, 2022 on Chrome 103.0:

Export

Use the method in this answer to get SearchEngines.json.

Import

I had to modify this answer's import code to the following:

(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["Search Engines"].forEach(({ short_name, keyword, url }) => {
        /* Actual search engine import magic */
        chrome.send('searchEngineEditStarted', [-1]);
        chrome.send('searchEngineEditCompleted', [short_name, keyword, url]);
    });
}());

Run this in the Chrome console on chrome://settings/searchEngines.

Erik Nomitch
  • 141
  • 2
4

I did following to share my Google Chrome search engine entries and it worked perfectly fine for me:

  1. WINDOWS XP: Go to C:\Documents and Settings\MyUserName\Local Settings\Application Data\Google\Chrome\User Data\Default

    ON WINDOWS 7: Go to C:\Users\MyUserName\AppData\Local\Google\Chrome\User Data\Default

  2. Copy these 3 files: Preferences, Web Data and Web Data-journal

  3. Put those 3 files onto the target machine

Kuldeep Jain
  • 149
  • 2
3

For me, I'm on Windows 10 and I wanted to copy search engines from my personal chrome profile to my corporate chrome profile. I did the following:

  1. I downloaded SQLite from https://www.sqlite.org/download.html (under "Precompiled Binaries" with the description "A bundle of command-line tools for managing SQLite database files"). I unziped it to c:\utils that's already in my path

  2. I opened up cmd.exe

  3. I changed directory to my default (personal) chrome profile

    cd "%USERPROFILE%\AppData\Local\Google\Chrome\User Data\Default"
    
  4. I exited Chrome entirely (even in the tray). Also, keep a copy of these instructions (or open them in a different browser) because you'll loose them.

  5. I ran the following:

    sqlite3 "Web Data" ".dump keywords" > c:\keywords.sql
    
  6. I changed to the new profile:

    cd "..\Profile 2\"
    
  7. I ran this:

    sqlite3.exe "Web Data" < c:\keywords.sql
    

    I got the following errors, which are okay:

    Error: near line 4: UNIQUE constraint failed: keywords.id
    Error: near line 5: UNIQUE constraint failed: keywords.id
    Error: near line 6: UNIQUE constraint failed: keywords.id
    Error: near line 7: UNIQUE constraint failed: keywords.id
    Error: near line 8: UNIQUE constraint failed: keywords.id
    

    If you get more errors, that means that you added search engines to your new profile. Delete them all, including these new ones just added and re-run this step. Or edit the SQL file by hand.

  8. I fired Chrome back up and now my search keywords work fine.

Giacomo1968
  • 53,069
  • 19
  • 162
  • 212
3

Piggybacking on a piggyback (https://superuser.com/a/1626575/915054) -- this works on Chrome 101. I just added an extra array to it.

//modified from https://superuser.com/a/1626575
(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();
    }
    let searchEngines = []
    let searchElement = document.querySelector('settings-ui').shadowRoot
        .querySelector('settings-main').shadowRoot
        .querySelector('settings-basic-page').shadowRoot
        .querySelector('settings-search-page').shadowRoot
        .querySelector('settings-search-engines-page').shadowRoot
        .querySelectorAll('settings-search-engines-list')
    for (let i = 0; i < searchElement.length; i++) {
        searchElement[i].shadowRoot.querySelectorAll('settings-search-engine-entry')
            .forEach($el => searchEngines.push({
                name: $el.shadowRoot.querySelector('#name-column').textContent,
                keyword: $el.shadowRoot.querySelector('#keyword-column').textContent,
                url: $el.shadowRoot.querySelector('#url-column').textContent
            }))
    }
    downloadData('search_engines.json', JSON.stringify(searchEngines));
}());
(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]);
    });
}());
sferencik
  • 194
  • 8
  • As of May 2022 this seems like the only working solution here. It's a very minor tweak of https://superuser.com/a/1626575/915054, which has a tiny problem (probably due to a change in Chrome). Going forward it would be best to _edit_ the solution rather than create new "piggy-backing" ones. (Sadly David probably didn't have high enough reputation score for editing the previous answers.) – sferencik May 30 '22 at 10:56
  • I used this for import but as of June 2022 this only worked with a few modifications. See my answer: https://superuser.com/a/1725276/645282 – Erik Nomitch Jun 08 '22 at 02:08
2

Chrome 100, working import / export:

Note: All the other answers weren't working so here's a strategy to debug if this ever stops working:

  1. Hijack chrome.send and then add a search engine and watch the logs:
let oldsend = chrome.send;
chrome.send = (...args) => {
   console.log("[chrome.send], message: %o, arguments: %o", args[0], args[1]);
   chrome.send(...args);
}

// Now add search engine and watch console logs, as of writing this is what's being called:
/*
chrome.send("searchEngineEditStarted", [-1]);
// Waits for you to click the save button, then:
chrome.send("searchEngineEditCompleted", ["Title", "keyword", "url with %s"]);
*/
  1. Now just replicate this to import search engines
  2. To export search engines find the element with the inspector, then right click and select "Copy JS path", then change the last .querySelector to .querySelectorAll and remove the :nth-of-type(__) from it. Now just do some element mapping.

Anyways, here are the working functions to import and export in Chrome 100:

Export:

function exportSearchEngines() {
    return [
        ...document
            .querySelector("body > settings-ui")
            .shadowRoot.querySelector("#main")
            .shadowRoot.querySelector("settings-basic-page")
            .shadowRoot.querySelector(
                "#basicPage > settings-section.expanded > settings-search-page"
            )
            .shadowRoot.querySelector(
                "#pages > settings-subpage > settings-search-engines-page"
            )
            .shadowRoot.querySelector("#activeEngines")
            .shadowRoot.querySelectorAll(
                "#containerWithCollapsibleSection > div > settings-search-engine-entry"
            ),
        ...document
            .querySelector("body > settings-ui")
            .shadowRoot.querySelector("#main")
            .shadowRoot.querySelector("settings-basic-page")
            .shadowRoot.querySelector(
                "#basicPage > settings-section.expanded > settings-search-page"
            )
            .shadowRoot.querySelector(
                "#pages > settings-subpage > settings-search-engines-page"
            )
            .shadowRoot.querySelector("#activeEngines")
            .shadowRoot.querySelectorAll(
                "#containerWithCollapsibleSection > iron-collapse > div > settings-search-engine-entry"
            ),
    ]
        .map((i) => i.shadowRoot.querySelector("div"))
        .map((i) => ({
            url: i.querySelector("#url-column").innerText,
            name: i.querySelector("#name-column").innerText,
            keyword: i.querySelector("#keyword-column").innerText,
        }));
}

Import:

async function importSearchEngine({name, keyword, url}){
    chrome.send("searchEngineEditStarted", [-1]);
    //The awaits are to prevent chrome from crashing. Don't mess with those.
    await new Promise(r => setTimeout(r, 100));
    chrome.send("searchEngineEditCompleted", [name, keyword, url]);
    await new Promise(r => setTimeout(r, 500));
}
Explosion
  • 121
  • 1
1

I wrote a python script which loads definitions from JSON data. Now you can manage your configuration as code:

https://gist.github.com/ninowalker/9952bf435f8acffa3ef59d6c538ca165

This is idempotent (e.g. can be run multiple times; wont add duplicates by keyword).

Works with python2 and OSX. Can be modified to support other platforms.

Nino Walker
  • 119
  • 2
1

This is how I do it (I don't remember where I found it).

  1. Create a script export_chrome_search_engines.sh:

    #!/bin/sh
    
    DESTINATION=${1:-./keywords.sql}
    TEMP_SQL_SCRIPT=/tmp/sync_chrome_sql_script
    echo "Exporting Chrome keywords to $DESTINATION..."
    cd ~/.config/google-chrome/Default
    echo .output $DESTINATION > $TEMP_SQL_SCRIPT
    echo .dump keywords >> $TEMP_SQL_SCRIPT
    sqlite3 -init $TEMP_SQL_SCRIPT Web\ Data .exit
    rm $TEMP_SQL_SCRIPT
    
  2. Create a script import_chrome_search_engines.sh:

    #!/bin/sh
    if ps -x | grep -v grep | grep Google\ Chrome > /dev/null; then
        echo "Close Chrome and try again..."
        exit 1
    fi
    
    SOURCE=${1:-./keywords.sql}
    #SOURCE=$1
    TEMP_SQL_SCRIPT=/tmp/sync_chrome_sql_script
    echo
    echo "Importing Chrome keywords from $SOURCE..."
    cd ~/.config/google-chrome/Default
    echo DROP TABLE IF EXISTS keywords\; > $TEMP_SQL_SCRIPT
    echo .read $SOURCE >> $TEMP_SQL_SCRIPT
    sqlite3 -init $TEMP_SQL_SCRIPT Web\ Data .exit
    rm $TEMP_SQL_SCRIPT
    
  3. Make them executable:

    chmod +x export_chrome_search_engines.sh import_chrome_search_engines.sh 
    
  4. To export, shut down Chrome and run:

    ./export_chrome_search_engines.sh
    cp ~/.config/google-chrome/Default/keywords.sql /tmp/
    
  5. To import, shut down Chrome and run:

    cp /tmp/keywords.sql  ~/.config/google-chrome/Default
    ./import_chrome_search_engines.sh
    
0

On macOS you can use chrome_se_export.py to extract all search engine entries.

The script basically extracts all rows1 from the keywords table of a Chrome configuration database and saves them as a JSON file.

The JSON file includes the entries listed in the sections Search engines, Site Search and Inactive shortcuts of the Manage search engines and site search page in Chrome Settings.

Alternatively you could also extract entries with sqlite3.2

sqlite3 ~/Library/Application\ Support/Google/Chrome/Default/Web\ Data 'select short_name, keyword, url from keywords;'

Analogous to this approach you could create a script to import the entries from the JSON file back into the database.


Tested with Chrome 113 on macOS Catalina 10.15.7

1. Excluding entries without a search query term (%s), so you might want to remove if re.search(r'{searchTerms}', kw[4]) to include those. An entry that has a search term %s in the GUI should have a {searchTerms} in the url column of the keywords table in the database.

2. Chrome must be closed or else the database will be locked. If you don't want to quit Chrome you could make a copy of the database.

Stefan Schmidt
  • 623
  • 5
  • 12
-2

As of now, no you cannot. However, you can share bookmarks with your colleagues.

Link to Google Bookmark sharing as of now, Google App users are not able to share bookmarks, or lists of bookmarks.

wizlog
  • 13,277
  • 24
  • 77
  • 116