All posts

DuckDuckGo search API: 4 types and how to choose

Which DuckDuckGo search API should you use? Use ddgs for small jobs or a hosted SERP API for ranked results. Learn to call it with a token and catch blocks.

  • duckduckgo
  • serp api
  • web scraping
  • ddgs
  • ai agents
On this page

“DuckDuckGo search API” covers four different things: the Instant Answer API, unofficial libraries such as ddgs, hosted SERP APIs, and proxies for DuckDuckGo AI Chat. For ranked web results, use a library or a SERP API. With Wayfern’s Search API, POST to https://api.wayfern.com/api/search/v1 with engines set to duckduckgo and a search-scoped wf_ token.

If you run scrapers, crawlers or agents on DuckDuckGo data, the question that matters is whether a blocked request tells you it was blocked.

You will be able to pick the right option, send an authenticated request that works, and handle the case where the engine returns nothing.

Key Takeaways

What does ‘DuckDuckGo search API’ actually mean?

“DuckDuckGo search API” names four kinds of product, and only two of them, unofficial libraries and hosted SERP APIs, return ranked organic rows. The Instant Answer API returns topic summaries, and AI chat wrappers return model answers.

Image generated

BucketWhat it returnsWho maintains itFit
Instant Answer APIAn abstract and related topics for an entityDuckDuckGoLooking up one named thing, not tracking rankings
Unofficial libraries (ddgs)Web, image, video and news resultsOpen-source contributorsLow volume, and you own the fixes
Hosted SERP APIs (SerpApi, SearchAPI.io, Wayfern)Parsed result rows as JSONThe vendorProduction volume and monitoring
AI chat proxiesModel answers, not search rowsIndividual repo authorsChat features, not SERP data

The EudaLabs ddgs library for Node.js lists web, image, video and news search as its features. Nothing backs it except its contributors, so a change on DuckDuckGo’s side is yours to fix.

Hosted APIs differ in scope. SerpApi’s DuckDuckGo endpoint is https://serpapi.com/search?engine=duckduckgo, and its kl parameter takes region codes such as us-en or fr-fr.

Wayfern’s Search API returns DuckDuckGo next to Google and Bing in one call, as our SERP API use case describes.

The fourth kind is the easiest to mistake for search. On GitHub’s duckduckgo-api topic page, some repositories wrap DuckDuckGo’s AI Chat as an OpenAI-compatible API. They return chat completions, not a results page.

Why do DIY scrapers and unofficial DuckDuckGo wrappers fail silently?

A DIY scraper or unofficial wrapper fails silently because a blocked request comes back as an ordinary page, and your parser reads that page as a search with zero results.

The failure takes four steps. Your code sends the query. The engine answers with a challenge or block page instead of results.

That page has no result markup, so your selectors match nothing. The parser returns an empty list, and the caller gets no status signal that says why.

A crash gets noticed. An empty list gets stored, and your pipeline records “no results” as a fact: a rank tracker shows a keyword vanishing, or an agent tells its user the web has nothing on the topic.

Check how each library reports a block before you trust it. The ddgs repository on GitHub lists “Advanced request handling to prevent rate limiting” as a feature.

Read its error-handling docs, then send a burst of queries. Watch whether any call raises an exception or whether they all return [].

Maintenance is the second failure. On GitHub’s duckduckgo-api topic page, one repository is a “lightweight package to get image results from duck duck go” with an old update date.

Before you depend on a wrapper, check three things:

  • The date of the last commit.
  • The open issues, especially reports of empty results.
  • Any deprecation note in the README.

The Wayfern Search API handles this differently: it lists failed engines in meta.engines_failed, so a partial failure doesn’t pass as an empty list.

Which DuckDuckGo search API parameters control region, dates, safe search and pagination?

Wayfern’s Search API controls DuckDuckGo results through six groups of fields, and five of them have a documented field in the Search API reference. Safe search is the exception. DuckDuckGo’s own help pages list its regions, safe search options and search syntax.

  1. Region and language: region, lang. DuckDuckGo uses kl-style codes, the format SerpApi’s kl parameter takes. Wayfern carries the region in region and the language in lang. Check the accepted value format in the API reference before you pass a kl code unchanged.

  2. Date range: date. Wayfern takes YYYYMMDD..YYYYMMDD, for example 20260101..20260131. Use Wayfern’s field names, not the parameter names in other vendors’ sample requests or responses.

  3. Operators: text, site, filetype. SearchAPI.io’s DuckDuckGo docs say DuckDuckGo queries can include operators such as site:, intitle: and inurl:. In Wayfern, put those in text, which accepts up to 512 characters.

    site and filetype are also separate fields, so you don’t have to build them into the string.

  4. Safe search: no documented Wayfern field. The honest catch: safe search is not among the documented Wayfern fields. DuckDuckGo’s safe search help page describes the setting itself. Read the API reference for DuckDuckGo-specific behavior before you rely on it.

  5. Pagination: limit, start. limit runs from 1 to 200 per engine and defaults to 50. start is an offset, and each response returns pagination.next_start and has_more.

    Loop on has_more instead of assuming a fixed page size, since result counts and duplicates can vary between requests. filter handles near-duplicates.

  6. Feature blocks: features. Set it to get people-also-search blocks in serp_features. Check the API reference for the DuckDuckGo response shape before you build a parser around any other block.

How do you call a DuckDuckGo search API with authentication and read the response?

You call DuckDuckGo through Wayfern’s Search API with one authenticated POST to https://api.wayfern.com/api/search/v1, then read ranked rows plus a status block.

  1. Create a token. Mint a search-scoped wf_ token and export it as WF_TOKEN. Tokens are shown once, so keep the value out of your code.
  2. Send the request. Set engines to duckduckgo:
curl -X POST https://api.wayfern.com/api/search/v1 
  -H "Authorization: Bearer $WF_TOKEN" 
  -H "Content-Type: application/json" 
  -d '{"text":"open source web scrapers","engines":["duckduckgo"],"region":"us-en","limit":10}'
  1. Add engines when you need them. Change one field: "engines":["google","bing","duckduckgo"]. Per the SERP API page, the engines are fetched at the same time and duplicate URLs are merged, so a URL that Google and DuckDuckGo both return appears once.
  2. Read the response. This sample shows the shape; it is illustrative, not captured output:
{
  "results": [
    {"absolute_rank": 1, "type": "ad", "ad": true, "url": "https://ads.example.com/offer", "engine": "duckduckgo"},
    {"rank": 1, "absolute_rank": 2, "type": "organic", "ad": false, "url": "https://example.org/guide", "engine": "duckduckgo"}
  ],
  "pagination": {"next_start": 10, "has_more": true},
  "meta": {"engines_failed": []}
}
  • As Wayfern’s SERP page defines them, rank counts organic rows only. absolute_rank counts every row in page order, ads included.
  • type and ad say what kind of row it is. url is the result, and engine names the engine that returned it.
  • pagination.next_start is the start offset for the next call. has_more says whether another page exists.
  • meta.engines_failed names any engine that failed.

Check meta.engines_failed before you trust a short list. A blocked engine can return what looks like an empty list, and this field is the only place the response says so.

Agents use the same search as the search_web tool on the MCP server at https://api.wayfern.com/mcp, and list_search_engines is free. The MCP docs and our page on live web data for AI agents show the setup.

How do you handle errors, caching and rate limits when searching DuckDuckGo?

You handle DuckDuckGo errors by treating partial failure as a normal state: read meta.engines_failed after every call, retry or fall back, and cache what you already paid for.

  1. Read meta.engines_failed first. If it names duckduckgo, count the call as a failure, not as “no results”. Wayfern’s SERP page says “A blocked engine often looks like an empty result list, so failures pass silently.”
  2. Retry with backoff, or fall back. Wait 2 seconds, then 4, then 8. Or drop to the other engines in the same request.
  3. Page when rows are short. If rows came back but fewer than you expected, check pagination.has_more and request again with pagination.next_start as start.
import time, requests

def search(body, token, tries=3):
    for i in range(tries):
        r = requests.post("https://api.wayfern.com/api/search/v1",
                          json=body,
                          headers={"Authorization": f"Bearer {token}"})
        r.raise_for_status()
        data = r.json()
        if "duckduckgo" not in data["meta"].get("engines_failed", []):
            return data
        time.sleep(2 ** (i + 1))
    raise RuntimeError("duckduckgo failed after retries")
  1. Cache on your side. Wayfern caches search results for 5 minutes, but it bills cache hits too, at 2 credits per provider results page. Key your own cache on the full request body so repeat queries cost nothing.
  2. Stay under the rate limit. The documented search limit is 30 requests a minute, inside a default of 120 a minute per client IP. Read the current rate limits before you size a worker pool.
  3. Stop at zero credits. As Wayfern’s home page says, “At zero credits, work stops.” There’s no free tier, so the cheapest way in is the Developer plan or a credit pack.

Libraries take the other approach: ddgs says it handles rate limiting inside the library, so throttling happens out of your sight. With a named-failure field, your code sees the failure and decides what to do.

Whether you may collect DuckDuckGo results depends on DuckDuckGo’s own terms and on the law where you work.

Read DuckDuckGo’s current terms yourself and check whether they address automated access clearly. If they don’t, treat that as an open question, not as permission.

Wayfern’s terms of service require lawful use. Don’t collect in ways that ignore a site’s terms or the law.

A hosted API doesn’t change your obligations: you still decide what gets collected and why. If you plan to resell results or store them at large scale, get legal advice first. This section is not legal advice.

ddgs, a single-engine API or a multi-engine API: which should you use?

OptionFits whenWhat you ownDocumented catch
Open-source ddgsSmall, low-volume jobsMaintenance, retries, block detectionThe name belongs to more than one project; check the last release
Single-engine vendor API (SerpApi, SearchAPI.io)You need DuckDuckGo-specific blocksYour integration; the vendor owns parsingCovers one engine per integration
Wayfern Search APIOne call should cover several enginesYour credit budget and your retry rulesNo free tier; rate-limited; no DuckDuckGo-only blocks

If your job is a few dozen queries a day, ddgs is likely enough. You own the upkeep, though. Read the README and the ddgs page on PyPI for the last release before you depend on it.

The name covers more than one project. The Python ddgs package is now a metasearch library that aggregates results from several search services, while EudaLabs ddgs is a Node.js library for DuckDuckGo. Confirm which one you’re installing.

If you need DuckDuckGo’s own result blocks, pick a single-engine vendor. SearchAPI.io’s docs say its DuckDuckGo API “parses organic results, ads, AI overview, knowledge graph, top stories, inline images, inline videos, and related searches.”

Wayfern’s documented fields cover organic rows, ads and people-also-search blocks. They don’t include those DuckDuckGo-only blocks, so check the Search API reference for the DuckDuckGo response shape before you commit.

Wayfern fits when DuckDuckGo is one of several engines. Our SERP page describes a multi-engine API “returning ranked Google, Bing and DuckDuckGo results with absolute ranks, ad flags and pagination.”

The credit balance is shared with the hosted browsers, the Web Data API and the MCP server, where the same search runs as the search_web tool. The honest catch: there’s no free tier, and the search endpoint is rate-limited.

If you’re also deciding between page-based and session-based tools, our web scraping buyer’s guide compares both by billing unit.

Best for:

  • ddgs: a few dozen queries a day, where you can absorb the maintenance.
  • Single-engine vendor: DuckDuckGo-specific blocks such as AI overview or knowledge graph.
  • Wayfern: scrapers and agents that want Google, Bing and DuckDuckGo behind one call and one balance.

Frequently asked questions

Does DuckDuckGo have an official search API?

DuckDuckGo documents an Instant Answer API, which returns instant answers and related topics, not a full ranked list of web results. For ranked results you use an unofficial library or a hosted SERP API. Check DuckDuckGo’s own API documentation for the current status before you build on either.

Is there a free DuckDuckGo search API?

The free route is open source: ddgs is a library, so you pay in maintenance instead of money. Wayfern has no free tier (see Wayfern pricing). For other vendors’ free quotas, check each vendor’s own pricing page.

Can I use DuckDuckGo results in an AI agent?

You can, through the search_web tool on Wayfern’s MCP server, which runs the same Search API call. list_search_engines is free. Our AI agents use case shows the setup.

What happens when DuckDuckGo blocks a request?

Wayfern names the blocked engine in meta.engines_failed instead of returning a result list that looks empty, as the SERP API use case describes. Read that field after every call, then retry or fall back. The API reference has the response shape.

How many results can I get per request?

Wayfern accepts a limit of 1 to 200 results per engine, per the Search API reference. Other vendors set their own caps, so read each vendor’s parameter docs before you plan pagination.

What should you do next with a DuckDuckGo search API?

Today: decide which of the four kinds of DuckDuckGo search API you need. Check the last release of any wrapper you already run.

This week: mint a search-scoped wf_ token (the developer docs show how), send the request from the how-to section, and read meta.engines_failed on every call. Check the search rate limit in the limits docs before you loop.

Later: add google and bing to engines, or wire search_web into an agent.

There’s no free tier, so start with a credit pack or the Developer plan on the pricing page and send that first request.

Sources

DDGS - DuckDuckGo Search API - GitHub · DuckDuckGo Search Engine Results API - SerpApi · duckduckgo-api · GitHub Topics · GitHub · SERP API - Google, Bing & DuckDuckGo | Wayfern · Pricing - Credits for Browsers & the Web Data API | Wayfern · API Reference - CDP, Web Data & Search | Wayfern · DuckDuckGo API Documentation · Wayfern MCP server docs. Every other source is linked where the article cites it.