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.");
});