Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 45 additions & 69 deletions ...etic-monitoring/api-checks/assertions.mdx → detect/assertions.mdx
Original file line number Diff line number Diff line change
@@ -1,57 +1,46 @@
---
title: 'Writing assertions for API checks'
description: 'Writing assertions for API checks'
title: 'Defining Assertions'
description: 'Add assertions to validate your check results'
sidebarTitle: 'Assertions'
---



The response of an API request can be checked for correctness and timeliness by using assertions on the response data. Assertions are flexible statements that combine preset modifiers with custom values to meet the needs of a broad set of use cases.
Uptime monitors and API checks allow you to define assertions to validate a response and check its data for correctness.

## How assertions work

Assertions are statements you create that check one aspect of the HTTP response. You can create multiple assertions for one check that assert various aspects of a response, for example:
Assertions let you validate specific parts of a check's response. For example:

- HTTP response status equals 200.
- HTTP response body equals the text "success".
- HTTP response time is lower than 2000 milliseconds.
- HTTP response header "X-Custom-Header" equals "SomeValue".
- HTTP response JSON object has a key called "accountBalance" with a value greater than 9999
- **URL monitor**: HTTP response status equals 200.
- **TCP monitor**: Response contains expected string (e.g. OK).
- **DNS monitor**: Resolved IP equals 93.184.216.34.
- **API check**: HTTP response header "X-Custom-Header" equals "SomeValue".

### Sources

In each assertion, a **source** is connected to a **comparison** and a **target**.

![api monitoring assertions example 1](/images/docs/images/api-checks/assertions-1.png)

In some cases a **property** is added, for example when asserting headers or JSON response bodies.
In some cases a [property](#property) is added, for example when asserting API check headers or JSON response bodies.

![api monitoring assertions example 2](/images/docs/images/api-checks/assertions-2.png)

Assertions are executed from top to bottom. If one assertion fails, the full check is considered as failed.

## Source

On each API check assertion, the following sources are available:
Supported assertion sources vary by monitor type. Refer to the documentation of the specific monitor (API, DNS, TCP, etc.) to see which sources are available.

- **Status code:** The HTTP response status, parsed as an integer.
- **JSON body:** The response body parsed as a JSON object.
- **Text body:** The response body as plain text.
- **Headers:** The response headers as an array of key/value pairs.
- **Response time:** The response time of the full API request in milliseconds, parsed as an integer value.
### Property

## Property
The property field is a free-form text input that lets you point to a specific part of the data you want to validate. It’s available for the following types of assertion [sources](#sources):

The property field is a free form text field used to identify the name of a header, the part of a JSON object using JSON path or part of a text body.
- **JSON response bodies**: Use a JSON path expression in the form of dot-separated strings to
target nested properties in an object, i.e. `$.product.size` or an item in an array, i.e. `$.[1].key`. [Learn more](#json-responses-with-json-path).

- With **JSON response bodies**, the property field accepts **JSON path** expressions in the form of dot-separated strings to
target nested properties in an object, i.e. `$.product.size` or an item in an array, i.e. `$.[1].key`
- **Text response bodies**: Provide a regular expression with a capture group to pick out parts,
i.e. `<!doctype (.{4})` would grab the word `html` from a body return `<doctype html>`. [Learn more](#text-body-assertions-with-regular-expressions).

- With **text response bodies**, the property field accepts a **regular expression** with a capture group to pick out parts,
i.e. `<!doctype (.{4})` would grab the word `html` from a body return `<doctype html>`

- With **headers**, you provide the header you want to assert in the property field, i.e. `Content-Type`. You can even add a
regular expression after that to tease out a specific part of the header.

Read more about asserting JSON response bodies below.
- **API check headers**: Enter the header name you want to assert on i.e. `Content-Type`. You can even add a
regular expression after that to tease out a specific part of the header. [Learn more](#using-regular-expressions).

## Comparison

Expand All @@ -75,19 +64,14 @@ Response time is empty? JSON Object is less than? We block out the comparisons w

The target field is a free form text field that determines the desired outcome of your assertion.


## JSON responses with JSON path

You can use **JSON path** to specify which field of a JSON response body should be asserted. JSON path is a query language
For monitors that support JSON body assertions, you can use **JSON path** to specify which field of a JSON response body should be asserted. JSON path is a query language
similar to Xpath for XML, but in general a lot more intuitive and simpler to use.

> For Checkly to be able to parse the JSON body, the `Content-Type` header of the response should be set to `application/json`.

### JSON path primer

JSON path only uses a handful of operators in its queries. Not all of them are useful in the context of assertions.
Here is an adapted set of examples based on [Stefan Goessner's 2007 introduction post](http://goessner.net/articles/JsonPath/).

The following JSONPath operators are available:

JSONPath | Description
-----------------|------------
Expand Down Expand Up @@ -153,7 +137,6 @@ JSONPath | Description
`$.store..price` | The price of everything in the store
`$.store.book.length` | The length of the book array
`$..book[2]` | The third book
`$..book[(@.length-1)]` | The last book via script subscript
`$..book[-1:]` | The last book via slice
`$..book[0,1]` | The first two books via subscript union
`$..book[:2]` | The first two books via subscript array slice.
Expand All @@ -163,8 +146,7 @@ JSONPath | Description
`$..book[?(@.price<30 && @.category=="fiction")]` | Filter all fiction books cheaper than 30
`$..*` | All members of JSON structure

Use this [online editor to play around](https://jsonpath.com/), or look at the examples below. We use this [jsonpath NPM
module](https://github.com/dchester/jsonpath) under the hood.
Use this [online editor](https://jsonpath.com/) to try out your own JSONPath expressions. For a full description of the syntax and semantics, see [RFC 9535](https://datatracker.ietf.org/doc/rfc9535/).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are not following the rfc and only support a subset of features. let's try to set right expectations:

  • we use non-rfc .length
  • we support none of the Function Extensions

Copy link
Contributor Author

@sujaya-sys sujaya-sys Dec 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are not following the rfc

@sbezludny Is a link to the RFC necessary at all then? Or do you think its worth linking it while mentioning the exceptions you highlighted?

Copy link

@ejanusevicius ejanusevicius Dec 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The underlying library we're using says it follows RFC9535. 🤔

I guess it is out-dated let's then adjust it accordingly.


### Asserting basic types

Expand Down Expand Up @@ -218,23 +200,24 @@ Regular expressions give you the power to extract specific parts of text from a
You can use regular expressions with two assertions sources:

1. **Text body:** Use the property field to add your regex.
2. **Headers:** First select the header you are interested in the property field, then click "add regex".
2. **API check headers:** First select the header you are interested in the property field, then click "add regex".

Here is an example:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example shows the JS .match() function. We should probably remove this too, if we're removing the reference above to .match() (lines 223-224).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally missed this, thanks. I've updated the example, could use another sanity check since I'm no regex expert.


Under the hood, we use the stock Javascript regular expressions implementation. Specifically, we use the [.match()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match)
method. We *do not use the `/g` modifier* and return the first matched group the expression finds.
```
The quick brown fox jumps over the lazy dog. It barked.
```

Sounds more complicated than it is. Here is an example:
And the following regular expression:

```javascript
const paragraph = 'The quick brown fox jumps over the lazy dog. It barked.'
const regex = /quick (.*) fox/
const found = paragraph.match(regex)
console.log(found)

// [ 'quick brown fox',
// 'brown',
// index: 4,
// input: 'The quick brown fox jumps over the lazy dog. It barked.' ]
```
quick (.*) fox
````

The assertion extracts:

```
brown
```

In the example above we return the string `brown` because it is the first capture group, the `(.*)` bit.
Expand All @@ -244,25 +227,18 @@ The first item `quick brown fox` is the full match, which we do not return.

### Text body assertions with regular expressions

If our API returns HTML, there might be a `lang="en"` attribute in the `<html>` element. We can capture the two character
country/language code value of that attribute with the following expression.
When a check returns a text-based response, you can use regular expressions to extract and assert on specific parts of the response body.

For example, an HTML document might include a `lang="en"` attribute on the `<html>` element. You can capture the two-character language code using the following regular expression:

![api monitoring use regular expression on text body](/images/docs/images/api-checks/assertions-10.png)

The expression `lang="(.{2})"` means 'grab any of the first two characters between `lang="` and the next `"`'. If we were
sure there are only non-capital characters, we could tighten it up a bit with `lang="([a-z]*)"`.

### Header assertions with regular expressions

We can use regular expressions with headers too. In this example, we check if the `max-age` property of a `Strict-Transport-Security`
response header is above a `100000`

![api monitoring use regular expression on http header](/images/docs/images/api-checks/assertions-11.png)






### API check header assertions with regular expressions

We can use regular expressions with [API check headers](/detect/synthetic-monitoring/api-checks/configuration#headers) too. In this example, we check if the `max-age` property of a `Strict-Transport-Security`
response header is above a `100000`.

![api monitoring use regular expression on http header](/images/docs/images/api-checks/assertions-11.png)
Original file line number Diff line number Diff line change
@@ -1,32 +1,25 @@
---
title: 'Requests'
description: 'Requests'
sidebarTitle: 'Requests'
title: 'Configuration'
description: 'Configure your API checks to validate responses and ensure your endpoints behave as expected.'
sidebarTitle: 'Configuration'
---

import GenericRuntimeVariablesTable from '/snippets/generic-runtime-variables-table.mdx';

A full HTTP request is created by filling out the various parts of the HTTP request settings screen. Not all sections and fields
are mandatory, only a name and URL are required to get going.
While configuring up your API check, you can run the request and its assertions using the **Run request** button. This will run the API check on production infrastructure and help you debug any issues.

While building up your API check, you can run the request and its assertions using the **Run request** button. This will run the
API checks on the production infrastructure and help you debug any issues.
## Basic Setup

## Method & URL
Start by specifying the endpoint you want to track.

An API check starts with creating an HTTP request including a HTTP verb (GET, POST, PUT, etc.) and a URL at the minimum.
![api monitoring request configuration](/images/docs/images/api-checks/api-request-configuration.png)

![api monitoring http request](/images/docs/images/api-checks/http-request-method.png)

- Available methods are `GET, POST, PUT, HEAD, DELETE, PATCH`
- URL's are checked for correctness and must start with either `http://` or `https://`

Checking the **"This request should fail"** checkbox allows you to treat HTTP error codes (4xx and 5xx) as correct responses. This comes in handy when testing 404 pages or 500 error handling.

When enabled:
* ✅ Failed responses (4xx, 5xx) → check passes
* ✅ Successful responses → check passes
* ❌ Failed assertions → check fails
- **URL**: The HTTP(S) URL to monitor (e.g. https://checklyhq.com). URL's are checked for correctness and must start with either `http://` or `https://`.
- **Request methods**: Available methods are `GET, POST, PUT, HEAD, DELETE, PATCH`.
- **IP family**: Defaults to IPv4.
- **Skip SSL**: Skip SSL certificate validation.
- **Follow redirects**: Automatically follow 30x redirects.
- **This request should fail**: Treat HTTP error codes (4xx and 5xx) as passed. Please note that successful responses still pass. Only failed assertions will cause the check to fail.

## Body

Expand All @@ -48,7 +41,6 @@ JSON bodies are commonly used with REST APIs.

### GraphQL


This option also sets the `Content-Type` request header to `application/json`, but allows you to type GraphQL queries and
format them as such, i.e.

Expand Down Expand Up @@ -93,10 +85,8 @@ This section allows you to add query parameters to the request URL in a structur

## Basic authentication

To add [HTTP basic authentication parameters](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication) to your API
request, use the username and password fields in the relevant section.

![api monitoring basic auth](/images/docs/images/api-checks/http-request-auth.png)
Add [HTTP basic authentication parameters](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication) to your API
request by entering a username and password in the Authentication tab.

## Accessing environment variables

Expand Down Expand Up @@ -167,6 +157,28 @@ parses your spec and prompts you to make some decisions about which requests are
- **Add a "group" tag:** Copy the name of you spec to a tag and add it to each imported request. This helps
filtering and grouping related checks in the Checkly dashboard.

## Assertions

The response of an API request can be checked for correctness and timeliness by using assertions on the response data. This allows you to verify things such as:

- HTTP response status equals 200.
- HTTP response body equals the text "success".
- HTTP response time is lower than 2000 milliseconds.
- HTTP response header "X-Custom-Header" equals "SomeValue".
- HTTP response JSON object has a key called "accountBalance" with a value greater than 9999.

![api check assertions](/images/docs/images/api-checks/api-check-assertions.png)

On each API check assertion, the following sources are available:

- **Status code:** The HTTP response status, parsed as an integer.
- **JSON body:** The response body parsed as a JSON object. To enable parsing, the Content-Type header of the response should be set to application/json.
- **Text body:** The response body as plain text.
- **Headers:** The response headers as an array of key/value pairs.
- **Response time:** The response time of the full API request in milliseconds, parsed as an integer value.

For more details, see our documentation on [Assertions](/detect/assertions).

## Responses

In almost all cases, you have full access to the HTTP response for assertions. We also store the full response
Expand Down
17 changes: 3 additions & 14 deletions detect/synthetic-monitoring/api-checks/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -59,25 +59,14 @@ API checks perform comprehensive endpoint validation:
API checks are ideal for testing both internal services and external API dependencies your application relies on.
</Tip>

## Timeouts
## Response Metrics

All API checks are capped at a timeout of **30 seconds**. With each request, we record the most relevant timing phases. This can help you troubleshoot slow responses, e.g. your DNS might be slow.
With each request, we record the most relevant timing phases:

The timing phases correspond to the Node.js request library timing phases:

- `wait`: Duration of socket initialization
- `dns`: Duration of DNS lookup
- `tcp`: Duration of TCP connection
- `firstByte`: Duration of HTTP server response
- `download`: Duration of HTTP download

![api monitoring timing phases](/images/docs/images/api-checks/timing-phases.png)

<Note>
## Interpreting the `wait` metric

The "wait" time is the time it takes for the underlying Node HTTP module to get a socket from the network layer.
This time can vary quite a bit, usually it goes from 900 microseconds to some milliseconds. Most clients for API / webpage will have this lag too.

</Note>
This can help you troubleshoot slow responses, e.g. your DNS might be slow.

3 changes: 2 additions & 1 deletion detect/uptime-monitoring/dns-monitors/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,10 @@ With JSON path assertions, you can:

* `$.Answer[0].TTL` → validate TTL values are within expected ranges
* `$.Answer[0].data` → check specific IP addresses or record values
* `$.Answer.length` → check how many records were returned
* `$.Status` → verify the DNS response status code

Learn more about JSON path assertions: [JSON responses with JSON path](/detect/synthetic-monitoring/api-checks/assertions/#json-responses-with-json-path).
Learn more about JSON path assertions: [JSON responses with JSON path](/detect/assertions#json-responses-with-json-path).

### JSON Response Schemas

Expand Down
2 changes: 2 additions & 0 deletions detect/uptime-monitoring/tcp-monitors/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ Configure connection timeouts and data transmission assertions:
* **Read timeout:** Time to wait for response after connection (default: 10 seconds)
* **Data to send:** Optional data to transmit after establishing connection

For more details, see our documentation on [Assertions](/detect/assertions).

### Response Validation

Validate the service response for more precise monitoring:
Expand Down
2 changes: 2 additions & 0 deletions detect/uptime-monitoring/url-monitors/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ Use assertions to validate the status code of your URL request. When one or more
<img src="/images/url-monitor-assertions.png" alt="URL monitor assertions interface showing status code configuration" />
</Frame>

For more details, see our documentation on [Assertions](/detect/assertions).

### Response Time Limits

Set performance thresholds to ensure your application meets speed requirements:
Expand Down
19 changes: 13 additions & 6 deletions docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,10 @@
"group": "API Checks",
"pages": [
"detect/synthetic-monitoring/api-checks/overview",
"detect/synthetic-monitoring/api-checks/api-structure",
"detect/synthetic-monitoring/api-checks/requests",
"detect/synthetic-monitoring/api-checks/assertions",
"detect/synthetic-monitoring/api-checks/configuration",
"detect/synthetic-monitoring/api-checks/set-up-and-tear-down",
"detect/synthetic-monitoring/api-checks/snippets",
"detect/synthetic-monitoring/api-checks/api-structure",
"detect/synthetic-monitoring/api-checks/troubleshooting"
]
},
Expand Down Expand Up @@ -251,7 +250,8 @@
"detect/testing/using-env-variables",
"detect/testing/playwright-reporter"
]
}
},
"detect/assertions"
]
},
{
Expand Down Expand Up @@ -1200,7 +1200,14 @@
}
},
"redirects": [

]
{
"source": "/detect/synthetic-monitoring/api-checks/assertions",
"destination": "/detect/synthetic-monitoring/api-checks/configuration#assertions"
},
{
"source": "/detect/synthetic-monitoring/api-checks/requests",
"destination": "/detect/synthetic-monitoring/api-checks/configuration"
}
]

}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed images/docs/images/api-checks/http-request-auth.png
Binary file not shown.
Binary file modified images/docs/images/api-checks/http-request-headers.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file removed images/docs/images/api-checks/timing-phases.png
Binary file not shown.
2 changes: 1 addition & 1 deletion platform/variables.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ be overridden at the check level.
How variables are accessed depends on where you're accessing them from:

* In [Browser](/detect/synthetic-monitoring/browser-checks/mac-structure#environment-variables), [Multistep](/detect/synthetic-monitoring/multistep-checks/overview#built-in-runtime-variables), and [API Check setup/teardown scripts](/detect/synthetic-monitoring/api-checks/set-up-and-tear-down#built-in-variables), use the standard Node.js `process.env.VARIABLE_NAME` notation.
* In [API Check requests](/detect/synthetic-monitoring/api-checks/requests#accessing-environment-variables), use Handlebars/Moustache templating delimiters, i.e. `{{VARIABLE_NAME}}`
* In [API Check requests](/detect/synthetic-monitoring/api-checks/configuration#accessing-environment-variables), use Handlebars/Moustache templating delimiters, i.e. `{{VARIABLE_NAME}}`
* In [webhook alert channels](/integrations/alerts/webhooks#template-variables), also use the Handlebar/Moustache format, i.e. `{{VARIABLE_NAME}}`

<Note>
Expand Down
Loading