Degoog Docs

Degoog Transports

Custom HTTP fetch strategies for your outgoing search requests.

What transports are

A transport controls exactly how Degoog makes its outgoing HTTP requests to search engines. You can select a specific transport for each engine by navigating to Settings then Engines then Configure then Advanced.

We include three built in transports out of the box:

Name Behaviour
fetch The native Bun fetch implementation with full SOCKS 5 and HTTP proxy support. This is the default for all engines.
curl Shells out directly to your system curl binary. This uses a different TLS stack which helps immensely when a website tries to block the default Bun fingerprint.
auto Tries fetch first. If the server responds with a 403, 429, 502, or 503 error, it automatically retries the request using curl.

You can install additional transports like FlareSolverr straight from the Store or place them manually inside your data/transports/ directory.

Where transports live

Your custom transports belong in data/transports/ or whatever path you set for DEGOOG_TRANSPORTS_DIR. Each transport is just a file or folder containing an entry file that exports a class or object implementing the transport contract.

Transport contract

Required properties:

  • name: A unique identifier written in lowercase with no spaces.
  • available(): Return true or a Promise resolving to true when your transport is ready to use. If you return false, the transport will be hidden from the engine dropdown menus.
  • fetch(url, options, context) (async): Perform the actual HTTP request and return a standard Response object.

Optional properties:

  • displayName: The friendly name shown in Settings then Transports.
  • description: A short description displayed in Settings then Transports.
  • settingsSchema and configure(settings): These follow the exact same pattern as engines and plugins. A Configure button will appear in Settings then Transports, and your values are stored safely in data/plugin-settings.json under transport-<name>.

Arguments

options

Field Type Description
method string The HTTP method which defaults to "GET".
headers Record<string, string> Your request headers.
body string The request body.
redirect RequestRedirect The redirect mode which defaults to "follow".
signal AbortSignal The abort signal used for cancellation.

context

Field Type Description
proxyUrl string | undefined The proxy URL configured in Settings then Server then Proxy. This comes already rotated. It will be undefined when proxies are disabled.
fetch (url, init?) => Promise<Response> A proxy aware fetch function. Always use this for all your outbound requests so the user proxy settings like SOCKS 5 or HTTP CONNECT are respected automatically.

Proxies

When a user enables a proxy in Settings then Server, context.proxyUrl is populated and context.fetch routes through it automatically. Your transport should always use context.fetch for any outbound HTTP calls so proxy routing just works effortlessly:

async fetch(url, options, context) {
          const doFetch = context.fetch;
          const res = await doFetch("https://my-service.example.com/api", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ target: url }),
            signal: options.signal,
          });
          // transform and return a Response
        }

Setup

Create your data/transports/ directory or set your DEGOOG_TRANSPORTS_DIR. Add a single file like my-transport.js or create a folder with an index.js file. Your transport settings ID will automatically become transport-<name>.

How settings work

  1. Declare your settingsSchema so a Configure button appears in Settings then Transports.
  2. When the user saves, the values go into data/plugin-settings.json under transport-<name>.
  3. Your configure(settings) function is called right after saving and every time the server restarts if settings exist.
  4. Return false from available() when required settings are missing so the transport does not show up in engine dropdowns until it is fully configured.
  5. Users can easily disable configurable transports using the toggle switch in Settings then Transports.

Example minimal transport

export default class MyTransport {
          name = "my-transport";
          displayName = "My Transport";
          description = "Example custom transport.";
        
          settingsSchema = [
            {
              key: "apiUrl",
              label: "API URL",
              type: "url",
              required: true,
              placeholder: "https://my-service.example.com",
            },
          ];
        
          _apiUrl = "";
        
          configure(settings) {
            this._apiUrl = (settings.apiUrl || "").trim();
          }
        
          available() {
            return this._apiUrl.length > 0;
          }
        
          async fetch(url, options, context) {
            const doFetch = context.fetch;
        
            const res = await doFetch(this._apiUrl, {
              method: "POST",
              headers: { "Content-Type": "application/json" },
              body: JSON.stringify({ url, timeout: 10000 }),
              signal: options.signal,
            });
        
            if (!res.ok) return new Response("", { status: res.status });
            const data = await res.json();
            return new Response(data.html ?? "", {
              status: data.status ?? 200,
              headers: { "Content-Type": "text/html" },
            });
          }
        }

Examples from the official store

  • FlareSolverr lets you bypass Cloudflare challenges via a FlareSolverr instance. It correctly uses context.fetch so all proxy settings are respected.

If you are distributing your transport through the Store, just add it under the transports/ directory in your repository and list it in the transports array inside your package.json.