<!-- https://developers.silktide.com/v1/governance/testing/test-html-fragment | Governance / Testing -->

# Test a piece of HTML for spelling, grammar and accessibility issues

`POST /v1/inspector/html-fragment-test`

Tests a piece of HTML, such as `<h1>Our wines</h1>` or a whole draft page,
there and then, and answers with what each check found. Use it to check
content before you publish it. Nothing is saved, and no website is needed.

Only some checks can run on HTML alone: Silktide's own spelling, grammar,
readability and accessibility checks, the ones certain enough to report an
error. A fragment has no styles, scripts, headers or other files, so checks
that need them, such as color contrast or broken links, are left out, and so
are checks from your policies. The list depends on the account, so read it
from the answer rather than assuming it.

A fragment is tested as a page on its own, so a short one fails page-level
checks such as a missing `<title>` or page language. Ignore the checks that
do not apply to what you sent.

Send `options` with `website.languages`. Without it, spelling and grammar
are checked in US English.

When the account has AI spell check turned on, the spelling check asks an AI
model about each word no dictionary recognizes. That costs Silktide money,
not the account's balance, and makes a call take several seconds; words it
has seen before are answered from what it learned then.

A missing or empty `html` fails with status `400` and an `InvalidRequest`
error whose `properties.field` is `html`.

## Request

### Body

- `html` (string, required, at least 1 characters): The HTML to test: a whole page or part of one.
- `url` (string, optional): The address to treat the HTML as coming from, for resolving relative links and images. Defaults to `https://example.com/`.
- `options` (map of any JSON, optional): Website settings to test with, by name, as on Update a website. Send `website.languages`, such as `["en-GB"]`: it is the only way the spelling, grammar and readability checks know the language. Defaults to US English.

## Response

Status `200`.

- `checks` (list of objects, required): Each check that can test a fragment of HTML, and what it found.
  - `checkId` (string, required): The check's id, such as `spelling`.
  - `name` (string, required): The check's short name, in the API user's language.
  - `standard` (string, required): The standard it tests against, such as `WCAG 2.0 A 1.1.1`. Can be empty.
  - `score` (number, required, can be null, 0 to 100): Its score for the HTML out of 100, to two decimal places. Null when it could not test it.
  - `numIssues` (integer, required): How many issues it found.
  - `testStatus` (string, required): `tested` when the check ran. Anything else says why it could not, such as `not-enough-text` or `no-checkable-languages`.
  - `points` (list of objects, required): Each issue it found. Empty when it found none.
    - `pointId` (string, required): The issue's id.
    - `selectors` (list of objects, required, can be null): Where in the HTML the issue is. Null when it is about the HTML as a whole, such as a missing `<title>`.
      - `type` (string, required): `text` to highlight some text, `css` to highlight the elements a CSS selector matches. One of: `text`, `css`.
      - `match` (string, required): The text to find, or the CSS selector.
      - `cssSelector` (string, optional): With `type: text`, the element to look for the text in. Can be empty.
      - `caseSensitive` (boolean, optional): With `type: text`, whether the text must match case.
    - `descriptionId` (string, optional): Which explanation of the issue applies, when its check has more than one.
    - `firstSeen` (null, required): When the issue was first seen. Always null here: a fragment has no history.
    - `newnessKeys` (null, required): Always null here.
    - `html` (string, optional): The HTML of the element at fault.
    - `htmlHash` (string, optional): A hash of `html`.
    - `text` (string, optional): The text at fault.
    - `isVisible` (boolean, optional): Whether the element is visible when the page loads.
    - `isSightVisible` (boolean, optional): Whether a sighted reader sees it, as opposed to text only for screen readers.
    - `classification` (string, optional): How the check grades the issue. For spelling: `10-error`, `15-language` (a word in another language), `20-potential` or `30-case`. For images: `10-visible` or `20-invisible`.
    - `word` (string, optional): Spelling: the word not recognized.
    - `suggestions` (list of strings, optional): Spelling: words it may have meant. Can be empty.
    - `correction` (string, optional): Spelling: the word as HTML with the letters to delete in `<del>`, such as `ha<del>z</del>`. Empty when the fix needs more than deleting letters.
    - `detectedLanguage` (string, optional, can be null): Spelling: the language the word seems to be in, when it can tell.
    - `languages` (list of strings, optional): Spelling: the languages the word was checked in.
    - `insideContext` (string, optional): Spelling: where the word is when it is not plain text, such as `alt`, `title`, `meta` or `screen-reader`. Empty otherwise.
    - `spellingSource` (string, optional): Spelling: what flagged the word: `hunspell` (a dictionary), `global` (Silktide's word list), `account` (the account's dictionary) or `ai` (an AI model).
    - `before` (string, optional): The text just before the issue.
    - `after` (string, optional): The text just after the issue.
    - `typo` (string, optional): Grammar: the text at fault.
    - `replacements` (list of strings, optional): Grammar: what to replace `typo` with.
    - `description` (string, optional): Grammar: what is wrong, in a sentence.
    - `ruleDescription` (string, optional): Grammar: the rule that found it.
    - `grammarRuleId` (string, optional): Grammar: the rule's id.
    - `language` (string, optional): Grammar: the language of the text.
    - `src` (string, optional): Media: the URL of the image, audio or video, resolved against `url`.
    - `srcHash` (string, optional): Media: a hash of `src`.
    - `srcType` (string, optional): Media: the kind of source, such as `image`.
    - `mediaType` (string, optional): Media: `image`, `audio` or `video`.
    - `width` (number, optional, can be null): The element's width in CSS pixels. Null when unknown, as it usually is for a fragment.
    - `height` (number, optional, can be null): The element's height in CSS pixels. Null when unknown.
    - `linkUrl` (string, optional): Links: the link's URL, resolved against `url`.
    - `linkUrlHash` (string, optional): Links: a hash of `linkUrl`.
    - `linkText` (string, optional): Links: the link's accessible name.

## Errors

| Status | Type | When |
| --- | --- | --- |
| 400 | `InvalidRequest` | `html` is missing or empty, `url` is not text, or `options` is not an object. `properties.field` names which. |
| 401 | `NotLoggedIn` | No API key was sent, or it is not a key for this region. |
| 429 | `TooManyRequests` | Too many requests to this path in five seconds. Retry after the number of seconds in the `Retry-After` header, which `properties.retryAfter` repeats. |
| 503 | - | Silktide is busy. Retry after the number of seconds in the `Retry-After` header. |

## Access

- Permission: any user of the account
- Plan feature: none
- Edition: Silktide 4 and Silktide 5
- Cost: uses the account's allowance
- Stability: stable, since 1.0.0

## Example: A paragraph with a misspelling and an image without alt text

```bash
curl -X POST "https://api.eu.silktide.com/v1/inspector/html-fragment-test" \
  -H "Authorization: silktide token=$SILKTIDE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "html": "<p>Our wines are <img src=\"barrel.png\"> aged in oak barels.</p>",
  "options": {
    "website.languages": [
      "en-US"
    ]
  }
}'
```

Response:

```json
{
  "checks": [
    {
      "checkId": "missing-alt",
      "name": "Missing alt text",
      "standard": "WCAG 2.0 A 1.1.1",
      "score": 66.67,
      "numIssues": 1,
      "testStatus": "tested",
      "points": [
        {
          "pointId": "055b0fba2ac90a62cca156afc9f47d21",
          "selectors": [
            {
              "match": "html>p>img",
              "type": "css"
            }
          ],
          "firstSeen": null,
          "newnessKeys": null,
          "html": "<img src=\"barrel.png\">",
          "isSightVisible": true,
          "classification": "10-visible",
          "src": "https://example.com/barrel.png",
          "srcHash": "98bd9120b407057c1b84d7fdada63291",
          "srcType": "image",
          "mediaType": "image",
          "before": "",
          "after": "",
          "width": null,
          "height": null
        }
      ]
    },
    {
      "checkId": "readability",
      "name": "Readability",
      "standard": "",
      "score": null,
      "numIssues": 0,
      "testStatus": "not-enough-text",
      "points": []
    },
    {
      "checkId": "spelling",
      "name": "Spelling",
      "standard": "",
      "score": 39.44,
      "numIssues": 1,
      "testStatus": "tested",
      "points": [
        {
          "pointId": "c5f2e207cbb58d9d26147ae6f7e94485",
          "selectors": [
            {
              "match": "barels",
              "caseSensitive": true,
              "cssSelector": "html>p",
              "type": "text"
            }
          ],
          "firstSeen": null,
          "newnessKeys": null,
          "word": "barels",
          "suggestions": [
            "barrels"
          ],
          "correction": "",
          "detectedLanguage": "en-US",
          "classification": "10-error",
          "before": " aged in oak ",
          "after": ".",
          "insideContext": "",
          "languages": [
            "en-US"
          ],
          "isSightVisible": true,
          "spellingSource": "ai"
        }
      ]
    }
  ]
}
```
