DuckDuckGo SERP Rank Checker API — Position for a Domain
Documentation menu
FetchLayer FetchLayer API

Check where a site ranks for a query

Find where a domain or URL ranks in DuckDuckGo’s organic results for a query — built for SEO rank tracking. Send a query and a target and get back whether it was found, its best (lowest) position, and every match with its position, URL, title and result page, scanning up to depth positions (1–200, default 100). A domain target (example.com, or https://www.example.com/) matches that site and, by default, its subdomains; matching is on whole hostname labels, so notexample.com and example.com.evil.net never match, and www. is ignored on both sides. A URL with a path (example.com/blog) matches pages on that host under that path: /blog, /blog/ and /blog/post, but not /blogging. Positions are counted exactly as search counts them — organic results only, ads never take a position, a repeated URL once. The scan stops after the first result page containing a match, so several matches on that page are all reported; set allMatches to scan the full depth. found: false always means the whole depth was examined, or every result DuckDuckGo lists when that is fewer (a note says so); if DuckDuckGo cannot be read part-way through, the response is a retryable 503, never a "not found". Rankings differ by the searcher’s country: results reflect a US searcher (us-en) unless you set region, and positions shift over time. DuckDuckGo lists at most about 190–200 results for a query, so a deeper check ends with endOfResults true. A deep check can take 30 seconds or more. Billing: A rank check costs 1 credit regardless of depth: scanning 200 positions across 10 or more result pages is billed as one request. serpPagesFetched reports how many result pages were read and is never billed.

POST /rank-check Web search
https://api.fetchlayer.dev/duckduckgo/rank-check
OpenAPI JSON

Headers

Authorization string required

Bearer token — your FetchLayer API key.

Parameters

query string required

The search query, as a searcher would type it (1–500 characters).

target string required

What to look for: a domain such as example.com (matches the site and its subdomains), or a URL with a path such as example.com/blog (matches pages under that path).

depth number optional

Organic positions to scan, e.g. 10, 20, 50 or 100 (1–200), or -1 for the maximum. One request at any depth. (default: 100)

allMatches boolean optional

Scan the full depth and report every matching position, instead of stopping after the first result page with a match. (default: false)

includeSubdomains boolean optional

For a domain target, whether subdomains such as blog.example.com count as the site. (default: true)

region string optional

Region code: us-en, uk-en, de-de, fr-fr, es-es, it-it, jp-jp, in-en, au-en, ca-en, br-pt and 52 more (64 codes, DuckDuckGo’s own list), or wt-wt for no region. Results and rankings differ by region. (default: us-en)

safeSearch string optional

DuckDuckGo’s own filter level: strict, moderate or off. DuckDuckGo still returns a site for a query that names it outright. (default: moderate)

timeRange string optional

any, day, week, month or year: only results published within it. (default: any)

format string optional

json or markdown. (default: json)

timeoutMs number optional

Time limit for each page read, in milliseconds (1000–120000).

Response Fields

rank-check

Check where a site ranks for a query

resultType string

search, rank-check, instant-answer, suggestions, news, videos or images.

requestedUrl string

The DuckDuckGo page this result corresponds to.

notes string[]

Caveats about this particular result — a list that may be incomplete, a depth DuckDuckGo could not reach, a later page that could not be read. Empty when there are none. Read it on every call.

transport string

The source this data came from. Always "duckduckgo".

scrapedAt string

ISO 8601 timestamp of when the data was collected.

query string

The query that was run.

region string

The region the results are for.

safeSearch string

The safe search level applied.

timeRange string

The time range applied.

target object

The target as understood: input, type (domain or url_prefix), value (the hostname, or host and path, that was matched) and includeSubdomains.

found boolean

Whether the target appeared within the scanned depth.

position number

Its best (lowest) organic position, or null.

matches object[]

Every match found: position, url, title and page.

depth number

The depth you asked for.

depthScanned number

Organic positions actually examined.

serpPagesFetched number

Result pages read. Informational only — never billed.

endOfResults boolean

DuckDuckGo ran out of results before the requested depth.

pagesScraped number

Always 1: a rank check counts as one request against your plan, however deep it scans.

Request

curl -X POST "https://api.fetchlayer.dev/duckduckgo/rank-check" \
  -H "Authorization: Bearer ss-your-key" \
  -H "Content-Type: application/json" \
  -d '{"query":"reddit api","target":"fetchlayer.dev","depth":200}'

Response

{
  "resultType": "rank-check",
  "requestedUrl": "https://duckduckgo.com/?q=reddit+api&kl=us-en&kp=-1",
  "scrapedAt": "2026-09-15T19:53:58.766Z",
  "transport": "duckduckgo",
  "notes": [
    "Stopped after the first page containing the target; set allMatches to scan the full depth."
  ],
  "query": "reddit api",
  "region": "us-en",
  "safeSearch": "moderate",
  "timeRange": "any",
  "target": {
    "input": "fetchlayer.dev",
    "type": "domain",
    "value": "fetchlayer.dev",
    "includeSubdomains": true
  },
  "found": true,
  "position": 129,
  "matches": [
    {
      "position": 129,
      "url": "https://fetchlayer.dev/blog/reddit-api-closed-2026",
      "title": "Reddit API Shut Down in 2026: What Still Works | FetchLayer",
      "page": 10
    },
    {
      "position": 131,
      "url": "https://fetchlayer.dev/reddit-scraper",
      "title": "Reddit Scraper API & MCP for AI Agents | FetchLayer",
      "page": 10
    }
  ],
  "depth": 200,
  "depthScanned": 139,
  "serpPagesFetched": 10,
  "endOfResults": false,
  "pagesScraped": 1
}