Helium includes a native implementation of DuckDuckGo’s !bang shortcuts, allowing you to search any website directly from the omnibox without visiting DuckDuckGo first.
What Are Bangs?
Bangs are shortcuts that let you search websites directly. Type !w to search Wikipedia, !gh to search GitHub, or !yt to search YouTube - all from your address bar.
Fast Searching Search hundreds of sites instantly without visiting them first
Native Integration Built into Chromium’s search engine system, not a web service
Privacy-Preserving Queries go directly to the target site, not through DuckDuckGo
Always Updated Bang list automatically syncs from Helium services
Quick Start
Type a bang keyword followed by your search query:
!w helium browser → Search Wikipedia for "helium browser"
!gh chromium patches → Search GitHub for "chromium patches"
!yt cat videos → Search YouTube for "cat videos"
!a mechanical keyboard → Search Amazon for "mechanical keyboard"
You can also put the bang at the end: helium browser !w - just press Enter to activate it!
How It Works
Helium implements bangs natively at the Chromium engine level:
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Omnibox Input │
└────────────────────┬────────────────────────────────────────┘
│
▼
┌──────────────────────┐
│ AutocompleteInput │ ← Parses !bang keywords
└──────────┬───────────┘
│
▼
┌────────────────────────┐
│ TemplateURLService │ ← Manages search engines
└────────┬───────────────┘
│
▼
┌────────────────────────────┐
│ BangManager │ ← Loads & caches bangs
└────────┬───────────────────┘
│
▼
┌────────────────────────────────┐
│ Helium Services API │ ← /bangs.json endpoint
└────────────────────────────────┘
Core Components
BangManager
Singleton class that fetches, caches, and manages the bang list. Location: components/search_engines/template_url_bang_manager.cc
AutocompleteInput
Extended to recognize !bang syntax at the beginning or end of queries. Location: components/omnibox/browser/autocomplete_input.cc
TemplateURLService
Converts bangs into TemplateURL objects that Chromium’s search system understands. Location: components/search_engines/template_url_service.cc
Implementation Details
Bang Data Structure
Each bang is represented by a simple struct:
struct Bang {
size_t id; // Unique identifier
std ::string name; // Human-readable name (e.g., "Wikipedia")
std ::string bang; // Bang trigger (e.g., "w")
std ::string template_url; // URL with {searchTerms} placeholder
};
Loading Bangs
Bangs are loaded when the browser starts:
void TemplateURLService :: LoadBangs () {
VLOG ( 2 ) << "LoadBangs() called" ;
bang_manager_ -> LoadBangs (url_loader_factory_, prefs_ . get (),
base :: BindOnce ( & TemplateURLService ::BangsLoadedCallback,
base :: Unretained ( this )));
}
If Helium Services are disabled or the network is unavailable, bangs use cached data from the previous fetch.
Network Request
The bang list is fetched from Helium services:
void BangManager :: DoStartFileFetch (
scoped_refptr < network :: SharedURLLoaderFactory > url_loader_factory ,
PrefService & prefs ) {
auto request = std :: make_unique < network :: ResourceRequest >();
request -> url = helium :: GetServicesBaseURL (prefs). Resolve (kBangsPrefix);
// Only fetch if user has enabled bang updates
request -> load_flags = helium :: ShouldFetchBangs (prefs)
? net ::LOAD_NORMAL
: net ::LOAD_ONLY_FROM_CACHE;
request -> credentials_mode = network :: mojom :: CredentialsMode ::kOmit;
request -> headers . SetHeader ( "Accept" , "application/json" );
}
Key privacy features:
No credentials sent (kOmit)
Respects user preference via ShouldFetchBangs()
Falls back to cache if network is disabled
30-second timeout with 3 retries
The bang list is served as JSON:
[
{
"s" : "Wikipedia" ,
"ts" : [ "w" , "wiki" ],
"u" : "https://en.wikipedia.org/wiki/Special:Search?search={searchTerms}" ,
"sc" : "other"
},
{
"s" : "GitHub" ,
"ts" : [ "gh" , "github" ],
"u" : "https://github.com/search?q={searchTerms}"
}
]
Fields:
s - Site name
ts - Trigger strings (array)
u - URL template with {searchTerms} placeholder
sc - Subcategory (optional, e.g., “ai”)
Parsing Logic
Bangs are parsed from JSON and converted to TemplateURLData:
TemplateURLData TemplateURLDataFromBang ( const Bangs :: Bang & bang ) {
TemplateURLData turl;
turl . SetShortName ( base :: UTF8ToUTF16 ( bang . name ));
turl . SetKeyword ( u"!" + base :: UTF8ToUTF16 ( bang . bang )); // Add ! prefix
turl . SetURL ( bang . template_url );
// Generate favicon URL from base domain
GURL favicon_url = GURL ( bang . template_url ). GetWithEmptyPath ();
favicon_url . path () = "/favicon.ico" ;
turl . favicon_url = std :: move (favicon_url);
turl . bang_id = 1 + bang . id ; // Mark as bang with ID
turl . safe_for_autoreplace = false ; // Don't auto-replace user engines
turl . GenerateSyncGUID ();
turl . is_active = TemplateURLData :: ActiveStatus ::kTrue;
return turl;
}
Bangs are marked with bang_id > 0 so they can be identified and managed separately from regular search engines.
Omnibox Integration
Keyword Detection
Helium extends AutocompleteInput to recognize bangs:
// Featured keyword mode now includes !
AutocompleteInput :: GetFeaturedKeywordMode ( std ::u16string_view text) {
- if (text == u"@" )
+ if (text == u"@" || text == u"!" )
return FeaturedKeywordMode ::kExact;
- if ( text . starts_with ( u'@' ))
+ if ( text . starts_with ( u'@' ) || text . starts_with ( u'!' ))
return FeaturedKeywordMode ::kPrefix;
return FeaturedKeywordMode ::kFalse;
}
This makes ! triggers work just like Chrome’s @ search shortcuts.
Trailing Bang Support
Uniquely, Helium supports bangs at the end of queries:
const size_t first_exclamation ( input . find_first_of ( '!' ));
if (first_exclamation != std :: u16string ::npos && first_exclamation != 0 ) {
bool might_be_bang = input_view . substr (first_exclamation - 1 )
. find_first_of ( base ::kWhitespaceUTF16) == 0 ;
if (might_be_bang) {
auto remaining_str = std :: u16string ( input_view . substr ( 0 , first_exclamation));
std ::u16string_view bang = input_view . substr (first_exclamation);
// Extract bang and reorder query
// ...
return std :: u16string (bang);
}
}
This allows natural typing: search query !site → searches “search query” on site.
Return Key Activation
Pressing Enter when a trailing bang is detected activates it:
void OmniboxViewViews :: HandleKeyEvent ( views :: Textfield * sender ,
const ui :: KeyEvent & event ) {
// ...
if ( controller ()-> IsPopupOpen () && ! control) {
// Accept trailing bang before opening selection
+ controller ()-> edit_model ()-> MaybeAcceptTrailingBang ();
controller ()-> edit_model ()-> OpenSelection (...);
}
}
void OmniboxEditModel :: MaybeAcceptTrailingBang () {
if ( ! HasTrailingBangKeyword ()) {
return ;
}
AcceptKeyword ( OmniboxEventProto ::RETURN_BANG);
// Find matching autocomplete entry
const AutocompleteResult & result = autocomplete_controller ()-> result ();
for ( size_t i = 0 ; i < result . size (); i ++ ) {
const AutocompleteMatch & match = result . match_at (i);
if ( input_ . text () == match . fill_into_edit ) {
SetPopupSelection ( OmniboxPopupSelection (i));
return ;
}
}
}
This creates a metric OmniboxEventProto::RETURN_BANG to track trailing bang usage.
Bang Categories
Bangs can be categorized for better organization:
enum BangCategory {
BANG_CATEGORY_OTHER = 0 ,
BANG_CATEGORY_AI ,
};
BangCategory GetCategoryFromJSONObject ( std :: string_view sc ) const {
if (sc == "ai" ) {
return BANG_CATEGORY_AI;
}
return BANG_CATEGORY_OTHER;
}
This allows UI filtering or different handling for specific bang types (like AI search engines).
Privacy Considerations
Unlike DuckDuckGo bangs, Helium’s implementation is direct :
DuckDuckGo: You → DDG → Target Site
Helium: You → Target Site
Your search query never touches Helium servers or DuckDuckGo.
Opt-Out Available
Bangs can be completely disabled:
Settings > Privacy > Helium Services > Allow downloading the !bangs list
When disabled:
No bang list fetched
Existing bangs remain functional (from cache)
No network requests made
Preference Integration
// Register preference
registry -> RegisterBooleanPref ( prefs ::kHeliumBangsEnabled, true );
// Check before fetching
bool ShouldFetchBangs ( const PrefService & prefs ) {
return ShouldAccessServices (prefs) &&
prefs . GetBoolean ( prefs ::kHeliumBangsEnabled);
}
Hidden from Lists
Bangs don’t clutter the search engine management UI:
bool TemplateURLService :: HiddenFromLists ( const TemplateURL * t_url ) const {
+ if ( t_url -> bang_id ()) {
+ return true ; // Hide bangs from chrome://settings/searchEngines
+ }
// ...
}
They’re available for use but don’t appear in the search engine picker.
Conflict Resolution
Bangs play nicely with custom search engines:
bool TemplateURL :: IsBetterThanConflictingEngine ( const TemplateURL * engine ) {
return std :: tuple (
// ... other criteria
+ // Favor bangs over other auto-generated engines
+ engine -> bang_id () > 0 ,
// Favor prepopulated engines
engine -> prepopulate_id () > 0 ,
// ...
);
}
Priority order:
User-created engines
Bangs
Prepopulated engines
Auto-generated engines
Example Bangs
Common bangs you might use:
Bang Site Example !wWikipedia !w rust programming!ghGitHub !gh chromium!soStack Overflow !so async javascript!ytYouTube !yt music!aAmazon !a wireless mouse!rReddit !r programming!mapsGoogle Maps !maps seattle!imdbIMDB !imdb inception
There are hundreds of bangs available. Try typing ! in the omnibox to see suggestions!
Advanced Usage
Multiple Triggers
Many sites have multiple bang aliases:
{
"s" : "Wikipedia" ,
"ts" : [ "w" , "wiki" , "wikipedia" ],
"u" : "https://en.wikipedia.org/wiki/Special:Search?search={searchTerms}"
}
You can use !w, !wiki, or !wikipedia - they all work.
Special Characters
Bang searches properly encode special characters:
!w C++ programming → Encodes + to %2B
!gh user/repo → Preserves / in query
Settings UI
Bangs have a dedicated toggle in Settings:
< settings-toggle-button id = "bangToggleButton"
pref = "{{prefs.helium.services.bangs}}"
label = "$i18n{heliumBangsToggle}"
sub-label = "$i18n{heliumBangsToggleDescription}" >
</ settings-toggle-button >
Text:
Label: “Allow downloading the !bangs list”
Description: “Helium will fetch a list of bangs that help you browse the Internet faster, such as !w or !gh. When disabled, bangs will not work.”
Troubleshooting
Check:
Settings > Privacy > Helium Services > Bangs is enabled
You’re connected to the internet (for initial fetch)
Type ! and wait for suggestions
Still not working?
Check chrome://settings/searchEngines - bangs should be hidden but active
Restart the browser to trigger a fresh bang load
Bang conflicts with custom search engine
Custom search engines take priority. If you’ve created a keyword !w, it will override the Wikipedia bang. Solution: Delete your custom engine or use a different keyword.
Trailing bangs not activating
Make sure you:
Have a space before the bang: query !bang ✓ not query!bang ✗
Press Enter (don’t click)
Have the bang at the very end of the query
<100ms Bang lookup is instant - no network latency
~5MB Complete bang list is about 5MB of JSON
In-Memory Bangs are cached in memory for immediate access
Future Enhancements
Possible future improvements:
Custom Bangs: Let users add their own bang shortcuts
Bang Discovery: Better UI for discovering available bangs
Bang History: Show most-used bangs first
Local Bang List: Ship a default list with the browser
Source Code Reference
Key files:
patches/helium/core/add-native-bangs.patch - Complete implementation
components/search_engines/template_url_bang_manager.h - Bang manager header
components/search_engines/template_url_bang_manager.cc - Bang manager implementation
components/omnibox/browser/autocomplete_input.cc - Omnibox parsing
chrome/app/settings_strings.grdp - Settings UI strings
The entire bang system is around 1000 lines of C++ code, demonstrating how tightly integrated it is with Chromium’s engine.