Features Β |Β Bang syntax Β |Β Snap syntax Β |Β Setup Β |Β Self-host Β |Β How it works Β |Β Comparison Β |Β Contributing
Turn your browser's address bar into a shortcut launcher. Type !g kittens to search Google, !w dogs for Wikipedia, !gh react for GitHub β over 14,000 shortcuts (called "bangs") that take you straight to the right site, instantly. No extra tabs, no round-trips, no waiting for a page to load. Or use snaps β type @w quantum to search your default engine restricted to Wikipedia, @gh api for GitHub-only results.
Other bang tools load a full page before redirecting β adding hundreds of milliseconds β or routes through an edge server adding network latency. Flashbang skips the page entirely β a Service Worker handles the redirect before your browser even starts rendering.
Visit flashbang.tech β if your browser supports OpenSearch, flashbang will appear in your search engine list automatically. Otherwise, add https://flashbang.tech?q=%s as a custom search engine in your browser. Optionally, set https://flashbang.tech/suggest?q=%s as the suggestion URL for address bar autocomplete. That's it.
Note for Microsoft Edge users: Edge needs a one-time setup tweak (the auto-discovered entry has to be deleted and re-added manually) β see Browser quirks. Without it, your default search engine gets overwritten after the first bang you use.
All three support bangs natively β but every query still round-trips through their servers before redirecting, adding significant network latency you can feel. Flashbang's Service Worker resolves the bang locally in sub 1ms and redirects before any network request leaves your machine. You also get bang-aware search suggestions in your address bar, custom bangs, feeling lucky, and it works in any browser β not just the one your engine ships with.
Core redirects never leave your machine once installed β the Service Worker handles them offline with no server involved. Search suggestions are completely optional and go through our server when enabled on the hosted version. One same-site cookie (
suggest) stores your configured suggestion provider, default bang, selected bang/snap prefixes, optional custom suggestion URL, custom bang trigger names, an explicitly pinned content language (nothing is written while you follow the browser), and compact top bang usage counts so the server can proxy and personalize suggestions. The frecency section contains only bang triggers and hit counts (e.g.g:50.yt:30), never query content. No accounts, no sessions, no personal data. There is no tracking or analytics β we don't know what you search or what bangs you use. Cloudflare Pages exposes basic request counts in its dashboard as a platform feature we did not opt into and cannot disable. It contains no query content or personally identifiable information.If you'd rather not trust our server at all, Flashbang is fully self-hostable. Deploy to Cloudflare Pages/Railway in minutes or
docker runit on any VPS β a single command gets you a fully private instance. See Setup for details.
- Built for speed β The redirect parser itself runs in well under 1ms, while browser-visible latency is dominated by browser-to-Service-Worker transport and scheduling. The
/benchpage measures that fetch round trip with deterministic settings, randomized paths, a no-op transport baseline, high-resolution isolated timing, and verification that every request was handled locally. It also runs paired top-level navigations against a direct same-origin target to estimate actual redirect overhead without destination network time. The Service Worker intercepts real searches before they hit the network, parses the bang, and responds with a 302 β no page load, framework, or round-trip to Flashbang's server. Run the benchmark yourself β results vary by browser and machine - Zero runtime deps β Ships without production npm dependencies; redirects run on plain browser APIs in the Service Worker
- Private β No analytics, no tracking. All data stays on your device for the core feature - redirects
- 14,000+ bangs β Merged from DuckDuckGo, Kagi, and custom sources. Updated daily via automated CI
- Custom bangs β Add your own bangs through the settings UI. They take priority over built-ins
- Configurable syntax β Choose distinct bang and snap prefixes from
!,@,$,:,;, and~. Defaults are!for bangs and@for snaps. The selected bang prefix also controls bare Feeling Lucky forms; leading\queryalways remains available - Local language negotiation β Sites with per-language editions normally negotiate with a redirect:
wikipedia.organswers a search by bouncing you toen.wikipedia.orgorde.wikipedia.orgbefore serving anything, which measured 3 hops and 782 ms to first byte. Flashbang performs that negotiation locally instead, sending a German reader straight tode.wikipedia.orgin 1 hop and 367 ms. The language follows your browser by default, can be pinned to one of 344 languages in settings, or switched off entirely so every site keeps its own default edition. Only host patterns with a reviewed list of editions the site actually hosts are eligible, so an unsupported language falls back rather than resolving to a hostname that does not exist β today that is 24 catalog entries across 8 Wikimedia projects, backed by a checked-in table of 826 editions - Search suggestions β The only bang tool with bang-aware autocomplete in your browser's native address bar. Type
!yand the browser itself suggests!yt(YouTube),!ya(Yandex),!yf(Yahoo Finance) β ranked by a combination of global popularity and your personal usage frequency. Regular queries can use Google, DuckDuckGo, Bing, Brave, Yahoo, Ecosia, Kagi, Qwant, Startpage, Yandex, or Baidu. Site-specific forwarding asks the completed bang's own autocomplete service by default, so!gh reactsuggests GitHub repositories,!wde berlinsuggests German Wikipedia pages, and package bangs can use AUR, crates.io, Maven Central, npm, NuGet, or Packagist. Endpoints for sites with per-language editions follow your content language, so!wsuggests from the same edition the redirect will land on. Amazon, Hacker News, Modrinth, Mozilla Add-ons, Reddit, YouTube, and 589 MediaWiki wikis are covered too. Self-hosted deployments can explicitly opt into custom providers. Everything is unified through a single/suggestendpoint that plugs into your browser's built-in suggestion UI. Firefox-based browsers also render bang descriptions, site names, and favicons inline in the dropdown viagoogle:suggestdetail. See Browser quirks for rendering and cookie differences across browsers - Frecency β The Service Worker tracks which bangs and snaps you use and how often, entirely in-memory on the redirect path. Your most-used triggers are promoted in autocomplete suggestions so they surface first. Compact snapshots are persisted to IndexedDB across Service Worker restarts. Suggestion personalization is available in Chromium-based browsers; it is not available in Firefox-based browsers β see Browser quirks
- Snaps and snap chains β Type
@trigger queryto restrict results to one site, or chain 2β8 sites with@gh,so,mdn query. Prefix (@w quantum) and suffix (quantum @w) positions both work. A bare single snap (@w) redirects to the trigger's homepage. Snaps reuse bang triggers; entries without a resolvable web domain, such as the internalsettingsshortcut, fall back to a normal search - Feeling Lucky β Prefix a query with
\, or add the selected bang prefix before or after it, to skip the results page and jump straight to the first result. The bang prefix defaults to!; selecting another prefix replaces those bare!forms, while\remains available. The default mode matches Google, DuckDuckGo, or Kagi when one of those is your default engine, and falls back to DuckDuckGo for other engines. You can also select a provider, use a custom URL, or disable it entirely - OpenSearch β Browsers auto-discover Flashbang as a search engine via
/opensearch.xml, including the suggestions endpoint. The XML is dynamically generated at request time using the current origin, so it works out of the box on any self-hosted domain orlocalhostβ no hardcoded URLs to change
Settings lets you select different prefixes for bangs and snaps from !, @, $, :, ;, and ~. Changing a prefix replaces that syntax rather than adding an alias. For example, with $ for bangs and ~ for snaps, use $gh react, react $gh, ~w quantum, and quantum ~w; !gh and @w become ordinary search text. The examples below use the default ! and @ prefixes.
Firefox-based browsers do not reliably show remote suggestions when address-bar input begins with :. A prefix snap such as :gh may have no suggestion dropdown even though a query-first snap such as test :gh does. Prefer @ or ~ for snaps if you want prefix autocomplete in Firefox, Zen, or LibreWolf.
Flashbang supports 4 formats. All bangs are case-insensitive.
| Format | Example | Result |
|---|---|---|
| Prefix bang | !g kittens |
Google search for "kittens" |
| Suffix bang | kittens g! |
Google search for "kittens" |
| Prefix, query first | kittens !g |
Google search for "kittens" |
| Suffix, bang first | g! kittens |
Google search for "kittens" |
If the query is just a bang with no search term (e.g. !g), Flashbang redirects to the service's homepage.
By default, snaps use @ instead of ! to perform a site-restricted search β your query goes to your default search engine with site:domain appended. Any bang trigger with a resolvable web domain works as a snap. All snaps are case-insensitive.
| Format | Example | Result |
|---|---|---|
| Prefix snap | @w quantum |
Default engine search for "quantum site:wikipedia.org" |
| Suffix snap | quantum @w |
Default engine search for "quantum site:wikipedia.org" |
| Bare snap | @gh |
Redirect to github.com homepage |
Chain 2β8 sites with one snap prefix and comma-separated shortcuts. For example, @gh,so,mdn,w service workers searches for service workers (site:github.com OR site:stackoverflow.com OR site:developer.mozilla.org OR site:wikipedia.org). The suffix form, service workers @gh,so,mdn,w, works too.
The chain preserves target order, removes duplicate domains and paths, and requires every shortcut to resolve to a valid snap target. Custom bangs and custom snap paths are supported. Autocomplete operates on the current segment, so @gh,so,m suggests completions such as @gh,so,mdn without repeating already-selected shortcuts.
If a query contains both a bang (!) and a snap (@), the bang takes precedence. Unknown snap triggers, and triggers without a resolvable web domain, fall back to a normal default search.
Skip the search results page and go directly to the first result. The table uses the default bang prefix; if you change it, the leading/trailing bare marker changes with it. Leading backslash remains fixed.
| Format | Example | Result |
|---|---|---|
| Backslash | \kittens |
First result for "kittens" |
Trailing ! |
kittens ! |
First result for "kittens" |
Leading ! |
! kittens |
First result for "kittens" |
The redirect destination depends on your lucky provider (configurable in settings):
- Default (match bang) β Uses your default search engine's native lucky feature if available (Google
btnI, DuckDuckGo\), otherwise falls back to DuckDuckGo's\redirect - Google / DuckDuckGo / Kagi β Always use that engine's lucky redirect
- Custom β Provide your own URL template with
{}as the query placeholder - Disabled β Lucky syntax is treated as a normal search query
A public instance is available at flashbang.tech. Just visit it, then add it as a custom search engine in your browser:
- Search URL:
https://flashbang.tech?q=%s - Suggestion URL:
https://flashbang.tech/suggest?q=%s(Optional)
Nothing to build or deploy.
For maximum query privacy, use https://flashbang.tech/#q=%s. Everything after # is a URL fragment, which browsers do not include in the HTTP request to Flashbang. Once installed, Flashbang's Service Worker reads and resolves the fragment locally, then loads a minimal synthetic page to navigate without carrying the private fragment to the destination. This extra page is slower and may briefly flash during navigation. On a first visit, the page fallback resolves the query in the browser instead. The standard https://flashbang.tech?q=%s URL is significantly faster and is recommended unless keeping the very first query request (which happens one time at SW install) out of to Flashbang's hosted server is more important than redirect speed.
Note: Search suggestions and OpenSearch auto-discovery require a server endpoint since browsers don't route these requests through Service Workers β both are completely optional. Redirects always work offline once installed with no server needed. If you use the hosted version, these requests go through our Cloudflare Pages Functions. No queries are logged or stored β self-host if you'd rather keep them local too.
The suggestion endpoint accepts cookie-independent query parameters for the suggestion provider and shortcut syntax:
spselects the suggestion providerbpselects the bang prefixnpselects the snap prefixlangselects the content language used by site-specific endpoints that have per-language editions; it accepts a language tag such asdeorpt-br, ornoneto leave every site on its own default edition. The cookie wins when both are present, and an unusable value is ignoredsite_specific_forwardcontrols whether non-bang terms are sent to a completed built-in bang's own autocomplete endpoint when one is available; it defaults to1, andsite_specific_forward=0disables it
bp and np must be supplied together, must differ, and each accepts !, @, $, :, ;, or ~. Invalid pairs safely fall back to cookie or default settings. Provider values are:
google, ddg, bing, brave, yahoo, ecosia, kagi, qwant, startpage, yandex, baidu, none
Example Firefox suggestion URL with provider and syntax overrides:
https://flashbang.tech/suggest?q=%s&sp=ddg&bp=%24&np=~&site_specific_forward=1
Site-specific suggestions compose with the provider and syntax parameters. A known site endpoint takes priority; bangs without one fall back to sp (or the cookie-backed provider):
https://flashbang.tech/suggest?q=%s&sp=ddg&site_specific_forward=1
Site-specific forwarding is enabled by default and changes where suggestion text is sent. For example, text after !gh reaches GitHub's API and text after !w reaches Wikipedia. Add site_specific_forward=0 to the suggestion URL to keep all suggestion requests on the selected sp provider instead. Redirects remain local and are unaffected.
Why this exists: in Chromium-based browsers, cookies are sent with suggest requests and settings configured in the UI are picked up automatically, so these overrides are rarely needed. Firefox-based browsers withhold cookies; the settings UI therefore generates a copyable URL containing sp and an explicit site_specific_forward=1, adds bp plus np when the selected syntax differs from the default !/@ pair, and adds lang when a content language is pinned. See Browser quirks for details.
These apply equally to the hosted version and any self-hosted instance β worth a quick read before adding flashbang as your default.
-
Microsoft Edge β bang destinations hijack the default search. After you use a bang like
!gm, Edge auto-registers the destination (Google Maps, GitHub, etc.) as a separate search engine with the same shortcut as flashbang (the host). When two engines share a shortcut, Edge picks the most-recently-used one for default searches β so your plain queries start going to Google Maps. Not observed in Chrome or Firefox.Fix β in
edge://settings/searchEngines:- Delete the auto-discovered flashbang entry.
- Click Add and re-add it manually:
- Search engine:
flashbang - Shortcut: something short and unique like
f - URL with %s:
https://flashbang.tech?q=%s(or your self-hosted URL)
- Search engine:
- Set it as your default.
Important: editing the auto-discovered entry's Shortcut doesn't persist β Edge re-derives it from
/opensearch.xmlon restart and reverts to the host. The delete-and-readd step is what makes the fix stick, because a manually-added entry is independent of the discovery XML. -
Firefox / Zen / LibreWolf β no frecency, no custom bangs in suggestions. Firefox-based browsers intentionally withhold cookies from OpenSearch suggest requests as a privacy measure. Flashbang's custom bang trigger names and frecency data are carried by the unified
suggestcookie, so those features remain unavailable on these requests. Provider, bang/snap prefix, and content-language settings can be embedded directly withsp,bp,np, andlang; the settings UI generates the complete URL β see Suggestion URL parameters. -
Tor Browser and Safari Lockdown Mode β slower fallback. These privacy modes can disable Service Workers, which Flashbang normally uses for local redirects. Flashbang falls back to loading the same bang data and resolving the query in the page, so redirects still work but require a network page load and do not have the normal sub-millisecond or offline guarantees. The query is still resolved in your browser, not by Flashbang's server.
-
Chromium β plain-text suggestions only. Chrome, Edge, Arc, and other Chromium-based browsers don't render rich suggestion details (descriptions, favicons, entity images) for search-type suggestions from custom search engines; they're shown as plain text. Firefox-based browsers render the rich data passed through
google:suggestdetail. This is a Chromium limitation, not flashbang's.
Cloudflare Pages (recommended) β supports both redirects and suggestions out of the box:
- Deploy the repo to Cloudflare Pages with build command
bun run codegen --from-merged && bun run buildand output directorydist - The Pages Functions automatically handle
/suggest(search suggestions) and/opensearch.xml(search engine discovery with correct origin) on the edge - Visit the site β your browser will auto-discover it via OpenSearch
- Or manually add a custom search engine:
- Search URL:
https://your-domain?q=%s - Suggestion URL:
https://your-domain/suggest?q=%s
- Search URL:
Railway β detects the Dockerfile and deploys automatically:
- Connect your repo on Railway
- Railway builds the Docker image and sets the
PORTenvironment variable automatically - Connect domain (you can auto-generate it in settings)
- Add a custom search engine:
- Search URL:
https://your-app.up.railway.app?q=%s - Suggestion URL:
https://your-app.up.railway.app/suggest?q=%s
- Search URL:
For deployments behind a reverse proxy or TLS terminator, set PUBLIC_ORIGIN to the browser-visible URL (for example, https://search.example.com). OpenSearch uses this value instead of the request URL. It must be an absolute http:// or https:// URL without credentials; any trailing slash, path, query, or fragment is discarded. If it is unset, Flashbang uses the request origin, preserving the default Cloudflare Pages behavior. If it is set but invalid, /opensearch.xml returns 500 rather than publishing incorrect or unsafe URLs.
Custom suggestion URLs are disabled by default because they allow the server to proxy requests to arbitrary destinations. A trusted self-hosted deployment can opt into the previous behavior by setting ALLOW_UNSAFE_CUSTOM_SUGGEST_URLS=true during both the build and at runtime. The setting is compiled into the UI, so changing it requires rebuilding and redeploying. Do not enable this on a public instance.
Other static hosts (Netlify, Vercel, etc.) β redirects work, but suggestions and dynamic OpenSearch require adding serverless functions for /suggest and /opensearch.xml. See functions/ for the implementations β they reuse shared modules from src/ and can be adapted to any serverless platform.
Run your own instance on any VPS. No dependencies to install β just Docker:
docker build -t flashbang .
docker run -p 3000:3000 flashbangTo include custom suggestion URLs in a private Docker deployment, build with docker build --build-arg ALLOW_UNSAFE_CUSTOM_SUGGEST_URLS=true -t flashbang .. The image uses the same value as its runtime default.
The image uses a multi-stage build β fetches bang sources, builds assets, and produces a minimal runtime image. Static assets are pre-compressed with Brotli at build time and served automatically, falling back to uncompressed for clients that don't support it. The port is configurable via the PORT environment variable (-e PORT=8080); PUBLIC_ORIGIN configures the browser-visible origin when running behind a reverse proxy (for example, -e PUBLIC_ORIGIN=https://search.example.com).
For a remote deployment, terminate TLS with a reverse proxy or hosting provider and expose Flashbang over HTTPS. Browsers only enable Service Workers in secure contexts (HTTPS or localhost), and Flashbang's suggestion settings cookie is Secure. Plain HTTP on a VPS will not provide worker redirects or persistent suggestion settings. Set the HTTPS origin as your browser's custom search engine:
- Search URL:
https://search.example.com?q=%s - Suggestion URL:
https://search.example.com/suggest?q=%s
Requires Bun. Service Workers require HTTPS except on localhost; a local HTTP server works because browsers treat localhost as a secure context:
bun run codegen && bun run build && bun run startbun run codegen fetches the latest bang definitions from DuckDuckGo and Kagi and generates the JavaScript bang maps. bun run build bundles, minifies, and pre-compresses all static assets with Brotli into dist/. bun run start serves the production build locally. Visit the local URL once β the Service Worker installs and redirects work offline after that. Set it as your browser's custom search engine:
If generated bang artifacts are missing, bun run build and bun run profile automatically run bun run codegen --from-merged before continuing.
- Search URL:
http://localhost:3000?q=%s - Suggestion URL:
http://localhost:3000/suggest?q=%s(Optional)
To pick up new bangs, pull the latest changes and re-run bun run codegen. If you host it, the daily GitHub Actions CI does this automatically.
The settings page has a copy button that gives you the exact search URL template.
Open the settings modal from the gear icon on the home page, or type !settings in the address bar to jump there directly. Type ! on its own to quickly access the home page.
- Shortcut syntax β Choose distinct bang and snap prefixes from
!,@,$,:,;, and~. Defaults are!and@ - Default bang β The built-in bang used when no selected bang prefix is in the query. Defaults to
g(Google). Change it toddg,b, or any other built-in trigger - Content language β The language used by sites that ship per-language editions, such as Wikipedia. Follow browser (the default), one of 344 languages, or Off to leave every site on its own default edition. The choice applies to redirects and to site-specific suggestions
- Feeling Lucky β Choose how lucky redirects resolve: Default (match Google, DuckDuckGo, or Kagi when selected as the default bang, otherwise fall back to DuckDuckGo), Google, DuckDuckGo, Kagi, Custom (your own URL template with
{}as query placeholder), or Disabled - Search suggestions β Choose the source for address bar autocomplete: Default (match a supported default bang, otherwise return no regular-query suggestions), Google, DuckDuckGo, Bing, Brave, Yahoo, Ecosia, Kagi, Qwant, Startpage, Yandex, Baidu, Custom (self-hosted deployments with
ALLOW_UNSAFE_CUSTOM_SUGGEST_URLS=trueonly), or None - Custom bangs β Add bangs with a trigger, name, and URL template (use
{}as the query placeholder). Advanced bangs can match the query with a regular expression, substitute$1,$2, etc., and set a separate domain or path for@snapsearches. Custom bangs override built-in ones - Search bangs β Real-time search across all 14,000+ bangs by trigger, name, or domain
- Import/Export β Export your settings and custom bangs as JSON. Import to restore or sync across devices
All settings are stored in IndexedDB locally on your device.
For example, a capture bang with URL https://translate.example/$1/$2 and regex (\w+)\s+(.*) turns !trurl ja https://example.com into a URL containing ja and the encoded source URL. Capture values can use percent, plus-space, or raw encoding.
An optional snap target such as docs.example.com/api makes @mybang query search only that domain and path, while !mybang query continues to use the bang's normal URL.
The redirect path is deliberately separate from the website UI and from the suggestion server:
flowchart TB
address[Address-bar ?q= navigation] --> controlled{Controlled by the Service Worker?}
controlled -->|Yes| worker[Service Worker fetch handler]
worker --> fast[Live runtime or persisted hot boot]
fast --> resolver[Canonical raw parser and redirect resolver]
resolver -->|Hot-boot miss| storage[Packed catalog from cache or network and IndexedDB settings]
storage --> resolver
resolver --> response[302 destination redirect]
response -. after response .-> sideEffects[waitUntil: frecency and deferred persistence]
controlled -->|No| page[Minimal page fallback]
page --> cold[Cold resolver module and generated hot table]
page -. prefetch for a non-hot bang .-> shard[Deterministic catalog shard]
cold -->|Generated hot bang| clientRedirect[location.replace destination]
cold -->|Other fresh-profile bang| shard
shard --> clientRedirect
cold -->|Existing profile or unsupported cold path| fullFallback[Full page fallback: catalog and IndexedDB]
fullFallback --> clientRedirect
page -. in parallel .-> registration[Register Service Worker]
fullFallback -. hand off catalog and settings .-> registration
registration -. after activation .-> later[Control later Flashbang navigations]
Installed profiles stay on the upper path and redirect without rendering Flashbang. A first or otherwise uncontrolled navigation uses the minimal page path while Service Worker registration proceeds independently; it does not wait for installation before redirecting. The private #q= path differs slightly and is described below.
When you type !gh react (or the equivalent with your selected bang prefix), the browser navigates to Flashbang's search URL. The installed Service Worker intercepts that navigation, reads q directly from the raw request URL, resolves the destination, and returns Response.redirect(..., 302). The browser follows that response without loading or rendering the Flashbang page.
The parser works on the still-encoded query instead of first passing the whole value through URLSearchParams, decoding it, and encoding it again. It recognizes literal and percent-encoded markers and spaces, computes the trigger's FNV-1a hash while extracting it, and preserves the raw search term where the destination template allows it. Custom bangs are checked first; built-ins are checked only if there is no custom override. The same parser handles all prefix/suffix bang forms, lucky syntax, snaps, and snap chains. Unknown syntax safely becomes a search through the configured default engine.
Destinations for sites with per-language editions carry a {lang} marker in their host. The resolver fills it from your content language using a checked-in table of the editions each site actually hosts, caches the resolved host per language, and drops those caches when the setting changes. A bare snap follows the same substitution, so @w opens your own edition's homepage, while a site-restricted snap deliberately filters on the language-independent domain (site:wikipedia.org) so results are not pinned to one edition. User-created bangs cannot contain the marker β only the generated catalog and the curated suggestion endpoints may.
The 14,000+ source records are not shipped to the redirect worker as a large JSON object. scripts/codegen.ts merges and validates the DuckDuckGo, Kagi, and project-specific sources, applies a hand-maintained overlay that rewrites destinations to their canonical form, and then produces purpose-built artifacts for different jobs:
bangs.bincontains the regular trigger-to-URL redirect index- generated sparse data handles advanced capture/regex bangs
- a packed radix trie powers prefix autocomplete and snap-chain completion
bangs-meta.bincontains the names and domains needed by the settings UI- a tiny generated hot-bang table covers common triggers during worker startup
For the redirect index, codegen splits every URL template around its query placeholder, deduplicates the resulting prefixes and suffixes, and stores compact IDs plus byte lengths in typed arrays. It also deterministically builds a CHD-style minimal perfect hash from each trigger's FNV-1a hash and writes records directly in hash-slot order. A lookup therefore selects one slot with no probe loop, verifies that the stored trigger really matches, and only then decodes and caches that entry's URL pieces. Most of the catalog remains byte-backed for the worker's lifetime.
Service Workers can be stopped whenever the browser considers them idle, so in-memory state cannot be assumed to survive. The full binary index is cached in Cache Storage, while settings, custom bangs, and compact frecency snapshots live in IndexedDB.
Flashbang also keeps a compact hot-boot record in the Service Worker's persisted navigation-preload configuration while leaving navigation preload itself disabled. That record can contain redirect settings and the user's top frecent bang URLs. Together with the generated hot-bang table, it lets a newly started worker answer common navigations before IndexedDB and the full binary catalog have finished loading. A miss falls through to the full index, preferring Cache Storage and caching a network response when necessary, so this optimization never changes redirect semantics. Browsers without the required API simply use the normal cache and IndexedDB path.
Destination resolution is synchronous once the required lookup state is available. After the 302 has been created, FetchEvent.waitUntil() schedules usage counting, coalesced IndexedDB persistence, hot-boot refreshes, and suggestion-cookie updates. Frecency can therefore personalize later autocomplete results without putting an IndexedDB write in front of the current redirect.
Browsers send OpenSearch suggestion requests to /suggest; they do not route them through the Service Worker. Bang completion is still local to the Flashbang deployment: the endpoint walks a generated radix trie whose nodes carry the maximum relevance of their descendants, then performs a bounded top-k search that prunes branches unable to beat the current results. Global relevance, optional frecency boosts, custom triggers, and already-selected snap-chain targets are combined during that walk. Regular non-bang queries are proxied to the configured suggestion provider and are never added to the bang catalog or frecency data.
The privacy-first #q=%s URL takes a related but intentionally slower path. The query remains in the URL fragment, which is not sent to the server. The Service Worker resolves it locally and returns a minimal synthetic page that calls location.replace() with a safely serialized destination; this prevents the private source fragment from being carried into the destination URL.
See DEVELOPMENT.md for build pipeline and project structure details.
π₯, π₯, and π₯ mark first, second, and third place. Ties share a medal; subjective or effectively universal rows are not ranked.
| flashbang | unduck | unduckified | ReBang | bangs.fast | cf-unduck | |
|---|---|---|---|---|---|---|
| Redirect method | π₯ Service Worker intercept + persisted hot boot + client fallback | π₯ window.location.replace |
π₯ Service Worker intercept + client fallback | π₯ Cloudflare Worker + client fallback | π₯ window.location.replace |
π₯ Cloudflare Worker + client fallback |
| When redirect happens | π₯ Before render when controlled; after a minimal cold page otherwise | π₯ After page loads | π₯ Before render when controlled; after a minimal cold page otherwise | π₯ At edge or after page loads | π₯ After page loads | π₯ At edge or after page loads |
| Sources / measured triggersβ | π₯ DDG + Kagi + custom β 14,627 | DDG + project entries β 13,570 | Kagi + custom β 13,593 | π₯ DDG + Kagi β 14,432 | π₯ Selectable DDG or Kagi β 13,541β14,074 | DDG + Kagi β 13,598 |
| Analytics | π₯ Noneβ | Plausible | Cloudflare beacon.min.js on hosted deploymentβ‘ |
Plausible + Vercel Analytics + Speed Insights | π₯ None (static GitHub Pages) | Google Analytics 4 via Cloudflare ZarazΒ§ |
| Server required | π₯ No for redirects; yes for optional suggestions/OpenSearch | π₯ No | π₯ No for redirects; yes for optional suggestions | Yes (Cloudflare Worker) | π₯ No | Yes (Cloudflare Worker) |
Snaps (site: search) |
π₯ Yes (@trigger) |
No | No | No | No | No |
| Snap chains | π₯ Yes (2β8 sites) | No | No | No | No | No |
| Feeling Lucky | π₯ Yes (configurable per-engine) | No | No | No | No | No |
| Local language negotiation | π₯ Yes (resolves per-language editions locally) | No (separate per-language bangs only) | No (separate per-language bangs only) | No (separate per-language bangs only) | No (separate per-language bangs only) | No (separate per-language bangs only) |
| Configurable shortcut syntax | π₯ Yes (separate bang/snap prefixes) | No (fixed !) |
No (fixed !) |
No (fixed !) |
No (fixed !) |
No (fixed !) |
| Private fragment search | π₯ Yes (#q=%s, Service Worker) |
No | No | No | π₯ Yes (#q=%s, page-based) |
No |
| Address-bar suggestions | π₯ Built in (bang-aware + regular queries + opt-in site forwarding) | No | π₯ Built-in bang completion + opt-in provider/site forwarding | No | No | π₯ Built-in DuckDuckGo suggestions |
| Frecency-ranked suggestions | π₯ Yes (local usage; Chromium) | No | No | No | No | No |
| OpenSearch | π₯ Yes (dynamic, self-host friendly) | No | π₯ Yes (static) | π₯ Yes (static) | π₯ Yes (static) | π₯ Yes (static) |
| Default engine setting | Yes | localStorage only; no UI |
Yes | Yes | Yes | Yes |
| Custom bangs | π₯ Yes (IndexedDB + persisted hot boot) | No | π₯ Yes (localStorage + SW Cache Storage) |
π₯ Yes (localStorage) |
π₯ Yes (IndexedDB) | π₯ Yes (localStorage + cookie) |
| Advanced custom bangs | π₯ Regex captures, encoding modes, custom snap paths | No | No | No | No | No |
| Bang catalog search | Trigger, name, or domain | No | No | Yes | Yes | Yes |
| Settings import/export | π₯ Yes | No | π₯ Yes | No | π₯ Shareable settings link | Shareable custom-bang link |
| Automatic bang updates | Daily | No | Daily | Monthly | Daily | Daily pull request |
| Build tool | Bun | Vite | Bun + Vite | Vite | Bun + Vite | Bun + Vite |
| Bang data for redirects | π₯ ~545 KiB packed triggerβURL lookup | 2.7 MB (full metadata) | π₯ ~688 KiB packed triggerβURL lookup | π₯ ~208 KB inline + 1.23 MB lazy-loaded | ~1,744β1,977 KiB JSON dataset | ~1,560 KiB generated trigger map |
| Core client redirect assetsΒΆ | π₯ First redirect: ~14.0 KiB hot / ~21.2 KiB other; complete offline: ~236 KiB transfer / ~656 KiB decoded | π₯ ~466 KiB transfer / ~1,980 KiB decoded | π₯ ~191 KiB transfer / ~694 KiB decoded; first redirect on the edge path | Edge path | ~525 KiB transfer / ~2,295 KiB decoded | Edge path |
| Parsed on | π₯ SW thread once per worker lifetime; main thread on cold fallback | Main thread (every page load) | π₯ SW thread once per worker lifetime; main thread on cold fallback | π₯ Edge worker or main-thread fallback | π₯ Main thread with cached index | π₯ Edge worker or main-thread fallback |
| License | AGPL-3.0 | MIT | MIT | MIT | MIT | MIT |
| GitHub stars |
β Flashbang does not include analytics scripts or tracking. Cloudflare Pages exposes basic request counts in its dashboard as a platform feature; that aggregate platform metric is not Cloudflare Web Analytics.
β‘ Unduckified's source contains no analytics code, but its hosted custom domain requested Cloudflare's beacon.min.js and /cdn-cgi/rum on August 3, 2026. Issue #13 documents the beacon remaining in browser network requests after the author disabled Web Analytics. This is deployment-level behavior rather than code in the Unduckified repository.
Β§ cf-unduck's live deployment injects Google Analytics 4 through Cloudflare Zaraz (G-EEX06M0N08). Zaraz is enabled in Cloudflare rather than application source, so the analytics integration does not appear in the public repository.
Measurement definitions and source revisions
β The medals in this row compare effective unique built-in redirect triggers after checked-in aliases and project-specific entries are expanded. Fixed catalogs use their complete runtime total. bangs.fast exposes mutually exclusive presets, so its range is 13,541 for the default DDG preset, 13,589 for Kagi Community, and 14,074 for Kagi Community + Internal; its medal uses that largest supported preset. Flashbang ranks first overall at 14,627, followed by ReBang at 14,432 and bangs.fast at up to 14,074. Flashbang covers 195 more triggers (1.4%) than runner-up ReBang and 1,034 more (7.6%) than Unduckified. The remaining totals are cf-unduck 13,598, Unduckified 13,593, and unduck 13,570.
Flashbang's count is the current data/bangs.json in this repository on August 18, 2026. The other counts were measured from source on August 3, 2026 at unduck c1b821d, Unduckified 58b33a7, ReBang 45d3a03, bangs.fast 213d94e, and cf-unduck 74ffeb8. Feature behavior was additionally refreshed against Unduckified 3907ca6. These projects are actively developed and may have changed since.
ΒΆ This row ranks the network bytes required before the first redirect first, then the complete decoded redirect runtime; compressed bytes used only for background/offline warming are secondary. Flashbang reports both states because its sharded design does not put the complete offline catalog in front of the first redirect: a generated hot bang transfers the cold resolver in two requests (~14.0 KiB / ~34.5 KiB decoded), while another built-in adds one routed shard for ~21.2 KiB / ~49.9 KiB decoded across three requests. Its complete installed worker and warm offline catalog are ~235.9 KiB transferred across 20 requests (~656.4 KiB decoded). βTransferβ uses each deployment's supported HTTP content encoding; βdecodedβ is the body size after HTTP decompression. Other Service Worker totals include the installed worker and complete packed catalog but exclude their first-uncontrolled-navigation fallback. Page-based totals include the JavaScript and fetched catalog used by their normal client redirect. HTML, CSS, fonts, analytics, settings, suggestions, and unrelated UI assets are excluded. Unduckified's August 21, 2026 release moved the first search of a new profile onto a Cloudflare Pages Function, so that one navigation costs the device ~1.28 KiB in a single request (an 837-byte bootstrap document that registers the Service Worker and forwards via location.replace(), then a bare 302 for every later uncontrolled search). That number is reported here but not ranked, for the same reason ReBang's and cf-unduck's edge redirects are not: it is not a client asset. The catalog did not shrink, it moved β src/bangs/packbang.ts writes the packed catalog verbatim into src/bangs/catalog-embed.ts as a base64 string (~688 KiB of catalog, ~917 KiB of module text), functions/index.ts imports it and decodes it once per isolate, and the code's own comment puts that at β~700 KiBβ and βa few millisecondsβ. Ranking a server-resident catalog first on a row that measures client bytes would reward relocating the bytes rather than removing them, so this row ranks the client runtime each project still ships, where Unduckified remains second: its complete Brotli archive is smaller transferred, but its first client redirect requires the complete catalog and its decoded runtime is larger. The latency this buys Unduckified is real and is reported where it is measured β the New profile lifecycle below, the one category Flashbang loses. Flashbang's August 22, 2026 edge-cache and Early Hints change closed most of that gap by removing round trips rather than bytes.
Flashbang's payload figures were measured live against the deployment on August 22, 2026, which does not yet carry the local language negotiation in this repository. Unduckified was measured live on August 22, 2026 for its critical path and on August 3, 2026 for the remaining rows; the remaining deployments were measured on July 23, 2026. Successful ReBang and cf-unduck edge redirects, and Unduckified's first-search edge redirect, execute remotely and have no client runtime body; βEdge pathβ does not mean zero network cost, excludes response headers and server code β including any bang catalog resident in the function bundle β and does not include the larger client fallback paths behind it. βNoβ means no built-in implementation was found; manual browser configuration is not counted.
The August 22, 2026 campaign ran 60 randomized pairs in every category against the current public deployments with the published harness (sw-restart.mjs, all 11 categories in one run), after Flashbang moved its search document behind Cloudflare's edge cache and began advertising the cold resolver in an HTTP 103 Early Hints response. A category is decided when the bootstrapped 95% confidence interval on the paired mean difference excludes zero, which is stricter than counting pair majorities. Flashbang took eight categories, two tie, and Unduckified took one.
| Lifecycle | Score | Flashbang median range | Unduckified median range |
|---|---|---|---|
| Live worker | 5 wins, 1 tie | 0.39β0.40 ms | 0.41β0.50 ms |
| Worker restart | 3 wins | 3.14β3.18 ms | 3.68β3.95 ms |
| New profile | 1 tie, 1 loss | 61.68β65.52 ms | 63.53β64.17 ms |
The live-worker margins remain small β 0.01β0.10 ms β and one of those six categories has a confidence interval spanning zero. The durable separation is still the restart path: Flashbang was 0.55β0.77 ms lower after a stopped worker restarted, taking 60 of 60 pairs in all three shapes at p < 0.0001.
The new-profile row is the one this campaign did not settle. On the hot !gh query Flashbang holds the lower median β 61.68 ms against 64.17 ms β but the paired mean difference runs 5.34 ms the other way with a 95% CI of -18.18β3.60 (p = 0.4505), so the category is a tie: median and mean disagree because both tails are heavy, and these samples cannot separate the two. The full-catalog alias stays Unduckified's and its paired margin widened from 3.25 ms in the previous campaign to 12.45 ms (95% CI 4.09β24.29, p = 0.0009), because that query still costs Flashbang a routed shard the edge redirect never fetches.
That row is also the least stable thing in this table, and it is worth being explicit about how unstable. Two further 60-round cold-only campaigns run the same day, on the same timing definition, put the hot !gh query 8.03 ms and 5.23 ms in Flashbang's favour (95% CI 0.58β18.81 and 0.02β10.41) and scored the alias a tie both times β the opposite verdict on both queries. On the live-worker rows the paired interval is narrower than the effect it brackets; here it is roughly four times wider, and a category that flips direction between campaigns an hour apart is measuring the network as much as the software. The two shipped rows are the ones the published harness produced in a single run; neither should be read as a settled result.
Two deployment changes shape Flashbang's side of that path, and neither moves a byte off it. The search document is served from Cloudflare's edge (cache-control: public, max-age=300), and because it carries nothing query-specific β Flashbang resolves the bang on the device β the cache key ignores the query string, so an arbitrary never-before-seen search still hits a warm edge object rather than the origin: /?q=!gh+test and /?q=!zz+neverseenβ¦ return the same cached object, cf-cache-status: HIT at the same age. The 103 then names cold-fallback.js before the document body arrives, so the resolver request starts during document delivery instead of after it; the byte harness observed that request beginning 45β54 ms into the navigation. Unduckified cannot cache the equivalent response, and does not try: its edge function returns the resolved destination itself, so the response is private, no-store by necessity. The architecture behind these states, and the privacy tradeoff behind that row, is explained in Why Flashbang is faster.
Full 11-category results and benchmark methodology
| Chromium 151, randomized pairs | Flashbang | Unduckified | Paired result |
|---|---|---|---|
Live worker, !gh test |
0.39 ms | 0.42 ms | Flashbang won 49/60; mean advantage 0.03 ms (95% CI 0.02β0.04, p < 0.0001) |
Live worker, full-catalog alias !github test |
0.40 ms | 0.41 ms | Flashbang won 45/60; mean advantage 0.02 ms (95% CI 0.01β0.03, p = 0.0025) |
Live worker, trailing test !gh |
0.39 ms | 0.41 ms | Flashbang won 44/60; mean advantage 0.02 ms (95% CI 0.02β0.03, p < 0.0001) |
Live worker, suffix test gh! |
0.40 ms | 0.41 ms | Tie β 37/60 pairs but mean difference 0.01 ms (95% CI -0.00β0.01, p = 0.2764) |
Live worker, empty query !gh |
0.39 ms | 0.41 ms | Flashbang won 45/60; mean advantage 0.02 ms (95% CI 0.01β0.03, p < 0.0001) |
| Live worker, 256-byte query | 0.39 ms | 0.50 ms | Flashbang won 60/60; mean advantage 0.10 ms (95% CI 0.09β0.11, p < 0.0001) |
Worker restart, !gh test |
3.14 ms | 3.69 ms | Flashbang won 60/60; mean advantage 0.58 ms (95% CI 0.53β0.63, p < 0.0001) |
| Worker restart, full-catalog alias | 3.15 ms | 3.68 ms | Flashbang won 60/60; mean advantage 0.55 ms (95% CI 0.50β0.60, p < 0.0001) |
| Worker restart, 256-byte query | 3.18 ms | 3.95 ms | Flashbang won 60/60; mean advantage 0.77 ms (95% CI 0.72β0.82, p < 0.0001) |
New profile, !gh test |
61.68 ms | 64.17 ms | Tie β Flashbang holds the lower median, but the paired mean runs 5.34 ms the other way (95% CI -18.18β3.60, p = 0.4505, 28/60 pairs) |
| New profile, full-catalog alias | 65.52 ms | 63.53 ms | Unduckified won 41/60; mean advantage 12.45 ms (95% CI 4.09β24.29, p = 0.0009) |
A category is awarded when the bootstrapped 95% confidence interval on the paired mean difference excludes zero. Pair counts and medians are reported alongside because they can disagree with that verdict, in both directions. On a live worker test gh! goes to Flashbang 37/60 by pair count, but its mean difference is 0.01 ms with an interval touching zero. On a new profile !gh test gives Flashbang the lower median while the paired mean and the pair count both go the other way, over an interval spanning -18.18β3.60 ms; a bolded median in that row is the campaign's point estimate, not a claimed win. Both are recorded as ties.
The comparison uses Unduckified's timing definition: CDP Network.requestWillBeSent wall time from navigation to the tool URL until the first GitHub request. It ran in Chromium 151.0.7922.34 on an Apple M4 Max; discarded three warm-up pairs; randomized tool order; measured live workers, explicitly stopped workers, and isolated browser contexts; bootstrapped 95% confidence intervals; and used a paired sign-flip permutation test. Absolute medians drift between sittings β repeated campaigns on this machine moved Flashbang's live-worker median between 0.39 ms and 0.65 ms with no code change β so only within-campaign paired comparisons are reported here, and figures from different campaigns are not compared against each other.
Both harnesses are standalone files in this gist: sw-restart.mjs produces the 11 latency categories above, cold-bytes.mjs the byte figures below. Neither needs a checkout or a build β npm install playwright, then run them β and both deployment URLs are environment variables, so pointing them at another build takes no code change. The gist's own JSON is from an earlier August 19, 2026 run against a pre-edge-redirect Unduckified; the figures on this page come from re-running the same two files against both current deployments.
The payload audit separates critical-path behavior from total offline footprint, and Unduckified moves fewer bytes over the wire on that path: the caching change bought Flashbang latency, not bytes. Over 10 rounds per scenario on August 22, 2026, Unduckified transferred a median 1.28 KiB in a single request before the destination request started, identically for the hot bang !gh test and the full-catalog alias !github test, because neither is resolved on the client any more. That is a smaller download, not a smaller lookup: the alias costs the same 1.28 KiB only because the complete catalog is already resident in the Pages Function, embedded in its bundle as base64 and decoded per isolate, so the work and the megabyte sit on the server instead of the device. The table above therefore reports the figure without ranking it, on the same βedge pathβ rule applied to ReBang and cf-unduck. Flashbang transferred 14.00 KiB across two requests for the hot bang (~34.5 KiB decoded) and 21.16 KiB across three for the alias (~49.9 KiB decoded), the third request being the routed shard; across 10 rounds each those held to 14.00β14.29 KiB and a flat 21.16 KiB. Flashbang's complete worker plus warm catalog measures 235.9 KiB transferred across 20 requests (~656.4 KiB decoded, 239.8β259.2 KiB across three install rounds), and continues caching only after the destination request starts. Decoded totals in this campaign are the response bodies after HTTP decompression for every request, matching the definition in the footnote above; earlier campaigns fell back to the compressed size for requests the harness did not refetch, which understated them.
Unduckified's offline footprint is quoted from its build artifact β 191.0 KiB Brotli worker-plus-catalog, 693.9 KiB decoded β and not from this harness. The harness observed only its bootstrap document and sw.js (1.7β4.7 KiB) inside the idle window, because the bootstrap navigates away with location.replace() before catalog precaching becomes observable to the measuring context. That figure reflects a limitation of the measurement, not a 1.7 KiB offline install; its worker restart times in the table above confirm a fully populated catalog.
Flashbang works differently. A Service Worker intercepts your navigation before the browser starts rendering any page. With a live worker, it parses the bang from the raw URL, resolves it through the packed minimal-perfect-hash lookup, and responds with a 302 redirect in under 1 ms in the measured campaign. No page loads and no page or UI bundle is parsed on that warm path. If the browser has stopped the worker, Flashbang restores its persisted hot-boot state; the measured restart medians were about 3.2 ms before the destination request. Your browser goes straight from the address bar to the destination without an intermediate rendered page.
Unduckified now uses the same broad warm-path architecture: an installed Service Worker, a packed binary catalog, and a page fallback for the first uncontrolled navigation. Its steady-state redirect time is therefore comparable to Flashbang's. The restart path is different: Unduckified rebuilds its in-memory lookup from the full cached catalog, while Flashbang's persisted hot-boot record and generated hot-bang table can answer common searches before its full runtime is ready. Flashbang also has a larger merged catalog, codegen-validated 16-bit trigger fingerprints, a configurable parser, snaps and snap chains, advanced custom bangs, private fragment mode, and frecency-aware suggestions.
For a first-ever search, Flashbang starts its cold resolver module (~10.3 KiB transferred / ~28.0 KiB decoded in the current build, which includes the locale table). Generated hot bangs such as !gh resolve from the module's embedded table without fetching a catalog shard. Other built-ins such as !github start a deterministic routed shard in parallel with the module; across the current 43-shard catalog, each shard is ~6.0β7.2 KiB transferred / ~13.8β16.0 KiB decoded. Flashbang redirects as soon as the required state resolves while Service Worker registration proceeds independently. Before registering, the page creates an empty build-specific handoff cache; activation consumes that signal and starts the complete catalog only after yielding to the destination. Controlled hot redirects schedule the same post-response warm under FetchEvent.waitUntil(). The full lookup is therefore available offline after the first successful use without competing with the first redirect, and rich fallback paths can still hand an already-loaded catalog and settings directly to the worker.
The new-profile benchmark is therefore network-sensitive end to end: it includes initial document delivery, first-page fallback execution, cold-module loading, any required shard transfer and decoding, and the outbound redirect. Worker installation starts concurrently but is not awaited. Serving the document from Cloudflare's edge cache and naming the cold resolver in an HTTP 103 Early Hints response removes two waits from that chain β the origin round trip for the document, and the gap between the document arriving and the resolver request starting. As of August 22, 2026 the hot !gh query on a new profile is a tie in which Flashbang holds the lower median, and Unduckified wins only the full-catalog !github alias, by 12.45 ms, which is the routed shard. Repeat campaigns move both verdicts, so neither is stable enough to lean on.
What remains of that row is the cost of a deliberate tradeoff rather than an unclaimed optimization. The state it measures occurs once per profile β plus any later search made while no worker controls the navigation β against a warm path taken thousands of times, and a 12.45 ms margin sits inside the run-to-run network variance already present in the column, whose paired interval spans 20 ms. Resolving at the edge is also not free of consequence. On the default ?q= URL both tools receive the query string during a cold navigation, since it is part of the URL being requested β but Flashbang answers with a static asset and derives the destination on the device, while Unduckified's Pages Function parses the query, returns the resolved destination in a Location header, and sets a seven-day cookie, so its origin learns both the search and its target for as long as no worker is installed.
More decisively, the two designs are not interchangeable. Flashbang additionally supports private fragment search at https://flashbang.tech/#q=%s, where the query lives in a URL fragment that browsers never transmit, so it does not reach Flashbang's server even on a first visit. A server-side redirect cannot offer this at any speed: an edge function is structurally unable to read a fragment, so a tool that resolves on the server must be given the query in the request line. Taking the new-profile row by resolving on a server therefore requires giving up the mode that makes the query private, which is why Flashbang resolves the first search locally and accepts the extra shard fetch as the price. What an edge cache can do β and what the August 22 change does β is remove the origin from the path without letting it see the query at all.
The packed bang database (currently ~545 KiB uncompressed), settings UI, and suggestion index are separate artifacts, so a redirect does not parse metadata it does not need. For first-page redirects, codegen weighs the actual encoded bangs, balances 256 hash cells across 43 catalog shards, and embeds the resulting 256-byte, one-byte-per-cell router; one table lookup selects the shard while the complete database warms after navigation. The odd shard count and layout are tailored to the current catalog rather than imposed by a generic power-of-two partition. The raw parser, minimal-perfect-hash lookup, hot-boot tier, and deferred persistence behind that path are described in How it works.
Not the few hundredths of a millisecond separating live workers. The measurable difference in Flashbang's favor is the worker restart, where it avoids rebuilding the full lookup and answers 0.55β0.77 ms sooner β a state a browser enters routinely, whenever it has stopped an idle worker between searches. On the first search in a new profile the two are level for a hot bang, and Unduckified is ahead on a query that routes to a catalog shard, because it resolves that search on its server rather than on your device. Flashbang keeps every redirect on the device by design and pays for it there. Both projects still depend on network conditions for their first uncontrolled page.
Run the benchmark yourself to measure validated browser-to-Service-Worker fetch latency and paired top-level redirect overhead on your device.
Flashbang was inspired by unduck by Theo Browne, which demonstrated the value of fast client-side bang redirects. Bang data is sourced from DuckDuckGo and Kagi.
A GitHub Actions workflow runs every 24 hours at 00:00 UTC to fetch the latest bang definitions from DuckDuckGo and Kagi, rebuild the generated JSON, and commit any changes. This keeps the bang database current without manual intervention.
See DEVELOPMENT.md for prerequisites, build commands, and project structure.
Flashbang is designed to be self-hosted and most of projects in this space bundle analytics. AGPL ensures that anyone who deploys a modified version must share their changes β protecting end users from forks that quietly add tracking or degrade privacy. The project introduces a genuinely novel approach (Service Worker intercept, two-tier bang data, bang-aware suggestions), and AGPL ensures derivatives contribute back rather than just extract.
