npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ddg-kit

v0.1.1

Published

Community-maintained DuckDuckGo Web and News client for duck-duck-scrape consumers.

Readme

ddg-kit

npm version CI license

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.0 supports 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, and SearchTimeType
  • 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
  • AbortSignal cancellation
  • 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.