> ## Documentation index
> Fetch the complete documentation index at: https://rankfield.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Read the results

> Read what an audit found: the main problems, every issue with its pages, page and link records, the folder tree, the crawl log and earlier audits.

`GET https://rankfield.dev/v1/site-audit/{id}/summary`

```bash cURL
curl 'https://rankfield.dev/v1/site-audit/169c615ff6c5057c8ca5384a6e2df47a/summary' \
  -H 'Authorization: Bearer YOUR_API_KEY'
```

```python Python
import requests

response = requests.get(
    "https://rankfield.dev/v1/site-audit/169c615ff6c5057c8ca5384a6e2df47a/summary",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
)
print(response.json())
```

```javascript JavaScript
const response = await fetch("https://rankfield.dev/v1/site-audit/169c615ff6c5057c8ca5384a6e2df47a/summary", {
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
  },
});
console.log(await response.json());
```

```json 200
{
  "id": "169c615ff6c5057c8ca5384a6e2df47a",
  "domain": "https://rankfield.dev",
  "status": "done",
  "health": {
    "score": 100,
    "urlsWithErrors": 0,
    "urlsWithoutErrors": 202,
    "internalUrls": 202,
    "note": "The share of crawled internal URLs with no error-level issue; site-wide findings are not counted per URL."
  },
  "inventory": {
    "internal": 202,
    "htmlPages": 103,
    "indexable": 103,
    "documents": 96,
    "redirects": 0,
    "errors": 0,
    "resources": 3,
    "disallowed": 0,
    "notFetched": 0,
    "known": 199,
    "sitemapUrls": 99,
    "externalChecked": 0,
    "externalBroken": 0,
    "externalUnchecked": {
      "total": 0,
      "excluded": 0,
      "robotsDisallowed": 0,
      "botBlocked": 0
    },
    "byStatus": {
      "2xx": 202,
      "3xx": 0,
      "4xx": 0,
      "5xx": 0,
      "failed": 0
    }
  },
  "notes": [],
  "headline": "Health 100 of 100: 202 of 202 crawled URLs have no errors. 103 HTML pages, 96 other documents; 0 kinds of error, 22 issue types in all.",
  "top": [
    {
      "issue": "schema-none",
      "name": "No structured data",
      "group": "ai",
      "severity": "notice",
      "site": false,
      "urls": 103,
      "of": {
        "set": "indexable",
        "urls": 103,
        "label": "indexable pages"
      },
      "share": 100.0,
      "text": "No structured data: 103 of 103 indexable pages. The indexable page has no structured data. Add JSON-LD for the page's type (Article, Product, Organization, BreadcrumbList…).",
      "example": "https://rankfield.dev/"
    },
    {
      "issue": "no-hsts",
      "name": "HSTS missing",
      "group": "other",
      "severity": "notice",
      "site": false,
      "urls": 103,
      "of": {
        "set": "htmlPages",
        "urls": 103,
        "label": "HTML pages"
      },
      "share": 100.0,
      "text": "HSTS missing: 103 of 103 HTML pages. The HTTPS page sends no Strict-Transport-Security header. Send HSTS (max-age of at least six months) once the whole site is HTTPS.",
      "example": "https://rankfield.dev/"
    },
    {
      "issue": "no-preferred-image",
      "name": "No preferred image",
      "group": "social",
      "severity": "notice",
      "site": false,
      "urls": 103,
      "of": {
        "set": "htmlPages",
        "urls": 103,
        "label": "HTML pages"
      },
      "share": 100.0,
      "text": "No preferred image: 103 of 103 HTML pages. The page names no preferred image (og:image, or an image in its structured data). Name the page's main image, so search and AI results can show it.",
      "example": "https://rankfield.dev/"
    },
    "…"
  ]
}
```

Start with the summary: its `notes` say how complete the audit is (why the crawl stopped early, rate limiting, the external URLs we did not check), then the ten most important problems in plain words, each with the pages it affects, how to fix it and an example. Then go as deep as you need. Every call works during the crawl too, on what was found so far.

## Parameters

### Headers

| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| `Authorization` | string | Yes | – | `Bearer` followed by your API key. See [Authentication](/docs/get-started/authentication). |

### Path parameters

| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| `id` | string | Yes | – | The audit's `id`, from [Audit a website](/docs/site-audit/audit-a-website). |

## Every way to read an audit

| Call | Answer |
|---|---|
| `GET /v1/site-audit` | Your audits, newest first. |
| `GET /v1/site-audit/{id}` | Status, live `progress` and `counts`. See [Follow an audit](/docs/site-audit/follow-an-audit). |
| `GET …/{id}/summary` | `notes`, plain sentences on how complete the audit is (why the crawl stopped early, rate limiting, the external URLs we did not check), then the ten most important problems in plain words. |
| `GET …/{id}/issues` | Every issue found, worst first, with the report's `groups` in order (Internal pages, Indexability, AI discoverability, Links, Redirects, Content and so on, each with its `subgroups`). Each issue: `id`, a short `name` such as "404 page", `severity`, `group`, `groupName`, `subgroup`, `description`, `fix`, `urls` out of `of`, `share`, `indexable` and `notIndexable`, `site` for site-wide findings, `found`, `change` against an earlier audit, `history` and five `examples`. In Links and Content a page issue comes as two rows, Indexable and Not indexable (`split`); `split=none` gives one row per issue, `split=indexability` splits every group. `view=all` lists all 213 checks, those that found nothing with `found: false`. Filters `severity`, `group`; `compare` names another finished audit of the same site to compare with. |
| `GET …/{id}/issues/{issue}` | The URLs with one issue as a table: `columns` names its fields in order, `url`, `status`, `depth`, `indexable` and `inlinks`, then the issue's own (`title` and `titleLength` for title issues, `redirectTo`, `canonical`, `ttfbMs`…), then `detail`. Each URL also has its `template`, and `total` counts them. Against an earlier audit a URL may carry `mark` (`new` or `added`); `lost=true` lists the URLs that no longer have it, marked `removed` or `missing`; `compare` as for `…/issues`. |
| `GET …/{id}/pages` | Page records. Filters `kind` (page, resource, external, all), `status` (a code, a class such as `4xx`, `failed`, `blocked`, `broken`, or `unchecked`: external URLs we did not check), `type` (html, document, image, css, js), `indexable`, `noindex`, `nofollow`, `canonical` (self, other, none), `orphan`, `template`, `depth`, `minDepth`, `maxInlinks`, `minWords`, `maxWords`, `issue` and `q` (the URL contains it); `sort` (url, status, depth, inlinks, words, ttfb, bytes, title) with `order` (asc, desc); `total` counts every match. `url` gives one page with its issues, inlinks and outlinks. |
| `GET …/{id}/pages/filters` | Ready-made page lists with their counts, in groups: internal URLs by status, resources, external URLs (all, broken, not checked), content type, indexability, canonical, depth and links. Each has `params`: send them as the query of `…/pages` to list it. |
| `GET …/{id}/links` | Links, each with `type` (href, image, resource, redirect), `flags`, `sourceStatus`, `targetStatus` and `targetNotCrawled`, and `total`. Filters `q` (either URL contains it), `from`, `to`, `broken`, `external`, `nofollow`, `resources`, `status` (of the target: `2xx` to `5xx`, `failed`, `blocked`, `unchecked`, `notCrawled`) and `type` (image, resource, navigation, redirect). |
| `GET …/{id}/links/filters` | Ready-made link lists with their counts: all, internal, external and to resources; internal links by the status of their target; external links to a broken URL or to one we did not check; followed, nofollow, image, navigation and redirect hops. Each has `params` for `…/links`. |
| `GET …/{id}/structure` | The site as a folder tree: the folders under `path` (none for the hosts), each with `urls`, `hasChildren` and `dist`, its URLs spread by `by`: `status` (the default), `type`, `depth` or `indexability`. |
| `GET …/{id}/log` | The crawl log: `from`, `to`, `durationSeconds` and `urls`, `minutes` (each minute's URLs by status class and fetches a second) and the `latest` fetches. |
| `GET …/{id}/history` | Every audit of the same site by your key, newest first, with its `health` score, `urls`, `htmlPages`, `resources`, `urlsWithErrors` and issues per severity. |
| `GET …/{id}/redirects` | Redirects with their whole chain and the final status; `chains=true` for chains only. |
| `GET …/{id}/duplicates` | Groups of exact duplicates (body, title, description, h1) and near duplicates; filter `kind`. |
| `GET …/{id}/orphans` | Pages known from your sitemaps or `urls` that no followed internal link reaches, with where we know them from. |
| `GET …/{id}/templates` | URL templates (`/blog/{slug}`) with page counts and their issues; estimates for sampled audits. |
| `GET …/{id}/sitemaps` | Each sitemap file read, and the consistency checks. |
| `GET …/{id}/diff/{previousId}` | New and fixed issues, new and gone pages, changed titles, canonicals and status, against an earlier audit of the site. |
| `GET …/{id}/export` | Every page record, 1,000 at a time, by `cursor`. |
| `POST …/{id}/cancel` | Stops the crawl. What was found stays readable, and the site-wide checks run on it. |

Lists take `cursor` (from the previous answer) and `limit` (1 to 1,000, default 100), and answer `{cursor, hasMore, items}`: pass `cursor` back while `hasMore` is true.

## The pages behind one issue

`GET /v1/site-audit/{id}/issues/title-duplicate`, from an audit of rankfield.dev: the `?tab=` addresses repeat the homepage's title.

```json
{
  "cursor": null,
  "hasMore": false,
  "items": [
    {
      "url": "https://rankfield.dev/",
      "status": 200,
      "depth": 0,
      "indexable": true,
      "inlinks": 102,
      "title": "Rankfield — Open web link metrics",
      "titleLength": 33,
      "detail": "3 pages",
      "template": "/"
    },
    {
      "url": "https://rankfield.dev/?tab=key",
      "status": 200,
      "depth": 2,
      "indexable": true,
      "inlinks": 99,
      "title": "Rankfield — Open web link metrics",
      "titleLength": 33,
      "detail": "3 pages",
      "template": "/?tab={v}"
    },
    {
      "url": "https://rankfield.dev/?tab=strength",
      "status": 200,
      "depth": 2,
      "indexable": true,
      "inlinks": 3,
      "title": "Rankfield — Open web link metrics",
      "titleLength": 33,
      "detail": "3 pages",
      "template": "/?tab={v}"
    }
  ],
  "issue": {
    "id": "title-duplicate",
    "name": "Duplicate title",
    "severity": "warning",
    "group": "content",
    "groupName": "Content",
    "subgroup": "",
    "description": "Several indexable pages share this exact title.",
    "fix": "Give each page its own title."
  },
  "of": {
    "set": "indexable",
    "urls": 103,
    "label": "indexable pages"
  },
  "total": 3,
  "columns": [
    "url",
    "status",
    "depth",
    "…"
  ],
  "compared": true
}
```

## Severity

- **error** (45 rules): hurts indexing or visitors now, such as a page or internal link that answers 4xx or 5xx, a redirect loop, or a canonical that points at a broken page.
- **warning** (78 rules): likely costs traffic, such as duplicate pages, thin content, orphan pages, or a linked page served as something other than HTML.
- **notice** (90 rules): worth a look, such as missing structured data, short titles or missing social cards.

## How counts read

- **Names and groups.** Each issue has a short `name` ("404 page", "Title too long"), a `description` of what was found and a `fix`, and sits in a `group` of the report, sometimes in a `subgroup`.
- **URLs affected.** An issue's `urls` counts each URL that has it once, out of the set the rule reads, given in `of` (`{set, urls, label}`): every crawled URL of the site (`internal`), HTML pages that answered 200 (`htmlPages`), the indexable ones (`indexable`), `redirects`, `sitemapUrls`, or the whole site (`site`, with no URL count). Read it as "3 of 103 HTML pages". `share` is the same as a percentage and never passes 100.
- **Documents are not HTML pages.** Markdown, PDF and other files count in the inventory's `documents` and only in the `internal` set.
- **Indexable split.** Page issues give `indexable` and `notIndexable`, so you can tell the pages that matter for search apart.
- **Issues found.** Per severity, `issueTypes` is how many kinds of issue were found and `affectedUrls` how many URL–issue pairs: a URL with three issues counts three times.
- **Health score.** The share of crawled internal URLs with no error-level issue, 0 to 100, given with its parts in `counts.health`.
- **Change.** Against an earlier finished audit of the same site (`compare` when you name one, else `previous`, else your latest one), each issue gives `change`: `added` (crawled both times, has it now and didn't), `new` (first crawled now and has it), `removed` (had it and doesn't), `missing` (had it and wasn't crawled this time) and `net`. An issue that is gone shows `urls` 0.
- **History.** `history` gives the issue's `urls` in up to ten earlier finished audits of the site, oldest first, ending with this one.
- **Not checked is never broken.** An external URL we did not check carries `error`: `siteExcluded` (a site we never fetch, such as the social networks' share links), `robotsDisallowed`, or `botBlocked` (its bot protection answered our check with a `401`, `403` or `429`, or a challenge page; `facts.firewall` says what we saw). None of them counts as a broken link, in issues, the `broken` filters or the inventory. `status=unchecked` lists them, on `…/pages` and `…/links`.

## Errors

| Status | Code | When |
|---|---|---|
| 400 | `invalid_input` | A parameter is missing, unknown or malformed (unknown parameters are refused), or the body is over 1 MB. |
| 401 | `unauthorized` | No valid API key. |
| 404 | `not_found` | No audit with this id for this key (only the key that started an audit can read it), an unknown issue, or a page that is not in the audit. |
| 500 | `internal` | Our bug. Retry. |
| 503 | `unavailable` | New audits are paused while the service is short of storage, or it is restarting. Retry after `Retry-After`. |

## MCP

On the [MCP server](/docs/agents/mcp-server), the tools for this are `site_audit_summary`, `site_audit_issues`, `site_audit_issue_pages`, `site_audit_pages`, `site_audit_links`, `site_audit_redirects`, `site_audit_duplicates`, `site_audit_orphans`, `site_audit_templates`, `site_audit_sitemaps`, `site_audit_diff`, `site_audit_export`, `site_audit_page_filters`, `site_audit_link_filters`, `site_audit_structure`, `site_audit_log` and `site_audit_history`.
