Custom Keyword Triggers with Chromium's Omnibox API

This article provides a practical guide on how developers can use the Chromium Omnibox extension API to register and manage custom keyword search triggers directly within the browser's address bar. It covers the entire implementation process, starting from declaring the trigger keyword in the extension's manifest file to writing the background service worker logic that intercepts user keystrokes, provides real-time search suggestions, and executes actions when a user makes a selection.

1. Registering the Keyword in the Manifest

To initialize the Omnibox API, you must declare the "omnibox" field in your extension's manifest.json file. This field takes an object defining the "keyword" string. Once the extension is loaded, typing this keyword into the Chromium address bar followed by the Tab or Space key activates your extension's custom search mode.

{
  "name": "Custom Omnibox Search",
  "version": "1.0",
  "manifest_version": 3,
  "icons": {
    "16": "icon16.png"
  },
  "background": {
    "service_worker": "background.js"
  },
  "omnibox": {
    "keyword": "find"
  }
}

Chromium automatically uses the 16x16 pixel icon defined in the "icons" field to display next to your extension's suggestions in the address bar dropdown.

2. Setting a Default Suggestion

You can customize the first line that appears in the address bar dropdown immediately after the user activates your keyword, even before they finish typing their query. Use the chrome.omnibox.setDefaultSuggestion() method inside your background service worker (background.js).

chrome.omnibox.onInputStarted.addListener(() => {
  chrome.omnibox.setDefaultSuggestion({
    description: "Search my custom database for: %s"
  });
});

The %s placeholder is automatically replaced by whatever text the user is currently typing.

3. Providing Real-Time Suggestions

As the user types after triggering the keyword, the chrome.omnibox.onInputChanged event fires. This listener receives the user's current text input and a suggest callback function. You use the suggest function to pass an array of SuggestResult objects back to the browser to populate the dropdown menu.

chrome.omnibox.onInputChanged.addListener((text, suggest) => {
  if (!text) return;

  const results = [
    {
      content: `https://example.com/search?q=${encodeURIComponent(text)}`,
      description: `Search Example for <match>${text}</match> - <dim> Instant Result</dim>`
    },
    {
      content: `https://example.com/docs/${encodeURIComponent(text)}`,
      description: `Open documentation for <url>https://example.com/docs/${text}</url>`
    }
  ];

  suggest(results);
});

Each SuggestResult object requires two properties:

  • content: The string value passed to your extension when the user selects this specific suggestion. This is not displayed to the user.
  • description: The text displayed in the Omnibox dropdown. You can style this text using three specific XML-style tags: <match> (bolds matching text), <dim> (mutes helper text), and <url> (formats text like a webpage link).

4. Handling User Selection

When the user presses Enter—either right after typing their query or after using the arrow keys to highlight one of your provided suggestions—the chrome.omnibox.onInputEntered event triggers.

This listener receives two arguments: the text (which is either the raw input or the content property of a selected suggestion) and the disposition (how the user wants the action handled based on keyboard shortcuts like Alt+Enter or Ctrl+Enter).

chrome.omnibox.onInputEntered.addListener((text, disposition) => {
  let targetUrl = text;

  // If the user didn't select a pre-formatted URL suggestion, build the URL
  if (!text.startsWith("http")) {
    targetUrl = `https://example.com/search?q=${encodeURIComponent(text)}`;
  }

  switch (disposition) {
    case "currentTab":
      chrome.tabs.update({ url: targetUrl });
      break;
    case "newForegroundTab":
      chrome.tabs.create({ url: targetUrl });
      break;
    case "newBackgroundTab":
      chrome.tabs.create({ url: targetUrl, active: false });
      break;
  }
});

5. Cleaning Up Cancelled Inputs

If a user activates your keyword, types a query, and then deletes the text or clicks away from the address bar without pressing Enter, the chrome.omnibox.onInputCancelled event is fired. Developers use this listener to abort pending network requests or reset temporary variables stored in the background script.

chrome.omnibox.onInputCancelled.addListener(() => {
  // Clean up any temporary state or abort fetch requests here
  console.log("User cancelled the Omnibox input.");
});