68

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

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

5
  • This is such a great question. I found ludovic.chabant.com/devblog/2010/12/29/… 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
    Commented Jul 12, 2016 at 16:03
  • Can someone create a feature request to Google so we all can upvote it there?
    – userJT
    Commented Feb 3, 2020 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: superuser.com/a/1641015/148251
    – Hicsy
    Commented Mar 1, 2022 at 0:15
  • Wait, why is no one mentioning Google's Programmable Search Engine? Or am I missing something?
    – Arctiic
    Commented Jun 8, 2022 at 5:58
  • This might be one of those questions where it's worth sorting the answers by date: superuser.com/questions/280694/…
    – mwfearnley
    Commented Nov 15, 2023 at 13:08

17 Answers 17

29

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).
18
  • These instructions worked perfectly well for me, chrome version 74.
    – Jason
    Commented Aug 5, 2019 at 13:52
  • 1
    I used this to transfer my Chrome search engine settings to Chromium Edge! Brilliant.
    – Scott Rhee
    Commented Jan 8, 2020 at 23:23
  • 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. Commented Jun 24, 2020 at 17:13
  • 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. Commented Jul 27, 2020 at 14:46
  • 2
    @PetrSrníček I made a fairly gross DOM traversal to get the export working again for Chrome 88 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). Commented Feb 16, 2021 at 20:51
15

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,is_active 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.

5
  • 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
    Commented Sep 12, 2018 at 19:11
  • 1
    @tbc0 I've added import instructions as well. I haven't tested on WSL but it should work in theory... Commented Sep 13, 2018 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) Commented Mar 3, 2019 at 6: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. Commented Dec 30, 2020 at 14:14
  • This still works for the export but not the import because Chrome overwrites Web Data on restart.
    – sferencik
    Commented May 3, 2022 at 11:07
12

...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.

11
  • Poggers. Thank you so much.
    – Raymo111
    Commented Mar 15, 2021 at 15:24
  • @Jacob Dalton Trying the import function on Firefox give me the following error: <input> picker was blocked due to lack of user activation.. I am using Firefox 87.0 Commented Apr 5, 2021 at 8: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. Commented Apr 5, 2021 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. Commented Apr 5, 2021 at 17:16
  • 1
    Export snippet updated for Chrome v 112.0.5615.49 on macOS below : superuser.com/a/1779104/44976 Commented Apr 15, 2023 at 11:54
7

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.

3
  • 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: superuser.com/a/688270/74576
    – Ryan
    Commented May 21, 2017 at 16:22
  • William's answer superuser.com/a/1350144/92959 was totally easy. I found Patrick's answer to be very complex compared with William's.
    – tbc0
    Commented Sep 12, 2018 at 19:15
  • Would you be open to sharing the JS parser? It sounds like it's exactly what I need! Commented Nov 25, 2020 at 15:32
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

1
  • 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
    Commented Mar 1, 2022 at 0:13
6

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));
}());
5
  • 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.
    – ijoseph
    Commented Apr 19, 2023 at 23:03
  • @ijoseph Which one of these many scripts did you use to import into Arc?
    – NReilingh
    Commented May 22, 2023 at 13:21
  • 1
    nvm -- was able to use the import section of this answer in Arc successfully.
    – NReilingh
    Commented May 22, 2023 at 13:26
  • @NReilingh great question. Don't remember tbh, and I should have listed it; I'm glad you did.
    – ijoseph
    Commented May 22, 2023 at 22:06
  • Thank you. The code you wrote is very user-friendly Commented Jun 23, 2023 at 1:27
5

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.

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

3
  • worked for me without "web data-jounal" (just drop both file into the "default" folder, restart chrome)
    – JinSnow
    Commented Nov 11, 2015 at 5:48
  • So awesome. Worked like charm! Thanks.
    – digitguy
    Commented Jun 30, 2020 at 0:33
  • This worked. Use "...\User Data\Profie 1" folder if you want to restore the second chrome profile
    – Faiz
    Commented Aug 18, 2020 at 21:18
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.

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]);
    });
}());
2
  • As of May 2022 this seems like the only working solution here. It's a very minor tweak of 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
    Commented May 30, 2022 at 10:56
  • I used this for import but as of June 2022 this only worked with a few modifications. See my answer: superuser.com/a/1725276/645282 Commented Jun 8, 2022 at 2: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));
}
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.

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
    
1

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

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

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.

1

This is the most current and complete solution as of time of posting (4 Jul 2024), tested on Arc/Chrome/Chromium 126. Obviously I'm just a messenger, piggybacking on piggibackings of piggybackers.

The reason I'm not editing old answers is I intend to maintain this answer going forward, so if you find that in your case this is not working, please comment to let me know and I'll update accordingly (or feel free to edit directly if you want/can).

A copy of this is also available and maintained here.

TOC

  1. Optionally export "Search engines" (note, these will be imported in the "Site Search" section) from the source browser/profile
  2. Export "Site Search" (with the exclusion of @bookmarks and @history) from the source browser/profile
  3. Optionally delete existing site searches in the target browser/profile
  4. Import engines (if you want) and searches in the target browser/profile

NOTE: you need to run the snippets below in the console. To do that, open developer tools by pressing ++I (mac) or F12 (win/linux), then select the Console tab. Place the cursor in the line with the blue , then paste the snippet you want to run in its entirety and press ENTER.

Steps

  1. go to chrome://settings/searchEngines in the source browser or profile
  2. open the console, optionally export Search engines:
(function exportSearchEngines() {
  /* 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').textContent
      })
    )

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

NOTE: Search engines will be then imported in the Site Search section.

  1. export Site Search:
(function exportSiteSearches() {
  /* 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 siteSearches = [];
  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 => {
      /* Don't export @bookmarks and @history shortcuts */
      if ($el.shadowRoot.querySelector('#shortcut-column').textContent[0] !== '@') {
        searchEngines.push(
          {
            name: $el.shadowRoot.querySelector('#name-column').textContent,
            keyword: $el.shadowRoot.querySelector('#shortcut-column').textContent,
            url: $el.shadowRoot.querySelector('#url-column').textContent
          })
        )
      }
    }

  downloadData('site_search.json', JSON.stringify(siteSearches));
}());
  1. go to the new browser or profile (again in chrome://settings/searchEngines). If you want, delete all Site search shortcuts:
(function deleteSiteSearches() {
  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 => {
      /* Don't delete @bookmarks and @history shortcuts */
      if ($el.shadowRoot.querySelector('#shortcut-column').textContent[0] !== '@') {
        $el.shadowRoot.querySelector("#delete").click()
      }
    })
}());

NOTE: You might have to run the snippet multiple times. Just hit and then ENTER until all entries disappear (@bookmarks and @history will NOT be deleted).

  1. finally, import your entries:
(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]);
  });
}());
0

EDIT: Upon rereading the thread I realized this solution is very similar to this one above. I'll leave this answer here as reference anyway.

Relatively simple sqlite3 solution

After taking a look at all the solutions in this thread, what helped me most is knowing that both the search engines and site search entries are saved in the keywords table within an sqlite3 database file. Knowing this, the solution becomes quite straight-forward:

  1. Dump keywords table to export
  2. Run the exported SQL commands to import

A. Exporting the table

  • First, you need to find where Chrome's sqlite3 database is stored in your computer.
    • In my case (Mac Sonoma 14.5, Google Chrome 125.0.6422.113), it was in ~/Library/Application Support/Google/Chrome/Default/Web Data.
  • Now, you can only access the database if Chrome is not running. Therefore, you have two options:
    • Close chrome
    • (recommended) Make a copy of the file, which won't be locked, and work with the copy. This way, you'll be able to keep looking at these instructions and don't have to close any tabs that you may not want to close
$ cd
$ cp Library/Application Support/Google/Chrome/Default/Web Data web_data
  • Now, dump the contents of the table:
$ sqlite3 web_data ".dump keywords" > old_keywords_dump.sql
  • Now transfer that file to your new computer

B. (optional) Clean up the SQL file

Because your new computer will already contain data, you may want to only append to what's already there. Therefore, my recommendation would be to:

  1. Dump the table of your new computer (like step A.) and use it as reference. You may call this file new_keyboards_dump.sql
  2. Remove the "CREATE TABLE" statement in old_keyboards_dump.sql
  3. Remove duplicate entries in old_keyboards_dump.sql that your new computer may already have—e.g. Google, Bing, Yahoo
  4. Make sure that the entries in old_keyboards_dump.sql do not cause primary key collisions with new_keyboards_dump.sql
    • In my case, I accomplished this by using a vim macro to change the id of each entry in old_keyboards_dump.sql to start above the highest entry of new_keyboards_dump.sql and go 1 by 1 from there

C. Import the entries

This last step is as simple as:

  1. Close chrome
  2. Run the sql commands in the new database
$ cd
$ sqlite3 "Library/Application Support/Google/Chrome/Default/Web Data" < old_keywords_dump.sql
  1. When you open Chrome again, you should have successfully imported all your search engines and site search entries from your other computer
-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.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .