Site Search in Omnibox Explainer
This document provides a technical overview of the Omnibox Scoped Search (also referred to as "site search" or "keyword search") functionality for Chrome engineers. The architecture and code paths described are shared across Windows, Mac, Linux, and ChromeOS. It is based on a detailed code analysis as of this writing (2025-09-24) covers two primary scenarios: scoped search via traditional keywords (e.g. youtube.com) and scoped search via built-in keywords (also known as "starter pack" keywords), which use the "@" syntax (e.g., @history).
Types of Keywords
Keywords in the Omnibox come from various sources and have different behaviors. Here's a breakdown of the most common types:
- Starter Packs: Built-in keywords with the "@" prefix (e.g.,
@bookmarks,@history). - Prepopulated: Keywords for common search engines (e.g.,
bing.com,yahoo.com). - User Created (Traditional): A user-created keyword where the template URL contains a %s
placeholder (e.g.,
youtubesearch). - Non-substituting User Created: A user-created keyword where the template URL does not contain a %s placeholder.
- Default Search Engine (DSE): The user's currently selected default search engine, which is kind of orthogonal to the other types here.
- Extension: Keywords registered by browser extensions (e.g., an
sshkeyword registered by the Secure Shell extension). - Enterprise Policy: Keywords set by a device administrator through enterprise policies. These
can be further subdivided into:
- Aggregator: e.g.,
@agentspace. - Non-aggregator: e.g.,
microsoft-documents.
- Aggregator: e.g.,
- Admin Policy: Keywords set by an admin policy.
High-Level Overview
The Omnibox uses a sophisticated system of providers, managed by the
AutocompleteController,
to generate suggestions. Site Search functionality is primarily handled by two distinct providers:
FeaturedSearchProvider: Manages the "Omnibox Starter Pack," which provides scoped search suggestions like@history,@bookmarks, and@tabs, as well as enterprise keywords (e.g. @agentspace or facebook-internal-documents).KeywordProvider: Manages searches directed at specific, non-default search engines using keywords. This is powered by theTemplateURLService, which stores URL templates for various sites.
While KeywordProvider and FeaturedSearchProvider manage surfacing the keyword entry points, most
providers (e.g., tabs, bookmarks, history, search, ...) are responsible for populating the
suggestions when in keyword mode. e.g.
- 'youtube.com query' will be handled by search provider.
- 'youtube.com cat video' to select a past youtube navigation will be handled by a history provider.
These providers rely on the TemplateURLService, which is populated with
TemplateURL
objects. These objects can come from several sources:
- For enterprise and policy keywords, they're set by policy.
- For pre-populated keywords, they're hardcoded into the binary, but in a json or some sort of data file, not necessarily in .cc directly.
- For extensions, they come from the extensions.
The general flow is as follows:
- User types into the Omnibox.
AutocompleteControllerstarts and queries all registered providers with the user's input.FeaturedSearchProviderandKeywordProvider, among others, generateAutocompleteMatchobjects based on the input.- These matches are ranked and displayed to the user.
- When a user selects a match that happens to have a keyword chip, they will navigate to the match, ignoring the keyword chip. When a user selects the keyword chip on the match, they will enter keyword mode (to handle subsequent input) which may or may not ultimately navigate to the target site. (You can enter youtube keyword mode by typing 'youtube.com query' then select a drive.google.com document titled 'youtube.com query' that does not navigate to youtube.com.)
Key UI Component Roles
The LocationBarView is the top level component of omnibox view hierarchy. See
Overview of the OmniboxView Hierarchy
(internal document) for a picture.
-
LocationBarViewowns the omnibox view, the popup view, and selected keyword view. It is mostly responsible for updating the keyword chip in the input row (e.g., "Search History"). -
OmniboxView: This is the text field where the user types. Its implementation (e.g.,OmniboxViewViews) is responsible for rendering the user's text, and handling input. It communicates user actions, like typing, to theOmniboxEditModel. -
OmniboxPopupView: This is the dropdown list of suggestions that appears below the text field. Its implementation (e.g.,OmniboxPopupViewViews) is responsible for rendering each suggestion line (usingOmniboxResultView). It receives the list ofAutocompleteMatchobjects from the model and informs the model when the user interacts with the list (e.g., hovering or selecting a suggestion).
The OmniboxEditModel acts as a controller for these views. For example, when a user selects a
suggestion in the OmniboxPopupView, the popup notifies the model. The model then updates its
internal state and may, in turn, commands the OmniboxView to change its displayed text or show a
keyword chip.
While the view and model are mutually aware of each other to facilitate this communication, their
ownership is hierarchical to prevent circular dependencies. The OmniboxView is owned by its parent
UI component (e.g., LocationBarView). The view, in turn, owns the
OmniboxController,
which owns the OmniboxEditModel. This creates a clear ownership chain: OmniboxView →
OmniboxController → OmniboxEditModel. Communication back up the chain is handled via non-owning
raw_ptr references.
Scenario 1: Scoped Search (@history)
This scenario describes how a user can scope their search to their local browser history.
User Journey:
- User types
@hist. - An autocomplete suggestion for "Search History" appears.
- User selects this suggestion.
- The text
@historydisappears from the input field and is replaced by a "Search History" chip. - User types a query, e.g.,
foo, and presses Enter. - The browser navigates to
chrome://history/?q=foo.
Technical Deep Dive
-
Suggestion Generation (
@hist)- Component:
FeaturedSearchProvider,TemplateURLService - Mechanism: The
@prefixed suggestions are part of the "Omnibox Starter Pack" feature, which are managed as specialTemplateURLobjects.- The
TemplateURLServiceis loaded with a set of default "starter pack" engines, including one for History with the keyword@historyand a uniquestarter_pack_id. This data is loaded fromcomponents/search_engines/template_url_starter_pack_data.cc. FeaturedSearchProvider::Start()is called on input. It detects that the input starts with@and queries theTemplateURLServicefor matching keywords.- It finds the
@historyTemplateURLobject. FeaturedSearchProviderthen creates anAutocompleteMatchwith the typeAutocompleteMatch::Type::STARTER_PACK.
- The
- Component:
-
Mode Activation (Selecting the suggestion)
- Component:
OmniboxEditModel,AutocompleteController - Mechanism: When the user selects the
STARTER_PACKmatch,OmniboxEditModel::OpenMatch()is called. This activates "keyword mode" with@historyas the keyword.- The
AutocompleteControlleris restarted with the new input. It recognizes that the omnibox is in keyword mode with aTemplateURLthat has astarter_pack_idfor history. - Crucially, the controller then adjusts its logic to only run a limited set of providers
relevant to history search:
HistoryURLProvider,HistoryEmbeddingsProvider, andFeaturedSearchProvider.
- The
- Component:
-
UI State Management (The Chip and Text Replacement)
- Component:
OmniboxEditModel,OmniboxView - Mechanism: The separation between the model's state and the view's displayed text is key.
- The
OmniboxEditModelsets its internal state to keyword mode, storing@historyinternally. - It then clears the user's visible text, replacing it with an empty string.
- The model notifies the
OmniboxView, which sees that the model is in keyword mode (is_keyword_selected()is true) and renders the "Search History" chip instead of the keyword text. - Specifically, the
SelectedKeywordViewis shown. It retrieves theTemplateURLfor@history, gets its short name ("History"), and uses this to format a localized string (e.g., "Search History").
- The
- Component:
-
Final Navigation (
foo+ Enter)- Component:
HistoryURLProvider,AutocompleteController - Mechanism: As the user types
foo, theAutocompleteControllerruns the filtered set of providers (e.g.,HistoryURLProvider) against the inputfoo.HistoryURLProviderfinds matching history entries for "foo".- It creates
AutocompleteMatchobjects withdestination_urls pointing to the relevant history pages (e.g.,chrome://history/?q=foo). - When the user presses Enter, the browser navigates to the selected history result.
- Component:
Scenario 2: Keyword Search (youtube.com)
This scenario describes how a user can search a specific website directly from the Omnibox using a keyword.
User Journey:
- User performs a search on
youtube.com. - Chrome automatically generates an inactive
TemplateURLfor YouTube search by detecting the site's OpenSearch description. - The user navigates to
chrome://settings/searchEngines. - The YouTube entry appears in the "inactive" list of site search engines.
- The user explicitly activates the YouTube entry.
- Now, when the user types "you" in the Omnibox, a suggestion for
youtube.comappears with a "Search YouTube" hint, and site search is fully enabled.
Technical Deep Dive
-
Search Engine Discovery and Storage
- Component:
TemplateURLService - Mechanism: When a user submits a search form on a website that provides an
OpenSearch description document,
Chrome's renderer process can detect it and send an IPC message to the browser process. The
TemplateURLServicethen creates and stores aTemplateURLobject. This object contains the site's name, the keyword (e.g.,youtube.com), and the URL template for performing a search (e.g.,https://www.youtube.com/results?search_query={searchTerms}).
- Component:
-
Automatic Keyword Generation
- Component:
SearchEngineTabHelper,TemplateURLService - Mechanism: When a user performs a search on a website, Chrome can automatically generate a
keyword for that site.
SearchEngineTabHelper::GenerateKeywordIfNecessary()is called on navigation.- It checks if the navigation is a form submission and if a keyword can be generated from the URL.
- If so, it calls
TemplateURLService::CanAddAutogeneratedKeyword()to check if a new keyword can be added. This is to avoid adding duplicate or conflicting keywords. - If a new keyword can be added, a
TemplateURLDataobject is created and added to theTemplateURLService. - This newly created
TemplateURLis marked assafe_for_autoreplace, meaning it can be replaced by a more official keyword later (e.g., one from an OpenSearch description document). - The
is_activestatus is set tokUnspecified, so the keyword is not immediately usable.
- Component:
-
Activation
- Component:
TemplateURLService - Mechanism: A newly created
TemplateURLis not immediately active (is_activeiskUnspecified). For it to be used for keyword search, it must be activated. There are two paths to activation:- Manual Activation: This is the immediate path. When a user goes to
chrome://settings/searchEnginesand activates an entry,TemplateURLService::SetIsActiveTemplateURL()is called. This function explicitly setsis_activetokTrueand also setssafe_for_autoreplacetofalse, ensuring the user's choice is preserved. This change takes effect immediately in the current session. - Automatic Generation: As described in the previous section, keywords can be generated
automatically. However, they must be manually activated by the user in
chrome://settings/searchEngines.
- Manual Activation: This is the immediate path. When a user goes to
- Component:
-
Suggestion Generation (
youtube.com foo)- Component:
KeywordProvider - Mechanism:
KeywordProvider::Start()is called with the user's input.- It calls
AutocompleteInput::ExtractKeywordFromInput()to parse the input into a potential keyword (youtube.com) and the remaining query (foo). - It then calls
TemplateURLService::AddMatchingKeywords()with the extracted keyword. TemplateURLServicefinds the activeTemplateURLobject matchingyoutube.com.KeywordProviderreceives thisTemplateURLand proceeds to call its internalCreateAutocompleteMatch()method. This creates anAutocompleteMatchof typeAutocompleteMatch::Type::SEARCH_KEYWORD.
- It calls
- Component:
-
Final Navigation (Enter)
- Component:
KeywordProvider - Mechanism: The final URL is constructed within
KeywordProvider::FillInUrlAndContents().- This function is called by
CreateAutocompleteMatch(). - It uses the
TemplateURLReffrom theTemplateURLobject. TheReplaceSearchTerms()method is called on this reference. - This method substitutes the
{searchTerms}placeholder in the URL template with the user's query (foo). - The resulting URL (e.g.,
https://www.youtube.com/results?search_query=foo) is set as thedestination_urlof theAutocompleteMatch. When the user presses Enter, the browser navigates to this URL.
- This function is called by
- Component:
Keyword State in Core Data Structures
To fully understand the logic, it's crucial to see how keyword state is tracked within the core data
structures: AutocompleteInput and AutocompleteMatch.
AutocompleteInput
The AutocompleteInput object represents the user's query and the omnibox's state. It has two key
fields, prefer_keyword_ and allow_exact_keyword_match_, which are used to signal that when the
user is in keyword mode, providers should show more "keyword-y" suggestions. For example, a search
for 'query' should suggest 'youtube.com/q=query' instead of 'google.com/q=query' when the user is in
the YouTube keyword mode.
AutocompleteMatch
The AutocompleteMatch object represents a single suggestion and contains several nuanced fields
for managing keywords:
-
associated_keyword: This field determines which keyword to activate via the keyword chip. For example, the@historykeyword activates thechrome://history... template URL. This can be a source of confusion, because when a user types "youtube", an autocomplete match might appear that navigates to 'amazon.com/youtube' but also has a keyword chip to activate theyoutube.comkeyword. In this case,associated_keywordwill store 'youtube.com', even though the rest of the match fields are Amazon-related. -
keyword: This field tracks whichTemplateURLwas used to create the match's destination URL. For example, if the user types 'youtube.com query', thekeywordfield will track 'youtube'. This can also be confusing, because even when the user isn't in keyword mode, most search suggestions are still generated using a keyword and will have theirkeywordfield set (e.g., togoogle.comfor the default search engine). -
from_keyword: This field tracks if the match was generated while the user is in keyword mode. This is another potential point of confusion, as it can betrueeven if the match doesn't have akeywordfield set. Conversely,from_keywordcan befalseeven whenkeywordis set. In essence,from_keywordreflects the input state when the match was created, whilekeywordreflects the match's data source.
Methods for Model-View Interaction
A key aspect of the Omnibox architecture is the interaction between the OmniboxEditModel (the
model) and its two main views. The model holds the state, while the views are responsible for
rendering the UI. The views are updated via a tightly-coupled observer-like pattern, where the model
directly calls methods on the views when its state changes.
The following table summarizes the key methods that facilitate this interaction within the scope of the scenarios described in this document.
| Initiator (Caller) | Target (Callee) | Method Called | Purpose |
|---|---|---|---|
OmniboxView |
OmniboxEditModel |
OnAfterPossibleChange() |
Notifies the model of user text input. |
OmniboxEditModel |
OmniboxView |
SetWindowTextAndCaretPos() |
Instructs the text view to change its content, e.g., when entering keyword mode. |
OmniboxPopupView |
OmniboxEditModel |
OpenMatch() / SetPopupSelection() |
Notifies the model that the user has selected or highlighted a suggestion. |
OmniboxEditModel |
OmniboxPopupView |
UpdatePopupAppearance() |
Instructs the popup to redraw itself based on the model's current state. |
AutocompleteController |
OmniboxEditModel |
OnResultChanged() |
Notifies the model that the autocomplete results have changed. |
Appendix: Architecture on Chrome for Android
The architecture described above is specific to desktop platforms which use the C++ Views UI
framework. Chrome for Android has a distinct architecture where the UI is primarily implemented in
Java and built upon a Coordinator pattern. This pattern distributes responsibilities among several
specialized components, in contrast to the more monolithic OmniboxEditModel on desktop.
However, the core suggestion generation logic is shared. The C++ AutocompleteController is used by
all platforms to generate suggestion results.
The Coordinator Pattern on Android
On Android, the Omnibox (known as the Location Bar) is managed by a top-level
LocationBarCoordinator.
This coordinator owns and orchestrates a set of sub-components, each with a specific responsibility.
The responsibilities of the desktop OmniboxEditModel are split among these components:
-
LocationBarCoordinator: The overall owner and assembler. It creates the other coordinators and mediators and wires them together. -
AutocompleteCoordinator: Manages the suggestion list UI, including theOmniboxSuggestionsDropdownview. It creates and owns theAutocompleteMediator. -
AutocompleteMediator: The primary logic hub for autocomplete. It is responsible for communicating with the C++AutocompleteControllervia JNI, processing the results, and updating thePropertyModelthat drives the suggestion list UI. -
UrlBarCoordinator: Manages theUrlBarview, which is theEditTextfield the user types into. It handles text state, cursor position, and selection, reporting user input to other components. -
LocationBarMediator: A central logic hub that connects the other components. It handles events like focus changes and button clicks, and manages the overall state of the location bar that doesn't directly involve text editing or autocomplete suggestions.
Interaction Flow for Suggestions
- A user types into the
UrlBarview (managed byUrlBarCoordinator). - During initialization,
LocationBarCoordinatorsets up a listener so that text changes inUrlBarCoordinatordirectly callAutocompleteCoordinator.onTextChanged(). AutocompleteCoordinator.onTextChanged()forwards the call toAutocompleteMediator.onTextChanged().- The
AutocompleteMediatortakes the user's input and initiates a request to the shared C++AutocompleteControllerthrough the JNI bridge. - When results are ready, the C++
AutocompleteControllersends them back to theAutocompleteMediatorvia itsonSuggestionsReceivedJNI callback. - The
AutocompleteMediatorreceives theAutocompleteResult, processes it, builds a list of view models, and updates the mainPropertyModelfor the suggestion list. - The
PropertyModelchange is observed by theOmniboxSuggestionsDropdownAdapter, which then renders the final views in the suggestion dropdown list.