Degoog Autocomplete
Build your own autocomplete providers to power the search-bar suggestion dropdown. Providers are aggregated, deduplicated, and ranked automatically.
Where providers live
Drop your custom provider into data/autocomplete/ or whatever you
set DEGOOG_AUTOCOMPLETE_DIR to. Each provider is a file or folder
with an entry file that exports a class or object containing a
name and getSuggestions.
Provider contract
Required:
- name: The display name shown in Settings → Autocomplete.
-
getSuggestions(query, context) (async): Returns a
Promise<AutocompleteSuggestion[]>. The array should contain plain suggestion strings or rich suggestion objects ({ text: string, rich?: RichSuggestion }). Return an empty array if no suggestions are available - never throw.
Optional:
-
settingsSchema and configure(settings):
Declare settings fields and receive saved values on startup and after every
save. Works exactly like engines and plugins. See
Search engines for the full
SettingFieldshape reference.
The context object
Every call to getSuggestions receives a
context argument. Always use context.fetch for
outbound HTTP so the provider respects proxy and transport settings.
| Field | Type | Description |
|---|---|---|
context.fetch |
typeof fetch |
A proxy- and transport-aware fetch function. Use this for every outbound
HTTP request instead of the global
fetch.
|
context.lang |
string |
ISO 639-1 base language code (e.g. "en", "fr",
"de"). Derived from the
DEGOOG_DEFAULT_SEARCH_LANGUAGE environment variable.
Defaults to "en" when the variable is unset.
|
context.useCache |
UseCache |
Async, namespaced TTL cache factory. Call
context.useCache<T>(namespace, defaultTtlMs) to get a
cache with await get, await set,
await delete, and await clear. Shared across
replicas when the optional Valkey sidecar is configured; per-process
otherwise.
|
Rich suggestions
Providers can return entity cards (images, subtitles, and descriptions) that appear at the very top of the autocomplete dropdown. To do this, return an object instead of a string:
export interface RichSuggestion {
description?: string;
thumbnail?: string;
type?: string;
}
export type AutocompleteSuggestion = string | { text: string; rich?: RichSuggestion };
Plain string suggestions are fetched on the server via
context.fetch (which respects the provider's outgoing transport).
When you include rich.thumbnail, return the upstream image URL
from getSuggestions. Degoog rewrites it to a signed
/api/proxy/image URL before the suggest API responds, so the
dropdown loads the image through the server.
Declaring client exposure
The settings page shows a network indicator on plugin cards when an extension
declares isClientExposed. Autocomplete providers do not use that
field. Return upstream thumbnail URLs as usual; Degoog signs them for the
image proxy when suggestions are merged.
Set needsAppRestart = true if your autocomplete provider cannot
work correctly until the Degoog server process restarts, for example because
it registers boot-time server behavior. When installed or updated via the
Store, Degoog will show a restart required warning on the extension and in the
admin Server tab until the instance owner restarts.
export const needsAppRestart = true;
| What you return | Server requests | Browser requests |
|---|---|---|
| Plain strings only |
Your provider uses context.fetch to call upstream APIs.
|
None from the provider itself. |
Rich suggestions with thumbnail |
Your provider fetches suggestions; Degoog signs each thumbnail for
/api/proxy/image.
|
The browser loads the signed proxy URL only. Degoog fetches the upstream image on the server. |
You do not need to call signProxyUrl or build proxy URLs yourself
in a provider. Omit rich.thumbnail entirely if you do not want
image cards in the dropdown.
async getSuggestions(query, context) {
const doFetch = context?.fetch ?? fetch;
const res = await doFetch(`https://example.com/suggest?q=${encodeURIComponent(query)}`);
const items = await res.json();
return items.map((item) => ({
text: item.title,
rich: {
description: item.subtitle,
thumbnail: item.imageUrl,
},
}));
}
async getSuggestions(query, context) {
const doFetch = context?.fetch ?? fetch;
const res = await doFetch(`https://example.com/suggest?q=${encodeURIComponent(query)}`);
const items = await res.json();
return items.map((item) => item.title);
}
Minimal example
export default class MyAutocompleteProvider {
name = "My Provider";
async getSuggestions(query, context) {
if (!query.trim()) return [];
const doFetch = context?.fetch ?? fetch;
const encoded = encodeURIComponent(query.trim());
try {
const res = await doFetch(
`https://example.com/suggest?q=${encoded}`,
{ headers: { Accept: "application/json" } },
);
if (!res.ok) return [];
const data = await res.json();
// OpenSearch format: [query, [suggestion, suggestion, ...]]
if (Array.isArray(data) && Array.isArray(data[1])) {
return data[1].map(String).filter(Boolean);
}
return [];
} catch {
return [];
}
}
}
OpenSearch compatibility
The /api/suggest/opensearch endpoint returns results in the
OpenSearch Suggestions 1.1
format: [query, [suggestion, suggestion, ...]]. This means your
browser address bar can use Degoog directly as a search engine with
autocomplete. Custom providers do not need to do anything special - the
registry wraps all results automatically.
Aggregation and scoring
When multiple providers are enabled, their suggestions are fetched in parallel and merged using a round-robin interleave. Duplicates are collapsed into a single suggestion that shows all contributing sources. The merged list is capped at 10 items.
Each provider has a Score field under the
Advanced section in Settings → Autocomplete. Higher
scores mean that provider's suggestions appear earlier in the merged list. The
default score is 1.
Outgoing transport
Like engines, every provider automatically gets an
Outgoing HTTP client selector under
Advanced. This can be set to fetch,
curl, curl-fallback, or any custom
transport you have installed. Always
use context.fetch in your provider so this setting applies
automatically.
Settings example
export default class MyAutocompleteProvider {
name = "My Provider";
settingsSchema = [
{
key: "apiKey",
label: "API Key",
type: "password",
secret: true,
required: false,
description: "Optional API key for authenticated requests.",
},
];
apiKey = "";
configure(settings) {
this.apiKey = typeof settings.apiKey === "string" ? settings.apiKey.trim() : "";
}
async getSuggestions(query, context) {
if (!query.trim()) return [];
const doFetch = context?.fetch ?? fetch;
const encoded = encodeURIComponent(query.trim());
const headers = { Accept: "application/json" };
if (this.apiKey) headers["Authorization"] = `Bearer ${this.apiKey}`;
try {
const res = await doFetch(`https://example.com/suggest?q=${encoded}`, { headers });
if (!res.ok) return [];
const data = await res.json();
return Array.isArray(data) ? data.map(String).filter(Boolean) : [];
} catch {
return [];
}
}
}
Language
context.lang is always set to a two-letter ISO 639-1 code. It is
derived from the DEGOOG_DEFAULT_SEARCH_LANGUAGE environment
variable (e.g. en-GB becomes en). If the variable is
not set, context.lang defaults to "en". Use it to
pass language or market parameters to your upstream API.
async getSuggestions(query, context) {
const lang = context?.lang ?? "en";
const mkt = `${lang}-${lang.toUpperCase()}`; // e.g. "en-EN", "fr-FR"
const res = await (context?.fetch ?? fetch)(
`https://example.com/suggest?q=${encodeURIComponent(query)}&lang=${lang}`,
);
// ...
}
Setup
Create your data/autocomplete/ directory or set
DEGOOG_AUTOCOMPLETE_DIR. Add a single file like
my-provider.js or a folder with an index.js. The
provider ID will be the filename or folder name prefixed with
autocomplete-.
If you plan on distributing your provider through the
Store, add it under the
autocomplete key in your store's
package.json manifest alongside a
screenshots/ folder so the Store card looks great.
Built-in providers
Degoog ships two built-in providers that are always available and cannot be uninstalled:
- Google - uses the Firefox suggest endpoint.
- DuckDuckGo - uses the public DuckDuckGo autocomplete API.
Additional providers (Brave, Bing, Yahoo) are available from the official store under the Autocomplete category.