Registering an Omnibox Keyword
Choose and declare an omnibox keyword for an MV3 extension — keyword rules and collisions, the default suggestion, teaching users the keyword exists, and measuring whether they use it.
Table of Contents
The omnibox keyword is a single line in the manifest and the most consequential naming decision in a search-shaped extension. Too long and nobody types it; too common and it hijacks ordinary searches — a user typing “go to the bank” finds your go keyword swallowing the query. Once shipped it is effectively permanent, because users build muscle memory around it. And a keyword nobody knows about is a feature nobody uses: the browser does nothing to advertise it. This guide is part of omnibox and address bar integration.
What makes a good keyword
Step-by-step
1. Declare the keyword
1{
2 "manifest_version": 3,
3 "omnibox": { "keyword": "docs" },
4 "background": { "service_worker": "sw.js", "type": "module" }
5}
Execution context: parsed at install. The keyword must be non-empty; use lower-case ASCII letters for portability. The user activates it by typing the keyword followed by Tab or Space — at which point the address bar shows your extension’s name and routes input to your listeners.
2. Set a default suggestion that explains itself
The first row the user sees after activating the keyword is the default suggestion. It should say what Enter will do, in words that also teach what the keyword is for.
1chrome.omnibox.onInputStarted.addListener(() => {
2 chrome.omnibox.setDefaultSuggestion({
3 description: "Search the extension docs for <match>%s</match> — or type an API name like <dim>alarms.create</dim>",
4 });
5});
Execution context: the service worker, registered at the top level. %s is replaced with the text typed so far. The <match> and <dim> tags are the omnibox’s own markup, covered in providing omnibox suggestions asynchronously.
3. Prepare the index when the keyword activates
onInputStarted fires the moment the user presses Tab after the keyword — before the first character of the query. It is the ideal moment to warm anything the suggestion path needs.
1let indexPromise = null;
2chrome.omnibox.onInputStarted.addListener(() => {
3 indexPromise ??= loadIndex(); // storage read, not a network fetch
4});
5
6async function loadIndex() {
7 const { docIndex } = await chrome.storage.local.get("docIndex");
8 return docIndex ?? [];
9}
Execution context: the service worker. The memoised promise is lost on eviction and recreated on the next activation, which costs one storage read. Keeping the index in storage.local rather than fetching it means the first suggestion does not wait on the network.
4. Teach users the keyword exists
The browser does not announce extension keywords anywhere a user would notice. If you do not tell users, most will never find it.
1// popup.js — a one-line hint, shown until the user has used the keyword once
2const { omniboxUsed } = await chrome.storage.local.get("omniboxUsed");
3if (!omniboxUsed) {
4 hint.textContent = "Tip: type “docs” then Space in the address bar to search without opening this.";
5 hint.hidden = false;
6}
1// sw.js — record first use, which retires the hint
2chrome.omnibox.onInputEntered.addListener(async () => {
3 await chrome.storage.local.set({ omniboxUsed: true });
4});
Execution context: the popup and the service worker. Retiring the hint after the first real use stops it becoming wallpaper. The first-run page is another good place to mention it, as described in showing a first-run setup page after install.
5. Measure whether it earns its place
A small, local counter of omnibox sessions against popup opens tells you whether the keyword is actually used — without any telemetry leaving the device.
1chrome.omnibox.onInputEntered.addListener(async () => {
2 const { usage = { omnibox: 0 } } = await chrome.storage.local.get("usage");
3 usage.omnibox += 1;
4 await chrome.storage.local.set({ usage });
5});
Execution context: the service worker. Surfacing these counts in a diagnostics view — or in an opt-in usage report — tells you whether to invest in the omnibox experience or in the popup. The privacy constraints on reporting are in reporting errors without breaking your privacy policy.
Choosing a keyword that survives contact with users
Three failure modes are common enough to plan against.
Collisions with ordinary typing. Some users press Space immediately after typing a word, and if that word is your keyword, their search is intercepted. Short common English words — go, to, my, new, the — collide constantly. A quick test: would a user ever start an ordinary search with this word followed by a space? If yes, pick another.
Collisions with other extensions and search engines. Chrome resolves keyword conflicts in favour of whichever was registered first and does not warn the second. Users who also run a popular extension with the same keyword will simply find yours never activates. Distinctive keywords avoid most of this; your product name, shortened, is usually the best candidate.
Localisation. The keyword cannot be localised through _locales in most engines, and non-ASCII keywords are awkward on many keyboard layouts. Choose something typable everywhere — Latin letters, no accents — and accept that it is the same across languages.
The keyword is also very hard to change once shipped. Users who learned it will find the old one silently stops working. If you must change it, keep the old behaviour discoverable — a popup notice for a release or two — rather than breaking the habit without explanation.
Cross-browser variation
- Chrome / Edge:
omnibox.keywordin the manifest; conflicts resolve to the first registrant silently.onInputStarted,onInputChanged,onInputEntered,onInputCancelledandsetDefaultSuggestionare all available. - Firefox:
browser.omniboxwith the same manifest key and events. Firefox shows the extension’s icon in the address bar when the keyword is active. - Safari: no omnibox API. A Safari build should drop the
omniboxkey and point users at a keyboard shortcut for the popup instead, as covered in omnibox support and alternatives across browsers. - All three: the keyword is global to the browser profile. Test it alongside the extensions your users are likely to run.
Verification
- Type the keyword and Space in the address bar; the extension’s name should appear and the default suggestion should show.
- Confirm the listeners are registered and the default is set:
1chrome.omnibox.setDefaultSuggestion({ description: "probe <match>%s</match>" });
2// then type the keyword + Space + "x" and confirm "probe x" appears
Execution context: the service worker console. If nothing appears, check for a keyword conflict with another extension or a search engine shortcut.
- Type an ordinary search that starts with a common word and confirm your keyword does not intercept it.
- Open the popup before and after first use and confirm the hint disappears.
FAQ
Can users change my keyword?
Not in most Chrome versions — extension keywords are fixed by the manifest. That is part of why choosing well matters.
Can one extension have several keywords?
No. Use prefixes inside the query instead — docs api:alarms, docs guide:popup — and parse them in onInputChanged.
Does the keyword need to match my extension’s name?
No, but a keyword derived from the name is easier to remember and less likely to collide.
What happens if a search engine uses the same keyword?
User-defined search-engine shortcuts and extension keywords share one namespace in the address bar. Whichever claims it first wins, and the other simply never triggers. There is no API to detect this, so distinctiveness is the only defence.
Related
- Providing omnibox suggestions asynchronously — the suggestion path the keyword opens.
- Handling omnibox input entered navigation — what happens on Enter.
- The _execute_action command and the four-shortcut limit — the other keyboard entry point.
- Omnibox and address bar integration — the parent guide.