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

# Keyword Monitoring

> Check that web pages and API responses contain the text you expect, and do not contain text you forbid

A keyword monitor makes the same HTTP request as an [HTTP monitor](/monitors/http) and then checks the response body for text. Use it to confirm a page shows the right content, to catch error messages that are served with a `200` status, or to detect defacement.

## When to use it

* Confirm "Welcome" or "Sign in" appears on your homepage
* Check that an API response contains `"status":"ok"`
* Alert when an error message such as `Database connection failed` appears
* Detect unwanted text such as `hacked by` or `Out of stock`

## Create a keyword monitor

<Steps>
  <Step title="Set the basics">
    Name, URL, interval and timeout work exactly as for HTTP monitors. See [HTTP settings](/monitors/http#settings).
  </Step>

  <Step title="Add keywords">
    Add one or more keywords. Mark each as **must contain** or **must not contain** (`should_contain`: `true` / `false`).
  </Step>

  <Step title="Choose matching rules">
    Pick `match_mode` and `case_sensitive` (below).
  </Step>
</Steps>

### Keyword settings

These go in `keyword_config`:

| Field | Description | Default |
| - | - | - |
| `keywords` | List of up to 20 entries `{ "text": "...", "should_contain": true \| false }`. `text` is 1 to 500 characters | see note |
| `match_mode` | `all` or `any`: how **must-contain** keywords are combined | `all` |
| `case_sensitive` | Match letter case exactly | `false` |
| `method` | HTTP method. `GET`, `POST`, `PUT`, `DELETE`, `OPTIONS` or `PATCH` (no `HEAD`: it returns no body). Required by the schema | Required |

<Note>
  Older clients can send a single `keyword` plus `should_contain` instead of the `keywords` list. `keywords` takes precedence when both are present. `regex_pattern` is accepted for compatibility but is treated as a plain text keyword, not a regular expression. At least one of `keywords`, `keyword` or `regex_pattern` is required.
</Note>

### Request settings

Request settings for the check (headers, body, expected status codes, redirects, slow-response threshold) are read from `http_config`, exactly as on HTTP monitors. See [HTTP monitoring](/monitors/http#settings) for the field list, including the default that **only status `200` passes** unless you set `expected_status_codes`.

### Example

```bash theme={null}
curl -X POST https://api.uptimeio.com/api/monitors \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Homepage content",
    "type": "KEYWORD",
    "target": "https://www.yourcompany.com",
    "interval_seconds": 300,
    "monitoring_regions": [],
    "http_config": { "method": "GET", "expected_status_codes": [200] },
    "keyword_config": {
      "method": "GET",
      "keywords": [
        { "text": "Welcome to YourCompany", "should_contain": true },
        { "text": "Database connection failed", "should_contain": false }
      ],
      "match_mode": "all",
      "case_sensitive": false
    }
  }'
```

## How matching works

1. The HTTP request is checked first (status code, timeout, TLS).
2. The keywords are checked against the **response body**.

| Keyword type | Check fails when |
| - | - |
| Must contain (`should_contain: true`) | `match_mode` is `all`: any such keyword is missing. `match_mode` is `any`: none of them is present. |
| Must not contain (`should_contain: false`) | **Any** such keyword is present. `match_mode` does not apply. |

Matching is plain substring matching. There is no regular-expression support: create separate keywords for each phrase.

<Warning>
  Only the response body is searched. The `search_area` field is accepted for compatibility but headers are not searched.
</Warning>

## Case sensitivity

| `case_sensitive` | Example |
| - | - |
| `false` (default) | `error` matches `Error` and `ERROR` |
| `true` | `Error` matches only `Error` |

## Examples

```json theme={null}
{ "keywords": [{ "text": "Out of stock", "should_contain": false }] }
```

Alerts when a product page says it is out of stock.

```json theme={null}
{ "keywords": [
    { "text": "\"status\":\"ok\"", "should_contain": true }
  ],
  "case_sensitive": true }
```

Alerts when the API stops returning the success indicator.

```json theme={null}
{ "keywords": [
    { "text": "Sign in", "should_contain": true },
    { "text": "Log in", "should_contain": true }
  ],
  "match_mode": "any" }
```

Passes when either phrase is on the page.

## SSL, domain expiry and slow responses

Keyword monitors support the same `ssl_monitoring`, `domain_monitoring` and slow-response options as HTTP monitors:

* [SSL certificate monitoring](/monitors/http#ssl-certificate-monitoring): warnings at 30, 15, 7 and 1 days; an expired or invalid certificate opens an incident.
* [Domain expiry monitoring](/monitors/http#domain-expiry-monitoring)
* [Slow response alerts](/monitors/http#slow-response-alerts)

## Best practices

* Choose text that is stable and specific. `Database connection timeout` beats `Error`.
* Monitor a lightweight endpoint. The whole response body is downloaded and searched.
* Test your keywords against the real page source before relying on them.
* Remember that UptimeIO sees the HTML your server returns, not content rendered later by JavaScript.

## Troubleshooting

<AccordionGroup>
  <Accordion title="Keyword reported missing but it is on the page">
    Check spelling and `case_sensitive`. View the page source (not the rendered page): content added by JavaScript is not in the response. If the content depends on cookies or the user agent, the monitor may receive a different page.
  </Accordion>

  <Accordion title="False alarms from a must-not-contain keyword">
    The phrase may also appear in navigation, scripts or comments. Use a more specific phrase.
  </Accordion>

  <Accordion title="Validation error about keywords">
    `keywords` needs 1 to 20 entries, each with non-empty `text` (max 500 characters) and a boolean `should_contain`. `method` cannot be `HEAD`.
  </Accordion>

  <Accordion title="Check fails on status code">
    Only `200` passes unless you list other codes in `http_config.expected_status_codes`.
  </Accordion>
</AccordionGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="HTTP Monitoring" icon="globe" href="/monitors/http">
    All request options
  </Card>

  <Card title="Notifications" icon="bell" href="/notifications/overview">
    Configure alerts for keyword monitors
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.