Try it
Run a live DuckDuckGo SERP request
One real call against the API, no signup and no key — exactly what the endpoint returns, as a results page and as raw JSON.
Endpoints & Pricing
Four DuckDuckGo Endpoints, One API Key
Pricing is set by category, not by engine — DuckDuckGo web search costs the same $0.03 per 1,000 SERP API calls at Scale as every other engine in the catalog. What you choose DuckDuckGo for is the data, not a discount.
Web SERP
- Ranked organic list with snippets
numup to 100,pages1–10- Publish dates on many organic rows
- Instant Answer box where shown
- Freshness d/w/m/y & SafeSearch
News
- ~25–30 results on a bare call
numup to 50 results per request- Publisher name, not a hostname
- ISO-8601
publishedTime - Excerpt + lead image URL
Images
- Up to ~95 images per request
- Full-size and thumbnail URLs
- Pixel width & height per row
- Source page URL, not just the file
- License, size, type, color, layout
Videos
- Title, duration and description
- Thumbnail plus
embedUrl - Publisher channel, not the platform
- View count where the source has one
duration&resolutionfilters
All four endpoints draw on the same allowance of free API calls, and every price above is the public rate for its category. Your tier is set by your account, not by the engine you send.
Pixel Position & Geometry on every DuckDuckGo SERP element
Add pixel_position=true to any DuckDuckGo Deep Search (/api/search) call and every item the response carries — organic results and the text ads above them — comes back with both an integer pixel_position (y-coordinate) and a full pixel_box with x, y, width and height, measured on a 1366×768 desktop viewport. DuckDuckGo’s result page is unusually flat, so the y-values are close together and above-the-fold cut-offs land differently than they do on a feature-heavy SERP — which is exactly what makes them worth measuring. Same per-call price, opt-in flag. Paid tiers only; values describe a standard desktop rendering, and an item deep in the response can come back null — branch on the field's presence and fall back to position.
{
"organic": [
{ "position": 1, "pixel_position": 144, "pixel_box": { "x": 8, "y": 144, "w": 1350, "h": 86 } },
{ "position": 2, "pixel_position": 249, "pixel_box": { "x": 8, "y": 249, "w": 1350, "h": 104 } },
{ "position": 3, "pixel_position": 372, "pixel_box": { "x": 8, "y": 372, "w": 1350, "h": 86 } }
]
}
Quick Start
DuckDuckGo Results in One Request
Set engine=ddg and send your key. The same two endpoints serve every engine, so switching a keyword set from Google to DuckDuckGo is a one-word change.
# German results, last 7 days, two pages of organic rows curl "https://apiserpent.com/api/search?q=passwort+manager+test&engine=ddg&country=de&language=de&num=20&freshness=w" \ -H "x-api-key: YOUR_API_KEY"
{
"success": true,
"query": "passwort manager test",
"type": "web",
"engine": "ddg",
"country": "de",
"pagesRequested": 2,
"pagesScraped": 2,
"results": {
"organic": [
{
"position": 1,
"title": "Passwort-Manager im Test 2026",
"url": "https://example.de/passwort-manager-test",
"snippet": "Wir haben 14 Passwort-Manager geprüft…",
"displayedUrl": "example.de"
}
],
"richSnippets": [
{ "position": 1, "publishDate": "2026-08-14", "breadcrumb": null, "rating": null }
],
"featuredSnippet": null,
"knowledgePanel": null,
"aiOverview": null,
"peopleAlsoAsk": [],
"relatedSearches": [],
"ads": { "top": [], "bottom": [], "totalCount": 0 },
"localPack": [],
"videos": [],
"shopping": []
},
"meta": {
"totalOrganic": 20,
"elapsed": "3184ms"
}
}
Read the empties, they are a feature. On format=full the results object carries the same eleven keys on every single call. A block DuckDuckGo did not put on the page arrives as null or [] — never as a missing key — so your parser never branches on the engine and adding a second engine later cannot break your schema. On engine=ddg, aiOverview is always null and relatedSearches is always []; ads come through where the page carries them.
# Quick Search returns organic rows only — the shape you want for rank tracking. # format=simple flattens `results` to [{position, title, url}]. import requests API = "https://apiserpent.com/api/search/quick" KEY = "YOUR_API_KEY" def rank_of(domain, keyword, country="us"): r = requests.get( API, params={"q": keyword, "engine": "ddg", "country": country, "num": 20, "format": "simple"}, headers={"x-api-key": KEY}, timeout=60, ) r.raise_for_status() for row in r.json().get("results", []): if domain in row["url"]: return row["position"] return None print(rank_of("example.com", "encrypted email providers"))
Swap "ddg" for "google", "bing", "yahoo" or "brave" and the same function tracks the same keyword on another engine. num is a ceiling, not a guaranteed count — check len(results) rather than assuming it.
Data Fields
What a DuckDuckGo Response Actually Contains
Field names are shared across every engine, so the parser you write here works everywhere else in the catalog. These are the ones DuckDuckGo populates.
Web Search Fields
- organic[].position
- organic[].title
- organic[].url
- organic[].snippet
- organic[].displayedUrl
- richSnippets[].publishDate
- featuredSnippet.text · .sourceUrl
- knowledgePanel.title · .description
- ads.top[] · ads.totalCount
News Search Fields
- articles[].position
- articles[].title
- articles[].url
- articles[].source
- articles[].publishedTime
- articles[].snippet
- articles[].image
- totalResults
- meta.elapsed
Image & Video Fields
- images[].thumbnail · .original
- images[].width · .height
- images[].source · .pageUrl
- videos[].duration
- videos[].thumbnail
- videos[].embedUrl
- videos[].publisher
- videos[].views
- videos[].publishedTime
Request Parameters
- q (search query)
- engine=ddg
- country (112 codes)
- language (2-letter ISO)
- num (≤100) · pages (1–10)
- freshness (d, w, m, y)
- safe (off, moderate, strict)
- format (full, simple)
- pixel_position · include_video_stats
Why DuckDuckGo SERP data
What is DuckDuckGo SERP data, and why teams use it
DuckDuckGo does not keep a profile of the person searching, so the ranking you record is a property of the query rather than of whoever ran it.
No personalization layer to subtract
DuckDuckGo does not tailor results around search history or a logged-in profile. Run the same keyword twice from two machines and you are far more likely to record the same ranking than you are on an engine that personalizes — which means less run-to-run noise to average away, and a position you can defend to a client.
An Instant Answer you never special-case
DuckDuckGo answers definitional and entity queries with a zero-click box above the list. It arrives in the standard featuredSnippet and knowledgePanel fields with its source link attached, so the code that reads answer boxes on other engines reads this one too. No DuckDuckGo-shaped branch in your parser.
Publish dates on a large share of rows
DuckDuckGo prints a date beside a lot of its organic results, and it comes back as richSnippets[].publishDate normalized to YYYY-MM-DD. That is content-freshness auditing for a whole keyword set without fetching a single one of the pages you are auditing.
The same eleven keys on every call
The results object never changes shape between engines, between queries, or between a page that carried an answer box and one that did not. A block that is not there is null or [], never absent, so a schema you write for one engine survives the day you add a second.
Going deeper: DuckDuckGo vs Google SERP data compares the two result sets field by field, and the DuckDuckGo Search API guide walks the whole response.
Regions & language
Country targeting on DuckDuckGo, honestly
DuckDuckGo does not take country and language as two independent settings — it takes one region token that bundles both, and it defines it for some of the 112 codes and not others.
| What DuckDuckGo defines | Codes | Examples | What you get |
|---|---|---|---|
| A region of its own for that country | 56 | de jp br in mx |
Country-level results in the locale DuckDuckGo defines for it |
| Its Arabia region | 16 | ae sa eg ma |
Arabic-language regional results, not one country |
| Its Latin America region | 12 | cr pa ec do |
Spanish-language regional results, not one country |
| No region for that country | 28 | ng ke lk is |
International results — never a substituted country |
Why this matters more than the headline number. A region code DuckDuckGo does not define is discarded rather than approximated, so an API that invents one for you is quietly returning results for nowhere in particular. Where DuckDuckGo has no region for a country, what comes back is international results you can recognize as such — never a different country wearing the label you asked for. The four buckets and their names come from DuckDuckGo’s own published region list (wt-wt, xa-ar, xl-es); DuckDuckGo search parameters, checked 7 September 2026.
Language is part of the same token. language therefore moves the DuckDuckGo region only where DuckDuckGo defines a second locale for that country — Canada (en, fr), Switzerland (de, fr, it), Belgium (nl, fr) and Spain (es, ca). Everywhere else the country is the parameter that actually moves the results, so that is the one we honor.
Cost Calculator
See How Much You Save
From $0.03/1K SERP API calls at Scale, high-volume collection stays cheap enough to run daily instead of monthly. Here is what DuckDuckGo web searches cost at Scale pricing.
$1.96 per 1,000 is the lowest rate on SerpApi’s published pricing page (its highest-volume Cloud plan, $106,050 for 54M searches); every smaller plan of theirs costs more per search. Verified on serpapi.com/pricing, 7 September 2026 — re-check before quoting it, competitor pricing moves.
Ideal For
Who Buys DuckDuckGo Results, and Why
Six jobs where DuckDuckGo is the right engine to send, not just the cheap one.
Rank tracking that does not drift
Because there is no profile shaping the page, a position you record today is comparable with the one you recorded last week. That kills a whole class of false movement in a rank tracker, and it is why DuckDuckGo often sits beside Google in the same daily crawl rather than instead of it.
Privacy-audience SEO
If you sell a VPN, a password manager, an encrypted mailbox, a browser or a security tool, a meaningful slice of your buyers search here and nowhere else. Tracking only Google means you are blind on the engine your own audience self-selected into. This is the one engine where that is the whole argument.
Bulk keyword research
At $0.03 per 1,000 SERP API calls on Scale, a 50,000-keyword sweep costs $1.50 and a million-keyword corpus costs $30. That changes the question from “which keywords can we afford to check” to “how often do we want to check all of them”.
Image datasets with a license filter
Up to ~95 images per request, each with full-size URL, pixel dimensions and the page it sits on — plus license filters covering the public-domain, share and modify-commercially buckets. At ~95 per call that is roughly 11 calls per thousand images, and a provenance URL on every row.
Content freshness auditing
A large share of DuckDuckGo organic rows carry a publish date, delivered as richSnippets[].publishDate. Pull a keyword set and you can see how old the ranking pages are before you commission anything — no crawling, no date-parsing every competitor’s template.
Research and IR corpora
Studies of search behavior and information retrieval need a result set that is not conditioned on a user profile, and they need it reproducible months later. Unpersonalized results plus a documented, stable JSON contract is exactly that. Start on the free calls and scale from there.
FAQ
DuckDuckGo API Questions
engine=ddg to /api/search or /api/search/quick and you get the ranked organic list as structured JSON.
num up to 100 and pages from 1 to 10, and num is a ceiling rather than a promised count — read the length of the array you get back. News accepts num up to 50; a bare call returns roughly 25 to 30 articles. Image search returns up to about 95 images in a single request, so a large dataset needs roughly 11 calls per thousand images. Video search returns a page of video rows per call.
language parameter changes the region only where DuckDuckGo defines a second locale for that country: Canada (en, fr), Switzerland (de, fr, it), Belgium (nl, fr) and Spain (es, ca).
freshness of d, w, m or y for the past day, week, month or year. Web accepts safe=off, moderate or strict. Image search adds size, type, color, aspect, layout, time and license filters, including the Creative Commons license buckets. Video search adds duration and resolution. If guaranteed adult-content removal is a hard requirement, DuckDuckGo’s own filter is lighter than Brave’s or Yahoo’s, so verify it against your own queries before you depend on it.
engine=ddg the aiOverview field is always null and relatedSearches is always an empty array; include_aio is accepted on google, yahoo and brave only. Ads come through where the page carries them. Both keys are still present on every response: the results object holds the same eleven keys on every call, so a block that is not there arrives as null or [] and your parser never has to branch.
delivery block rather than leaving you to notice. One exception to the refund rule: a 404 for a resource that does not exist is an answer, so that call is charged.
Start from $0.03 per 1,000 Searches
DuckDuckGo’s ranked results as JSON, on the same key and the same contract as four other engines. New accounts include free API calls, usable on any endpoint. No credit card required to start.
Try for Free

