URL: /code/data/domains/benchmark · Id: `page:/code/data/domains/benchmark`

# Domain.benchmark

> Measure a domain beside its rivals, one row each: authority, estimated traffic, ranking terms, referring domains and monthly search ad budget.

`POST https://api.sb/{your-domain}/domains/benchmark`

Measure a domain beside its rivals, one row each: authority, estimated traffic, ranking terms, referring domains and monthly search ad budget.

- **Price:** 0.75¢ a domain
- **Success rate:** 100% of 12,396 calls
- **Freshness:** Fresh for 30 days
- **Emits:** `Domain.benchmarked`
- **Capability:** [Market data](https://startupbuilder.dev/systems/marketing/market-data)

```text title="Run it · Ask"
How does leaseline.app compare with rentrival.example on authority, traffic and links? Spend up to 5¢.
```

```ts title="Run it · SDK"
import { $ } from 'startup-builder'

const result = await $.try.Domain.benchmark({ hostname: 'leaseline.app', competitors: ['rentrival.example'], maxCost: 0.05 })
```

```json title="Run it · Response"
{
  "rows": [
    {
      "hostname": "leaseline.app",
      "authority": 4,
      "pageAuthority": 11,
      "spamScore": 1,
      "traffic": null,
      "keywords": 3,
      "referringDomains": 6,
      "backlinks": 14,
      "adBudget": 0,
      "locale": "en-US",
      "observedAt": "2026-10-27T14:02:11Z",
      "method": "estimated"
    },
    {
      "hostname": "rentrival.example",
      "authority": 41,
      "pageAuthority": 38,
      "spamScore": 2,
      "traffic": 18400,
      "keywords": 2210,
      "referringDomains": 612,
      "backlinks": 9830,
      "adBudget": 4200,
      "locale": "en-US",
      "observedAt": "2026-10-27T14:02:11Z",
      "method": "estimated"
    }
  ],
  "cost": {
    "usd": 0,
    "maxUsd": 0.015,
    "units": 2,
    "misses": 0
  }
}
```

## Options and prices
| You get | Input that selects it | Price | Success rate |
| --- | --- | --- | --- |
| Authority, page authority and spam score | `{"measures":["authority"]}` | About 0.3¢ a domain | 100% of 12,396 calls |
| Estimated traffic and ranking terms | `{"measures":["traffic","keywords"]}` | About 0.1¢ a domain | 99.2% of 25,412 calls |
| Referring domains and backlink totals | `{"measures":["links"]}` | About 0.25¢ a domain | 100% of 10,952 calls |
| Monthly search ad budget | `{"measures":["adBudget"]}` | About 0.1¢ a domain | 99.2% of 25,412 calls |

## Inputs
| Name | Type | Default | Meaning |
| --- | --- | --- | --- |
| `hostname` | [`Hostname`](/code/data/types#hostname) | Required | The domain to measure: yours or a rival’s. |
| `competitors` | [`Hostname[]`](/code/data/types#hostname) | `the top 3 from `Domain.findCompetitors`` | Up to 999 domains measured beside it, one row each. |
| `measures` | `('authority' \| 'traffic' \| 'keywords' \| 'links' \| 'adBudget')[]` | `all five` | What to measure. Each measure is its own job with its own price. |
| `locale` | `string` | `your home Market` | The market and language, such as `en-US`. |
| `maxAge` | `string` | `'30d'` | A stored reading younger than this returns at $0 instead of reading again. |
| `maxCost` | `number` | `0.50` | The most this call may spend, in USD. Over it, the call is refused before it spends, or stops early with what it has. |

## Outputs
| Field | Type | Unit | What `null` means |
| --- | --- | --- | --- |
| `rows` | `Domain[]` | None. | Never null: one row per hostname, `hostname` first. |
| `rows[].hostname` | [`Hostname`](/code/data/types#hostname) | None. | Never null. |
| `rows[].authority` | `number \| null` | 0 to 100, one scale across sources | Unknown: too new or too small to score. |
| `rows[].pageAuthority` | `number \| null` | 0 to 100, the home page | Unknown. |
| `rows[].spamScore` | `number \| null` | 0 to 100 | Unknown. |
| `rows[].traffic` | `number \| null` | organic visits a month, estimated | Too little search traffic to estimate. Never zero visits. |
| `rows[].keywords` | `number \| null` | terms ranking in the top 100 | Unknown. |
| `rows[].referringDomains` | `number \| null` | domains linking to it | Unknown. |
| `rows[].backlinks` | `number \| null` | links | Unknown. |
| `rows[].adBudget` | `number \| null` | USD a month on search ads, estimated | Unknown. `0` means no search ads were seen. |
| `rows[]` | [`Observed`](/code/data/types#observed) | None. | Each row also carries `observedAt`, `method` and `locale`. |
| `cost` | [`Cost`](/code/data/types#cost) | USD | Never null. In try mode `usd` is 0 and `maxUsd` is what the call would have cost. |

## Read the result
| Field | Value | What it means | What to do |
| --- | --- | --- | --- |
| `referringDomains` | Yours, against 10, 25 and 50 | The targets for week 4, week 12 and month 6. They raise your difficulty ceiling from about 10 to about 20, then about 35. | Read it weekly; under 10 at week 4, put the founder’s minutes into listings and the link gap, not new pages. (our planning number, tied to the referring-domain scale) |
| `referringDomains` | A rival’s, far above yours | The terms they rank for are mostly above your ceiling for now. | Target terms at or under your ceiling, and run `Domain.findLinks` with `gap` to find where their links came from. (the winnability rule in the search playbook) |
| `traffic` | `null` for your domain | Too little search traffic to estimate yet: unknown, not zero. | Read your own clicks from Search Console instead; it is free and exact. (the contract every data call keeps) |
| `adBudget` | Over $0 for a rival | They pay for search clicks, so some terms convert for them. | List the terms with `Keyword.find` in `rival-paid` mode, then weigh each against your break-even. (the paid search playbook) |
| `authority` | Moves you cannot explain | Authority is a model of links, recomputed monthly, and two sources disagree. | Steer by referring domains to your target pages; report authority, never chase it. (our planning number) |

## Effects
**Action class**

None: no approval rule names it, so it runs within its seat’s Permissions and Limits

**Modes**

- `try`: Runs the read and returns real rows; nothing is saved and nothing is billed.
- `send`: Returns a pending Action at once; its Event carries the rows when the read finishes.
- `do`: Waits for the read and returns the rows, billed per result.

**Idempotency**

The same `Idempotency-Key` with the same input replays the first answer at $0; with other input it returns 409.

**Saved or shared**

Records each competitor as an observed relationship, never as a Domain you hold. Readings are shared across startups for 30 days.

**Emits**

`Domain.benchmarked` with `{ rows, hostname, competitors }`

**Performed by**

[Analyst](https://startupbuilder.dev/agents/marketing/analyst)

**Price**

About 0.75¢ a domain. Free: a reading younger than `maxAge`. `maxCost` defaults to 50¢. Your domain and 3 rivals, every month for 6 months: 24 × 0.75¢ a domain is about 18¢.

**Reliability**

The first route succeeds 100% of 12,396 calls. If it fails, a second route answers at 100% of 1,948 calls, and you pay for one.

**Freshness**

A reading younger than 30 days returns at $0. Readings are shared across startups for the same subject and locale.

**Batch and pages**

Up to 1,000 domains a call. It answers in one response.

**Rate**

[The shared rate rules](/code/data#rate): 10 calls a second per key, and an array input counts as one call.

## Refuses when
This call has no refusals of its own. Every data call can also meet [the shared data-call refusals](/code/refusals#data-calls): [`filter-unsupported`](/code/refusals#filter-unsupported), [`input-missing`](/code/refusals#input-missing), [`limit-exceeded`](/code/refusals#limit-exceeded), [`max-cost`](/code/refusals#max-cost), [`rate-limited`](/code/refusals#rate-limited), [`sources-busy`](/code/refusals#sources-busy), [`venue-unsupported`](/code/refusals#venue-unsupported).

## When it waits
Returns in one response; nothing waits.

## Example

**Ask**

```text
How does leaseline.app compare with rentrival.example on authority,
traffic and links? Spend up to 5¢.
```

**API**

```bash
curl -X POST "https://api.sb/leaseline.app/domains/benchmark?mode=try" \
  -H "Authorization: Bearer $SB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"hostname":"leaseline.app","competitors":["rentrival.example"],"maxCost":0.05}'
```

The response is the one in the Run it window above.

**CLI**

```bash
npx startup-builder do Domain.benchmark --try --data '{"hostname":"leaseline.app","competitors":["rentrival.example"],"maxCost":0.05}'
```

**MCP**

```json
{
  "name": "do",
  "arguments": {
    "mode": "try",
    "code": "return await $.Domain.benchmark({ hostname: 'leaseline.app', competitors: ['rentrival.example'], maxCost: 0.05 })"
  }
}
```

**SDK**

```ts
import { $ } from 'startup-builder'

const result = await $.try.Domain.benchmark({
  hostname: 'leaseline.app',
  competitors: ['rentrival.example'],
  maxCost: 0.05,
})
```

To retry, send the same `Idempotency-Key`: the retry returns the first answer for $0. A new key reads again.

A `sk_test_` key answers these the same way every time, at $0 ([every test value](/code/data#test-values)).

| Test value | Always returns | What it is for |
| --- | --- | --- |
| `maxCost: 0.0001` | Refuses with [`max-cost`](/code/refusals#max-cost) | Any priced call with a maxCost of 0.0001 is refused before it spends: the price is above the cap. |
| `rate-limited.test` | Refuses with [`rate-limited`](/code/refusals#rate-limited) | Any call naming this hostname answers 429 with Retry-After, so your retry logic runs. |
| `sources-busy.test` | Refuses with [`sources-busy`](/code/refusals#sources-busy) | Any call naming this hostname answers 503 as if every route were busy, and nothing is spent. |

Watch it on a schedule: a Monitor runs this call and records an Event only when the reading changes.

```ts
await $.Monitor.create({
  verb: 'Domain.benchmark',
  input: { hostname: 'leaseline.app', measures: ['links'] },
  change: 'link-gained',
  every: '1w',
})
```

## Used by
- **Workflows:** [Competitor gap](/capabilities/size-up-competitors/competitor-gap) · [Directory submissions](/capabilities/earn-first-links/directory-submissions) · [Keyword opportunity map](/capabilities/research-demand/keyword-opportunity-map)
- **Agent tasks:** [Monthly search content](/capabilities/make-content/monthly-search-content)
- **Jobs:** [Earn first links](/capabilities/earn-first-links) · [Research demand](/capabilities/research-demand) · [Size up competitors](/capabilities/size-up-competitors)

## Related
[`Domain.findCompetitors`](/code/data/domains/find-competitors) · [`Domain.findLinks`](/code/data/domains/find-links) · [`Domain.verify`](/code/data/domains/verify)