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
- What does ‘DuckDuckGo search API’ actually mean?
- Why do DIY scrapers and unofficial DuckDuckGo wrappers fail silently?
- Which DuckDuckGo search API parameters control region, dates, safe search and pagination?
- How do you call a DuckDuckGo search API with authentication and read the response?
- How do you handle errors, caching and rate limits when searching DuckDuckGo?
- Is it legal to collect DuckDuckGo search results?
- ddgs, a single-engine API or a multi-engine API: which should you use?
- Frequently asked questions
- Does DuckDuckGo have an official search API?
- Is there a free DuckDuckGo search API?
- Can I use DuckDuckGo results in an AI agent?
- What happens when DuckDuckGo blocks a request?
- How many results can I get per request?
- What should you do next with a DuckDuckGo search API?
- Sources
“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
- A blocked scrape can look like an empty result list, so read the status field: Wayfern names failed engines in
meta.engines_failed.- On Wayfern’s SERP API,
rankcounts organic rows only;absolute_rankcounts every row, ads included.- Search costs 2 credits per provider results page and is capped by rate limits. Wayfern has no free tier.
ddgsfits small, low-volume jobs where you can own the maintenance.
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.

| Bucket | What it returns | Who maintains it | Fit |
|---|---|---|---|
| Instant Answer API | An abstract and related topics for an entity | DuckDuckGo | Looking up one named thing, not tracking rankings |
| Unofficial libraries (ddgs) | Web, image, video and news results | Open-source contributors | Low volume, and you own the fixes |
| Hosted SERP APIs (SerpApi, SearchAPI.io, Wayfern) | Parsed result rows as JSON | The vendor | Production volume and monitoring |
| AI chat proxies | Model answers, not search rows | Individual repo authors | Chat 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.
Region and language:
region,lang. DuckDuckGo uses kl-style codes, the format SerpApi’sklparameter takes. Wayfern carries the region inregionand the language inlang. Check the accepted value format in the API reference before you pass a kl code unchanged.Date range:
date. Wayfern takesYYYYMMDD..YYYYMMDD, for example20260101..20260131. Use Wayfern’s field names, not the parameter names in other vendors’ sample requests or responses.Operators:
text,site,filetype. SearchAPI.io’s DuckDuckGo docs say DuckDuckGo queries can include operators such assite:,intitle:andinurl:. In Wayfern, put those intext, which accepts up to 512 characters.siteandfiletypeare also separate fields, so you don’t have to build them into the string.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.
Pagination:
limit,start.limitruns from 1 to 200 per engine and defaults to 50.startis an offset, and each response returnspagination.next_startandhas_more.Loop on
has_moreinstead of assuming a fixed page size, since result counts and duplicates can vary between requests.filterhandles near-duplicates.Feature blocks:
features. Set it to get people-also-search blocks inserp_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.
- Create a token. Mint a search-scoped
wf_token and export it asWF_TOKEN. Tokens are shown once, so keep the value out of your code. - Send the request. Set
enginestoduckduckgo:
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}' - 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. - 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,
rankcounts organic rows only.absolute_rankcounts every row in page order, ads included. typeandadsay what kind of row it is.urlis the result, andenginenames the engine that returned it.pagination.next_startis thestartoffset for the next call.has_moresays whether another page exists.meta.engines_failednames 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.
- Read
meta.engines_failedfirst. If it namesduckduckgo, 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.” - Retry with backoff, or fall back. Wait 2 seconds, then 4, then 8. Or drop to the other engines in the same request.
- Page when rows are short. If rows came back but fewer than you expected, check
pagination.has_moreand request again withpagination.next_startasstart.
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") - 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.
- 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.
- 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.
Is it legal to collect DuckDuckGo search results?
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?
| Option | Fits when | What you own | Documented catch |
|---|---|---|---|
| Open-source ddgs | Small, low-volume jobs | Maintenance, retries, block detection | The name belongs to more than one project; check the last release |
| Single-engine vendor API (SerpApi, SearchAPI.io) | You need DuckDuckGo-specific blocks | Your integration; the vendor owns parsing | Covers one engine per integration |
| Wayfern Search API | One call should cover several engines | Your credit budget and your retry rules | No 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.