DuckDuckGo Search Scraper - A tool to retrieve DuckDuckGo search results with a simple API. Get organic results, ads, related searches, knowledge graph information, and AI Search Assist answers when available.
Get results as structured JSON for applications or Markdown for LLMs and AI agents, without managing HTML parsing or proxies.
Using a simple GET request, you can retrieve DuckDuckGo search results:
https://serpapi.com/search?engine=duckduckgo&q=coffee&kl=us-en&api_key=YOUR_SERPAPI_API_KEY
- Register at SerpApi to get your API Key. Keep your key private.
q: the search query, limited to 500 characters. Supports operators such assite:,inurl:, andintitle:.kl(optional): the region, such asus-enfor the United States. This is not Bing'smktor Google'sglparameter.
JSON is the default output and is useful when you need individual result fields. Add output=md to receive Markdown for text-based workflows, LLMs, and AI agents.
curl --get https://serpapi.com/search \
--data-urlencode engine="duckduckgo" \
--data-urlencode q="coffee" \
--data-urlencode kl="us-en" \
--data-urlencode output="md" \
--data-urlencode api_key="YOUR_SERPAPI_API_KEY"Markdown is returned as text, not a JSON object. Use a text response reader instead of a JSON parser. The JSON field names below do not define a guaranteed Markdown structure.
curl --get https://serpapi.com/search \
--data-urlencode engine="duckduckgo" \
--data-urlencode q="coffee" \
--data-urlencode kl="us-en" \
--data-urlencode output="json" \
--data-urlencode api_key="YOUR_SERPAPI_API_KEY"Create a main.py file and install requests:
pip install requestsAdd this code to your file:
import requests
SERPAPI_API_KEY = "YOUR_SERPAPI_API_KEY"
params = {
"api_key": SERPAPI_API_KEY,
"engine": "duckduckgo",
"q": "coffee",
"kl": "us-en",
"output": "json"
}
search = requests.get("https://serpapi.com/search", params=params, timeout=60)
search.raise_for_status()
response = search.json()
if "error" in response:
raise RuntimeError(response["error"])
print(response)When organic results are present, they are available in response["organic_results"].
To request Markdown instead, keep the parameter definitions above and replace the request and response-handling lines with:
params["output"] = "md"
search = requests.get("https://serpapi.com/search", params=params, timeout=60)
search.raise_for_status()
print(search.text)Create an index.js file and install the SerpApi JavaScript package:
npm install serpapiAdd this code to your file for JSON results:
const { getJson } = require("serpapi");
const API_KEY = "YOUR_SERPAPI_API_KEY";
getJson({
api_key: API_KEY,
engine: "duckduckgo",
q: "coffee",
kl: "us-en"
}, (json) => {
if (json.error) {
throw new Error(json.error);
}
console.log(json);
});For Markdown, use a text-capable HTTP client rather than getJson. This standalone alternative uses built-in fetch in Node.js 18 or later:
async function main() {
const params = new URLSearchParams({
api_key: "YOUR_SERPAPI_API_KEY",
engine: "duckduckgo",
q: "coffee",
kl: "us-en",
output: "md"
});
const response = await fetch(`https://serpapi.com/search?${params}`, {
signal: AbortSignal.timeout(60000)
});
const text = await response.text();
if (!response.ok) {
throw new Error(`SerpApi HTTP ${response.status}: ${text}`);
}
console.log(text);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});Use a simple GET request from any programming language, or explore the ready-to-use libraries in SerpApi Integrations.
| Name | Description | Requirement |
|---|---|---|
| engine | Must be set to duckduckgo. |
Required |
| api_key | Your SerpApi private API key. | Required |
| q | Search query, up to 500 characters. | Required |
| Localization and Filters | ||
| kl | Region code, such as us-en, uk-en, or fr-fr. See the supported regions. |
Optional |
| safe | 1 - Strict, -1 - Moderate (default), -2 - Off. |
Optional |
| df | Date filter: d - Past day, w - Past week, m - Past month, y - Past year, or a custom YYYY-MM-DD..YYYY-MM-DD range. |
Optional |
| search_assist | Set to true to request an AI Search Assist answer when available. Defaults to false. Cannot be combined with m. |
Optional |
| Pagination | ||
| start | Result offset. The initial request (omitted or 0) can return up to 35 organic results; a positive offset can return up to 50. Counts vary and duplicates are possible. |
Optional |
| m | Maximum requested result count, from 1 to 50 (default 50). The initial page still returns at most 35. Cannot be combined with search_assist. |
Optional |
| SerpApi Parameters | ||
| no_cache | Set to true for fresh results instead of the one-hour cache. Cannot be combined with async. |
Optional |
| async | Set to true for later retrieval through the Searches Archive API. Cannot be combined with no_cache or used with Ludicrous Speed enabled. |
Optional |
| output | json (default) for structured results, md for Markdown, or html for raw HTML. |
Optional |
Visit the official documentation for all available parameters.
When available, use the response's serpapi_pagination.next URL with your API key for the next request. Alternatively, start controls the result offset. Do not assume that m=50 guarantees 50 results or that every page has the same size.
DuckDuckGo can return duplicate results, especially with larger offsets and result counts. Deduplicate by result URL, stop when no next-page link is available, and set a page or result limit rather than paginating indefinitely.
Add search_assist=true to request DuckDuckGo's AI-generated answer and sources when available. Omit m when using this option. The answer appears in the search_assist object in JSON results; it is not guaranteed for every query.
This option is independent of output format: search_assist requests an additional search feature, while output=md controls how the response is formatted.
The fields returned depend on the query and available source data. The following is a field guide, not a literal API response:
{
"organic_results": [
{
"position": "Integer - Position of the result",
"title": "String - Page title",
"link": "String - Destination URL",
"snippet": "String - Result excerpt",
"favicon": "String - Site icon URL"
}
],
"related_searches": [
{
"query": "String - Related search query",
"link": "String - DuckDuckGo search URL"
}
],
"search_assist": {
"answer": "String - AI-generated answer, when requested and available",
"expanded_answer": "String - Expanded answer",
"sources": [
{
"link": "String - Source URL",
"site": "String - Source website",
"text": "String - Source title"
}
]
},
"serpapi_pagination": {
"next": "String - SerpApi URL for the next page, when available"
}
}Other sections may include ads, knowledge_graph, news_results, inline_images, and search_information. Do not assume every response includes every section or that every entry has every field.
For Markdown output, use output=md and read the response as text as shown above.
- Track keyword rankings and compare search visibility across engines.
- Collect source links and snippets for research applications.
- Monitor brand mentions and competing websites.
- Analyze related searches for content planning.
- Retrieve available entity information from knowledge graphs.
- Compare AI Search Assist answers and their cited sources.
Feel free to reach out via contact@serpapi.com.
