# Timeouts and response size

Two limits shape every web check: the **timeout** (how long to wait for an answer before the check fails) and, for
HTTP-family monitors, the **maximum response size** (how much of the body is downloaded and judged). Both have
ceilings so that one very slow or very large target cannot tie up a checkpoint.

## Timeout by monitor type

| Type | App label | API field (v2) | Range | Default |
|---|---|---|---|---|
| Website/HTTPS (`http`), API (`api`) | **Timeout** (Main Settings), slider 1-100 s | `settings.timeout` (milliseconds) | 50-100000 ms | 40000 ms (40 s) |
| Web content check (`cntCheck`) | **Timeout**, slider 1-120 s | `settings.timeout` (ms) | 50-120000 ms | 40000 ms |
| Page speed (`waterfall`) | **Page load timeout**; **Page load timeout without XHR** (0 = off) | `settings.timeout`, `settings.xhr` (ms) | 0-40000 ms each | 20 s in the app |
| Transaction (`tran`) | **Transaction timeout**; per-step **Navigation timeout** | `settings.timeout` (whole check), per-step `timeout` (ms) | 0-40000 ms | 40000 ms (steps: 20000 ms) |
| Ping, Port | No setting | - | - | The checkpoint's built-in limit |

The timeout covers connecting, the TLS handshake and receiving the response. For Website/HTTPS monitors DNS
resolution is not counted against it. A check that runs out of time fails with a timeout error, and - like any
failure - is then [re-checked](/monitors/down-detection/) before the monitor turns Down.

**Choosing a value.** Too tight, and a site that is slow but working is reported down. Too loose, and a real outage
takes longer to confirm and is recorded as lasting longer than it really did (each failed check waits the full
timeout - see [Short outages recorded as long downtime](/troubleshooting/short-outages/)). For most sites 10-30
seconds is a good range. To alert on slowness without calling the site down, keep a generous timeout and add a
timing [assertion](/monitors/advanced/assertions/) such as `time lt 2s`.

## Maximum response size (Website/HTTPS and API)

| Setting (app label) | API field (v2) | Type / allowed values | Default | What it does for you |
|---|---|---|---|---|
| **Max response size** (Response Validation) | `settings.maxSize` | Bytes. Effective ceiling 10 MB (10485760); the API accepts 1024 and up | 1 MB (1048576) | Stops downloading the body once it reaches this size. Keyword checks and assertions judge only the part that was downloaded. |

The body is read up to the limit and the rest is ignored. A keyword or value that sits past the limit is simply
not seen.

:::caution[A cut-off body fails the check instead of guessing]
When the page is larger than the limit and a required keyword was not found in the downloaded part - or an
assertion could not be proven on it - the check cannot tell whether the text is missing or just past the
cut-off. It then **fails** with the error `ContentTooLarge` ("Response body exceeds the N-byte scan limit; ...")
rather than silently passing, and the monitor can go Down like for any other failure. A keyword that must **not**
appear and is found in the downloaded part is still reported normally. Fix it by raising **Max response size** (up
to 10 MB) or by matching something nearer the top of the page.
:::

## Set it up in the app

1. On **Sites**, open the monitor.
2. **Timeout**: expand **Main Settings** and set **Timeout** (seconds). For Page speed and Transaction monitors,
   the timeouts are in the type's own settings group.
3. **Max response size**: expand **Response Validation** and set **Max response size**; the unit selector switches
   between bytes, KB and MB.
4. **Save**.

**Profile -> Defaults -> Timeout** (5, 10, 20, 30, 40, 60 or 120 s, or **Built-in default**) sets the timeout the
**Add Monitor** form starts with; types with a lower ceiling keep their own maximum.

## Do it with the API or MCP

```bash
# 20-second timeout, read at most 2 MB (scope monitor:write)
curl -X PATCH "https://api2.host-tracker.com/monitor/$MONITOR_ID" \
  -H "Authorization: Bearer $HT_TOKEN" -H "Content-Type: application/json" \
  -d '{ "settings": { "timeout": 20000, "maxSize": 2097152 } }'
```

`settings` in a `PATCH` merges into the monitor's existing settings - only the members you send change. MCP:
**`update_monitor`** with `settingsJson` `{"timeout":20000,"maxSize":2097152}`; for many monitors,
**`bulk_update_monitors`** with `patchJson` `{"settings":{"timeout":20000}}`.

## Limits and gotchas

- The API refuses a value outside the type's range (`422 invalid_settings` with `min`/`max`) rather than clamping
  it. Timeouts are **milliseconds** on the API and **seconds** in the app.
- The app's **Max response size** slider goes down to 0 ("read no body at all"), but the API's smallest accepted
  value is 1024 bytes, so a value below 1 KB is refused on save. To judge headers and status only, use the
  `HEAD` [method](/monitors/advanced/http-request-config/) instead.
- A `maxSize` above 10 MB is accepted by the API but stored as 10 MB, the checkpoint's own ceiling.
- 40000 ms is the default for web types and is not stored explicitly, so a read may omit `timeout` when it is at
  the default.

## Related

- [HTTP request configuration](/monitors/advanced/http-request-config/)
- [Assertions and validation rules](/monitors/advanced/assertions/)
- [Short outages recorded as long downtime](/troubleshooting/short-outages/)
