ddg-kit
August 2, 2026 ยท View on GitHub
A focused, community-maintained compatibility client and maintenance path for
the Web and News APIs used by
duck-duck-scrape.
ddg-kit provides a maintained migration path for applications that depend on
the observed duck-duck-scrape Web and News API. It preserves familiar
function names, options, enums, and result shapes while adding typed provider
failures, cancellation, one query deadline, and explicit proxy control.
The code is a greenfield rewrite. ddg-kit is not an official
duck-duck-scrape release and is not affiliated with DuckDuckGo.
Current release:
0.1.0supports Web and News only. Images, video, autocomplete, public VQD/bootstrap helpers, and spice endpoints are outside the current compatibility claim.
Relationship to duck-duck-scrape
ddg-kit occupies the community-maintained compatibility role for downstream
applications that use the Web and News surface of duck-duck-scrape. We
maintain the greenfield client, compatibility fixtures, release
artifacts, failure semantics, and migration guidance for that surface.
We do not maintain the duck-duck-scrape repository, own its npm package, or
represent its maintainers. ddg-kit is not an official fork, package transfer,
or DuckDuckGo integration. Its compatibility target is the observed downstream
API, not an upstream promise.
Applications can migrate Web and News to ddg-kit while keeping
duck-duck-scrape for endpoints that are not yet supported here. This staged
path is intentional: it gives downstream maintainers a maintained compatibility
option without requiring an all-at-once dependency replacement.
Installation
npm install ddg-kit
Requirements:
- Node.js 18.17 or newer
- ESM or CommonJS
No API key is required. DuckDuckGo does not publish a supported contract for the endpoints used by this package. Provider changes can therefore cause typed failures until the package adapts.
Quick start
Web search
import { SafeSearchType, search } from "ddg-kit";
const response = await search("Node.js AbortSignal", {
maxResults: 5,
safeSearch: SafeSearchType.MODERATE,
});
for (const result of response.results) {
console.log(result.title, result.url);
}
News search
import { SearchTimeType, searchNews } from "ddg-kit";
const response = await searchNews("semiconductor earnings", {
maxResults: 5,
time: SearchTimeType.WEEK,
});
for (const result of response.results) {
console.log(result.title, result.url);
}
CommonJS consumers can use the same named API:
const { search, searchNews } = require("ddg-kit");
Why this package exists
Many existing duck-duck-scrape consumers need a maintained migration path.
That path must not turn uncertain provider responses into successful empty
results. DuckDuckGo can return a challenge page, an HTTP error, or a changed
payload. ddg-kit rejects those responses with DdgError.
The package keeps the useful part of the prior Web/News contract:
search,searchNews,SafeSearchType, andSearchTimeType- familiar Web and News result fields
- named, namespace, default, dynamic, ESM, and CommonJS imports
This release also adds:
- structured errors for challenges, limits, timeouts, HTTP failures, response limits, and parse changes
- one total deadline across fallback attempts
AbortSignalcancellation- explicit proxy selection and credential-safe failures
- tests against the packed npm artifact
Public API
| Export | Purpose |
|---|---|
search(query, options?, request?) | Run a Web search |
searchNews(query, options?, request?) | Run a News search |
createDdgClient(options?) | Create a configured client |
DdgError | Inspect a typed provider or transport failure |
SafeSearchType | Select strict, moderate, or disabled safe search |
SearchTimeType | Select day, week, month, year, or all time |
Common search options:
| Option | Web | News | Purpose |
|---|---|---|---|
safeSearch | Yes | Yes | Select content filtering |
time | Yes | Yes | Restrict results by age |
locale | Yes | Yes | Select the request locale |
region, marketRegion | Yes | No | Select Web result regions |
offset | Yes | Yes | Request a result offset |
vqd | Yes | Yes | Supply an existing DuckDuckGo query token |
maxResults | Yes | Yes | Bound the returned result count |
The third argument accepts signal, timeoutMs, and proxy. It does not
accept arbitrary Needle options.
Handle failures by code
import { DdgError, search } from "ddg-kit";
try {
const response = await search("example query");
console.log(response.results);
} catch (error) {
if (!(error instanceof DdgError)) {
throw error;
}
if (error.code === "BOT_CHALLENGE") {
console.error("DuckDuckGo returned a challenge", error.cooldownMs);
} else if (error.retryable) {
console.error("Search can be retried later", error.code);
} else {
console.error("Search failed", error.code);
}
}
| Code | Meaning |
|---|---|
INVALID_INPUT | The query or option value is invalid. |
UNSUPPORTED_OPTION | The package cannot preserve the requested semantics. |
TIMEOUT | The total query deadline expired. |
RATE_LIMITED | DuckDuckGo returned a rate limit. |
BOT_CHALLENGE | DuckDuckGo returned a bot or anomaly challenge. |
UPSTREAM_4XX | DuckDuckGo returned a client HTTP error. |
UPSTREAM_5XX | DuckDuckGo returned a server HTTP error. |
PARSE_ERROR | A provider response no longer matches the parser contract. |
RESPONSE_TOO_LARGE | A response crossed the configured safety limit. |
UNKNOWN | The transport failed without a more specific classification. |
Check error.retryable before retrying. Respect error.cooldownMs after a bot
challenge.
Request control
Create a client when several calls share the same policy:
import { createDdgClient } from "ddg-kit";
const client = createDdgClient({
timeoutMs: 10_000,
proxy: "http://127.0.0.1:8080",
challengeCooldownMs: 60_000,
});
const controller = new AbortController();
const response = await client.search(
"example query",
{ maxResults: 10 },
{
signal: controller.signal,
timeoutMs: 5_000,
},
);
Pass proxy, set DUCKDUCKGO_PROXY_URL, or opt in with USE_PROXY=true and
PROXY_URL. The package ignores ambient HTTP_PROXY and HTTPS_PROXY
settings.
Compatibility and scope
Many Web and News consumers can migrate by changing the package name:
- import { search, SafeSearchType } from "duck-duck-scrape";
+ import { search, SafeSearchType } from "ddg-kit";
Review the third request argument during migration:
await search("query", searchOptions, {
signal,
timeoutMs: 10_000,
proxy: false,
});
Supported in 0.1.0 | Planned or outside the current scope |
|---|---|
| Web and News search | Images, video, and autocomplete |
search, searchNews, createDdgClient | Public VQD or bootstrap helpers |
| Safe search, time, locale, region, offset, max results | Spice endpoints |
| ESM and CommonJS | MCP server behavior |
| Timeout, cancellation, cooldown, explicit proxy | Aggregation and ranking |
Web representation fallback is internal. Callers cannot select Web preload, HTML, or Lite parsing paths. Read MIGRATION.md for deliberate differences, VQD behavior, and rollback guidance.
The public compatibility matrix is the source for the current Web/News P0 contract. It records supported exports, deliberate option mappings, structured failure behavior, and legacy surfaces that remain outside the release line.
ddg-kit does not bypass rate limits, bot challenges, CAPTCHAs, or access
controls. Applications that need a supported service-level agreement should
use an official search API.
Planned compatibility (P1)
Images and video search are planned for P1. They are not part of the 0.1.0
public compatibility claim. These endpoints have different request filters and
result schemas from Web and News, so P1 will add separate typed APIs and
parsers. It will not alias image or video results to Web results.
P1 must add frozen fixtures for successful, empty, challenged, malformed,
timed-out, and paginated responses. It must pass the packed ESM/CommonJS
matrix and a downstream canary before consumers remove their remaining
duck-duck-scrape dependency. Until then, applications that need Images or
video should keep that dependency for those operations. They may migrate Web
and News to ddg-kit independently.
Verification
Version 0.1.0 promotes the runtime code accepted in v0.1.0-rc.2. Changes
after RC2 cover documentation and release metadata, not runtime behavior.
The project records each type of evidence separately:
- Package checks: 27 tests, type checking, build, and packed-consumer tests
- Runtime matrix: packed ESM and CommonJS consumers on Node 18.17, 20, and 22
- Failure behavior: synthetic fixtures for challenges, limits, timeouts, HTTP errors, parse changes, and response limits
- Independent review: RC1 was rejected after a clean-checkout failure; RC2 was accepted after the fix
- Migration evidence: downstream canaries and maintainer-reviewed merged pull requests record focused Web/News adoption and unresolved limits
Read the RC1 rejection report, the RC2 acceptance report, and the compatibility status.
Local canaries do not prove production adoption, downstream maintainer approval, Linux or macOS runtime behavior, or long-running provider stability. The canary index records the current evidence. The adoption index separates local canaries from downstream maintainer acceptance.
Recent downstream evidence includes
OpenCandle PR #145 and
intercept-mcp PR #6.
Both merged focused Web/News migrations. These merges show maintainer review
and acceptance of a narrow compatibility change; they do not provide a
production SLA or prove broad provider stability.
Maintenance and contributions
You can open a focused pull request for:
- reproducible Web or News fixes with synthetic fixtures
- error, timeout, cancellation, proxy, redaction, or package compatibility fixes
- documentation corrections and focused tests
Open a proposal before changing the public API, result contract, retry policy, runtime dependencies, supported Node versions, or Web/News product boundary.
The project does not accept provider-control bypasses, live response bodies, credentials, private queries, silent semantic changes, or unrelated search aggregation work. Read CONTRIBUTING.md and SECURITY.md before submitting a change. Use the support and compatibility guide to report provider breakage or request a new compatibility surface. GOVERNANCE.md describes the maintenance and adoption signals behind trust claims.
Development
npm ci
npm run check
Run the packed Node matrix when a change affects the public API, runtime compatibility, build, or package contents:
npm run test:matrix
Default tests stay offline. The opt-in live E2E runner uses one Web request and one News request with automatic retries disabled. A provider challenge is recorded as blocked evidence, not as a successful empty result.
Release integrity
Each release binds one source commit to one annotated Git tag, GitHub Release, npm package, and recorded tarball hash. The publish workflow requests npm provenance from GitHub Actions.
See CHANGELOG.md, the release checklist, and the code provenance record.
License
Apache-2.0. See docs/PROVENANCE.md for the greenfield code origin and dependency license review.