URL: /docs/guides/evaluating-a-domain

---
title: Evaluate a domain
description: Read a listing properly — banded metrics, missing data, marquee linkers, and the availability stamp that is not a check.
---

A page of listings gives you rows. Turning rows into a judgement means handling three things the API is deliberate about: the metrics are bands, a missing metric is not a zero, and the availability timestamp is not a live check.

## Read the whole row

```bash
curl -s https://getrevised.com/api/v1/domains/LxRrd32h \
  -H "Authorization: Bearer $REVISED_KEY"
```

```json Example response
{
  "id": "LxRrd32h",
  "status": "active",
  "domain": "septictankcleaningsydney.com.au",
  "tier": "open",
  "name_disclosed": true,
  "tld": "com.au",
  "category": "other",
  "referring_domains": "100-250",
  "backlinks": "100-500",
  "domain_authority": "10-19",
  "revised_score": { "low": 85, "high": 95 },
  "agent_citability": null,
  "spam": "low",
  "age_years": 4,
  "snapshots": "<10",
  "linked_by": ["FCC"],
  "metrics_missing": ["agent_citability"],
  "hold_state": "none",
  "estimated_value_cents": 100,
  "availability_checked_at": "2026-09-19T21:04:06.589Z",
  "updated_at": "2026-09-19T21:04:06.589Z"
}
```

| Field | What it tells you |
| --- | --- |
| `referring_domains` | How many **distinct** sites link here. The most durable signal on the row — far harder to manufacture than raw backlink count. |
| `backlinks` | Total links. A large number over a small referring-domain count usually means one site linking many times. |
| `domain_authority` | An aggregate of the link graph, 0–100. Correlates with referring domains, but not perfectly. |
| `revised_score` | Revised's own published range. `rsMin` filters its lower bound. |
| `agent_citability` | How often the domain is cited by the sources AI answer engines draw on. A different question from link authority. [Methodology](https://getrevised.com/agent-citability). |
| `spam` | `low` or `moderate`. Filters the obvious cases, not all of them. |
| `snapshots` | How much of the site the public archive holds — a proxy for whether it was a real site rather than a parked shell. |
| `linked_by` | Named, recognisable domains that link here. Read this column. |
| `age_years` | Age in whole years, where known. |
| `metrics_missing` | Which of the optional metrics on this row are `null`. |

## The metrics are bands

`referring_domains` is `"100-250"`, not `137`. `domain_authority` is `"10-19"`. `revised_score` is a `{low, high}` range.

That is deliberate: a point estimate implies a precision the underlying link data does not have. A domain measured at 137 referring domains today might measure 119 next week with nothing about the domain having changed, and sorting on a fake third significant figure produces a fake ranking.

So flatten bands to a midpoint **for sorting**, keep the band string **for display**, and never show a midpoint to a reader as if it were a measurement. Four shapes to handle: `"10-50"`, `"<100"`, `"250+"` and `"1K-5K"`.

```python
_SUFFIX = {"K": 1_000, "M": 1_000_000}


def _num(token):
    """'1K' -> 1000.0, '250' -> 250.0"""
    token = token.strip().upper()
    if token and token[-1] in _SUFFIX:
        return float(token[:-1]) * _SUFFIX[token[-1]]
    return float(token)


def band_midpoint(band):
    """Flatten a published band to a single sortable number.

    '10-50' -> 30.0      midpoint
    '<100'  -> 50.0      half the ceiling
    '250+'  -> 375.0     the floor plus 50%, arbitrary but consistent
    None    -> None      genuinely unknown; not zero
    """
    if band is None or band == "":
        return None
    band = str(band).strip()
    if band.startswith("<"):
        return _num(band[1:]) / 2
    if band.endswith("+"):
        return _num(band[:-1]) * 1.5
    if "-" in band:
        low, high = band.split("-", 1)
        return (_num(low) + _num(high)) / 2
    return _num(band)


for probe in ["10-50", "<100", "250+", "1K-5K", "0-9", None]:
    print(f"{str(probe):>8} -> {band_midpoint(probe)}")
```

```text Output
   10-50 -> 30.0
    <100 -> 50.0
    250+ -> 375.0
   1K-5K -> 3000.0
     0-9 -> 4.5
    None -> None
```

## Missing is not zero

`agent_citability: null` means the domain has no row in the current index — **not** a score of zero. The same goes for `domain_authority`, `backlinks`, `age_years` and `category`. Every row carries `metrics_missing` naming exactly which of its optional metrics are absent, so you never have to guess whether a blank means "we looked and found nothing" or "we have not looked".

Filling a missing metric with `0` silently pushes those rows to the bottom of your ranking. That is a judgement, and not one you meant to make.

The honest alternative: drop the missing component and re-normalise the remaining weights.

```python
import math

WEIGHTS = {"rd_mid": 0.35, "da_mid": 0.25, "citability": 0.25, "snap_mid": 0.15}

# Ceilings past which more stops meaning better, for the log-scaled components.
CEILINGS = {"rd_mid": 500.0, "snap_mid": 200.0}


def _component(column, value):
    if value is None:
        return None
    if column in CEILINGS:
        # log1p so 0 maps to 0, then clamp at the ceiling.
        return min(math.log1p(value) / math.log1p(CEILINGS[column]), 1.0)
    return min(max(value / 100.0, 0.0), 1.0)  # DA and citability are already 0-100


def rank_score(row):
    """Weighted 0-100 score. Missing components are dropped, not zeroed."""
    total, used = 0.0, 0.0
    for column, weight in WEIGHTS.items():
        value = _component(column, row.get(column))
        if value is not None:
            total += value * weight
            used += weight
    if used == 0:
        return None
    return round(100 * total / used, 1)


def components_used(row):
    """How many of the four components this score is actually built on."""
    return sum(_component(c, row.get(c)) is not None for c in WEIGHTS)


candidate = {"rd_mid": 175.0, "da_mid": 15.0, "citability": None, "snap_mid": 5.0}
print(rank_score(candidate), "from", components_used(candidate), "of", len(WEIGHTS), "components")
```

```text Output
50.6 from 3 of 4 components
```

Two rules the weights do not express, and both matter:

- **Log-scaling on the count-like components.** The gap between 10 and 100 referring domains matters much more than the gap between 1,000 and 1,090.
- **Report how many components were used.** A row scored on two of four is a weaker claim than one scored on all four, even when the number is higher. Re-normalising keeps the arithmetic honest; it cannot invent the missing evidence.

Weights are a judgement call, not a fact. Keep them where whoever reads the ranking can argue with them.

## Scan `linked_by` before you trust the score

`linked_by` names recognisable domains that link to this one. A listing with a **small** referring-domain count and a university, a government body or Wikipedia in `linked_by` is often more interesting than one with hundreds of forgettable links — and no single aggregate captures that. It is the column most worth reading with your own eyes.

## Availability is a stamp, not a check

<Warning>
  `availability_checked_at` records when Revised **last checked** that the name is unregistered. Revealing a name in the web directory re-checks it on the spot; this API and its exports carry the last-checked timestamp instead. A row can report a name as available when somebody registered it an hour ago. **Confirm at a registrar before you act.**
</Warning>

Measure the age of the stamp and act on it:

```python
from datetime import datetime, timezone

checked = datetime.fromisoformat(row["availability_checked_at"].replace("Z", "+00:00"))
age_hours = (datetime.now(timezone.utc) - checked).total_seconds() / 3600

if age_hours > 48:
    print(f"{row['id']}: availability last checked {age_hours:.0f}h ago — re-check before acting")
```

```text Output
LxRrd32h: availability last checked 62h ago — re-check before acting
```

`checkedDays` filters the directory on stamp freshness, so you can ask for only recently-checked rows at the source.

## Before you register anything

<Steps>
  <Step title="Read the archive">
    Pull up what the site actually was. A high referring-domain count on a domain whose archived pages are pharmacy spam is a liability, not an asset — `spam: "low"` filters the obvious cases, not all of them.
  </Step>
  <Step title="Confirm the links still exist">
    A link recorded in a crawl is not necessarily a link on the live page today.
  </Step>
  <Step title="Confirm availability at a registrar">
    The stamp is not a check, and a Revised hold reserves the listing here and nothing else.
  </Step>
  <Step title="Have a plan for the content">
    Inheriting links to a site about Queensland fishing and pointing them at something unrelated wastes most of what you just picked up.
  </Step>
</Steps>

## Next

<CardGroup cols={2}>
  <Card title="Reveals and holds" icon="lock" href="/docs/guides/revealing-and-holds">
    Reserve a listing while you do the checks above.
  </Card>
  <Card title="Python walkthrough" icon="code" href="/docs/examples/python-walkthrough">
    The same parser and ranking, end to end, in a runnable notebook.
  </Card>
</CardGroup>
