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).
Keywords in the Omnibox come from various sources and have different behaviors. Here's a breakdown of the most common types:
@bookmarks, @history).bing.com, yahoo.com).youtube search).ssh keyword registered by the Secure Shell extension).@agentspace.microsoft-documents.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 the TemplateURLService, 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.
These providers rely on the TemplateURLService, which is populated with TemplateURL objects. These objects can come from several sources:
The general flow is as follows:
AutocompleteController starts and queries all registered providers with the user's input.FeaturedSearchProvider and KeywordProvider, among others, generate AutocompleteMatch objects based on the input.The LocationBarView is the top level component of omnibox view hierarchy. See Overview of the OmniboxView Hierarchy (internal document) for a picture.
LocationBarView owns 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 the OmniboxEditModel.
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 (using OmniboxResultView). It receives the list of AutocompleteMatch objects 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.
@history)This scenario describes how a user can scope their search to their local browser history.
User Journey:
@hist.@history disappears from the input field and is replaced by a “Search History” chip.foo, and presses Enter.chrome://history/?q=foo.Suggestion Generation (@hist)
FeaturedSearchProvider, TemplateURLService@ prefixed suggestions are part of the “Omnibox Starter Pack” feature, which are managed as special TemplateURL objects.TemplateURLService is loaded with a set of default “starter pack” engines, including one for History with the keyword @history and a unique starter_pack_id. This data is loaded from components/search_engines/template_url_starter_pack_data.cc.FeaturedSearchProvider::Start() is called on input. It detects that the input starts with @ and queries the TemplateURLService for matching keywords.@history TemplateURL object.FeaturedSearchProvider then creates an AutocompleteMatch with the type AutocompleteMatch::Type::STARTER_PACK.Mode Activation (Selecting the suggestion)
OmniboxEditModel, AutocompleteControllerSTARTER_PACK match, OmniboxEditModel::OpenMatch() is called. This activates “keyword mode” with @history as the keyword.AutocompleteController is restarted with the new input. It recognizes that the omnibox is in keyword mode with a TemplateURL that has a starter_pack_id for history.HistoryURLProvider, HistoryEmbeddingsProvider, and FeaturedSearchProvider.UI State Management (The Chip and Text Replacement)
OmniboxEditModel, OmniboxViewOmniboxEditModel sets its internal state to keyword mode, storing @history internally.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.SelectedKeywordView is shown. It retrieves the TemplateURL for @history, gets its short name (“History”), and uses this to format a localized string (e.g., “Search History”).Final Navigation (foo + Enter)
HistoryURLProvider, AutocompleteControllerfoo, the AutocompleteController runs the filtered set of providers (e.g., HistoryURLProvider) against the input foo.HistoryURLProvider finds matching history entries for “foo”.AutocompleteMatch objects with destination_urls pointing to the relevant history pages (e.g., chrome://history/?q=foo).youtube.com)This scenario describes how a user can search a specific website directly from the Omnibox using a keyword.
User Journey:
youtube.com.TemplateURL for YouTube search by detecting the site's OpenSearch description.chrome://settings/searchEngines.youtube.com appears with a “Search YouTube” hint, and site search is fully enabled.Search Engine Discovery and Storage
TemplateURLServiceTemplateURLService then creates and stores a TemplateURL object. 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}).Automatic Keyword Generation
SearchEngineTabHelper, TemplateURLServiceSearchEngineTabHelper::GenerateKeywordIfNecessary() is called on navigation.TemplateURLService::CanAddAutogeneratedKeyword() to check if a new keyword can be added. This is to avoid adding duplicate or conflicting keywords.TemplateURLData object is created and added to the TemplateURLService.TemplateURL is marked as safe_for_autoreplace, meaning it can be replaced by a more official keyword later (e.g., one from an OpenSearch description document).is_active status is set to kUnspecified, so the keyword is not immediately usable.Activation
TemplateURLServiceTemplateURL is not immediately active (is_active is kUnspecified). For it to be used for keyword search, it must be activated. There are two paths to activation:chrome://settings/searchEngines and activates an entry, TemplateURLService::SetIsActiveTemplateURL() is called. This function explicitly sets is_active to kTrue and also sets safe_for_autoreplace to false, ensuring the user's choice is preserved. This change takes effect immediately in the current session.chrome://settings/searchEngines.Suggestion Generation (youtube.com foo)
KeywordProviderKeywordProvider::Start() is called with the user's input.AutocompleteInput::ExtractKeywordFromInput() to parse the input into a potential keyword (youtube.com) and the remaining query (foo).TemplateURLService::AddMatchingKeywords() with the extracted keyword.TemplateURLService finds the active TemplateURL object matching youtube.com.KeywordProvider receives this TemplateURL and proceeds to call its internal CreateAutocompleteMatch() method. This creates an AutocompleteMatch of type AutocompleteMatch::Type::SEARCH_KEYWORD.Final Navigation (Enter)
KeywordProviderKeywordProvider::FillInUrlAndContents().CreateAutocompleteMatch().TemplateURLRef from the TemplateURL object. The ReplaceSearchTerms() method is called on this reference.{searchTerms} placeholder in the URL template with the user's query (foo).https://www.youtube.com/results?search_query=foo) is set as the destination_url of the AutocompleteMatch. When the user presses Enter, the browser navigates to this URL.To fully understand the logic, it's crucial to see how keyword state is tracked within the core data structures: AutocompleteInput and AutocompleteMatch.
AutocompleteInputThe 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.
AutocompleteMatchThe 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 @history keyword activates the chrome://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 the youtube.com keyword. In this case, associated_keyword will store ‘youtube.com’, even though the rest of the match fields are Amazon-related.
keyword: This field tracks which TemplateURL was used to create the match‘s destination URL. For example, if the user types ‘youtube.com query’, the keyword field 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 their keyword field set (e.g., to google.com for 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 be true even if the match doesn‘t have a keyword field set. Conversely, from_keyword can be false even when keyword is set. In essence, from_keyword reflects the input state when the match was created, while keyword reflects the match’s data source.
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. |
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.
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 the OmniboxSuggestionsDropdown view. It creates and owns the AutocompleteMediator.
AutocompleteMediator: The primary logic hub for autocomplete. It is responsible for communicating with the C++ AutocompleteController via JNI, processing the results, and updating the PropertyModel that drives the suggestion list UI.
UrlBarCoordinator: Manages the UrlBar view, which is the EditText field 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.
UrlBar view (managed by UrlBarCoordinator).LocationBarCoordinator sets up a listener so that text changes in UrlBarCoordinator directly call AutocompleteCoordinator.onTextChanged().AutocompleteCoordinator.onTextChanged() forwards the call to AutocompleteMediator.onTextChanged().AutocompleteMediator takes the user's input and initiates a request to the shared C++ AutocompleteController through the JNI bridge.AutocompleteController sends them back to the AutocompleteMediator via its onSuggestionsReceived JNI callback.AutocompleteMediator receives the AutocompleteResult, processes it, builds a list of view models, and updates the main PropertyModel for the suggestion list.PropertyModel change is observed by the OmniboxSuggestionsDropdownAdapter, which then renders the final views in the suggestion dropdown list.