---
id: api/commands/request
title: cy.request()
description: Make an HTTP request in Cypress.
section: api
source_path: docs/api/commands/request.mdx
version: 58fe37da39eb8c609113be4464c25c595e9f2b59
updated_at: '2026-08-20T21:57:41.703Z'
---
# request

Make an HTTP request.

## Syntax

```
cy.request(url)
cy.request(url, body)
cy.request(method, url)
cy.request(method, url, body)
cy.request(options)
```

### Usage

**Correct Usage**

```
cy.request('http://dev.local/seed')
```

### Arguments

**url _(String)_**

The URL to make the request to.

If you do not provide a fully qualified domain name (FQDN) URL, Cypress will make its best guess as to which host you want `cy.request()` to use in the URL.

1.  If you make a `cy.request()` after visiting a page, Cypress assumes the URL used for the `cy.visit()` is the host.

```
cy.visit('http://localhost:8080/app')
cy.request('users/1.json') //  URL is  http://localhost:8080/users/1.json
```

1.  If you make a `cy.request()` prior to visiting a page, Cypress assumes the host is the `baseUrl` property configured inside of of your [configuration file](/llm/markdown/app/references/configuration.md).

*   cypress.config.js
*   cypress.config.ts

```
const { defineConfig } = require('cypress')

module.exports = defineConfig({
  e2e: {
    baseUrl: 'http://localhost:1234',
  },
})
```

```
import { defineConfig } from 'cypress'

export default defineConfig({
  e2e: {
    baseUrl: 'http://localhost:1234',
  },
})
```

```
cy.request('seed/admin') // URL is http://localhost:1234/seed/admin
```

1.  If Cypress cannot determine the host it will throw an error.

**body _(String, Object)_**

A request `body` to be sent in the request. When `body` is a JavaScript object or boolean, Cypress automatically JSON-serializes it and sets the `Content-Type: application/json` request header. When `body` is a string, it is sent as-is with no automatic content-type.

**method _(String)_**

Make a request using a specific method. If no method is defined, Cypress uses the `GET` method by default.

Supported methods include:

*   `GET`
*   `POST`
*   `PUT`
*   `DELETE`
*   `PATCH`
*   `HEAD`
*   `OPTIONS`
*   `TRACE`
*   `COPY`
*   `QUERY`
*   `LOCK`
*   `MKCOL`
*   `MOVE`
*   `PURGE`
*   `PROPFIND`
*   `PROPPATCH`
*   `UNLOCK`
*   `REPORT`
*   `MKACTIVITY`
*   `CHECKOUT`
*   `MERGE`
*   `M-SEARCH`
*   `NOTIFY`
*   `SUBSCRIBE`
*   `UNSUBSCRIBE`
*   `SEARCH`
*   `CONNECT`

**options _(Object)_**

Pass in an options object to change the default behavior of `cy.request()`.

You can also set options for `cy.request()`'s `baseUrl` and `responseTimeout` globally in [configuration](/llm/markdown/app/references/configuration.md).

| Option | Default | Description |
| --- | --- | --- |
| `log` | `true` | Displays the command in the [Command log](/llm/markdown/app/core-concepts/open-mode.md#Command-Log) |
| `url` | `null` | The URL to make the request to |
| `method` | `GET` | The HTTP method to use in the request |
| `auth` | `null` | Adds Authorization headers for [HTTP Basic Authentication](#HTTP-Basic-Authentication). |
| `body` | `null` | Body to send along with the request |
| `failOnStatusCode` | `true` | Whether to fail on response codes other than `2xx` and `3xx` |
| `followRedirect` | `true` | Whether to automatically follow redirects |
| `form` | `false` | Whether to convert the `body` values to URL encoded content and set the `x-www-form-urlencoded` header |
| `encoding` | `utf8` | The encoding to be used when serializing the response body. The following encodings are supported: `ascii`, `base64`, `binary`, `hex`, `latin1`, `utf8`, `utf-8`, `ucs2`, `ucs-2`, `utf16le`, `utf-16le` |
| `gzip` | `true` | Whether to accept the `gzip` encoding |
| `headers` | `null` | Additional headers to send; Accepts object literal. _Note:_ `headers` will only be sent for the initial request for `cy.request()`, not for any subsequent requests. |
| `qs` | `null` | Query parameters to append to the `url` of the request |
| `retryOnStatusCodeFailure` | `false` | Whether Cypress should automatically retry status code errors under the hood. Cypress will retry a request up to 4 times if this is set to true. |
| `retryOnNetworkFailure` | `true` | Whether Cypress should automatically retry transient network errors under the hood. Cypress will retry a request up to 4 times if this is set to true. |
| `timeout` | [`responseTimeout`](/llm/markdown/app/references/configuration.md#Timeouts) | Time to wait for `cy.request()` to resolve before [timing out](#Timeouts) |

You can also set options for `cy.request()`'s `baseUrl` and `responseTimeout` globally in the [Cypress configuration](/llm/markdown/app/references/configuration.md).

### Yields

`cy.request()` yields the `response` as an object literal containing properties such as:

*   `status`
*   `body`
*   `headers`
*   `duration`

The `response.body` is automatically parsed as a JavaScript object when the response has a `Content-Type` header whose value ends in `json` (such as `application/json` or `application/vnd.api+json`). Otherwise, `response.body` is a string.

## Examples

### URL

#### Make a `GET` request

`cy.request()` is great for talking to an external endpoint before your tests to seed a database.

```
beforeEach(() => {
  cy.request('http://localhost:8080/db/seed')
})
```

#### Issue an HTTP request

Sometimes it's quicker to test the contents of a page rather than [`cy.visit()`](/llm/markdown/api/commands/visit.md) and wait for the entire page and all of its resources to load.

```
cy.request('/admin').its('body').should('include', '<h1>Admin</h1>')
```

### Method and URL

#### Send a `DELETE` request

```
cy.request('DELETE', 'http://localhost:8888/users/827')
```

#### Alias the request using [.as()](/llm/markdown/api/commands/as.md)

```
cy.request('https://jsonplaceholder.cypress.io/comments').as('comments')

cy.get('@comments').should((response) => {
  expect(response.body).to.have.length(500)
  expect(response).to.have.property('headers')
  expect(response).to.have.property('duration')
})
```

### Method, URL, and Body

#### Send a `POST` request with a JSON body

```
cy.request('POST', 'http://localhost:8888/users/admin', { name: 'Jane' }).then(
  (response) => {
    // response.body is automatically parsed from JSON when the server responds
    // with a Content-Type ending in "json" (e.g. application/json)
    expect(response.body).to.have.property('name', 'Jane') // true
  }
)
```

### Options

#### Request a page while disabling auto redirect

To test the redirection behavior of a login without a session, `cy.request` can be used to check the `status` and `redirectedToUrl` property.

The `redirectedToUrl` property is a special Cypress property that normalizes the URL the browser would normally follow during a redirect.

```
cy.request({
  url: '/dashboard',
  followRedirect: false, // turn off following redirects
}).then((resp) => {
  // redirect status code is 302
  expect(resp.status).to.eq(302)
  expect(resp.redirectedToUrl).to.eq('http://localhost:8082/unauthorized')
})
```

#### HTTP Basic Authentication

To send a request to an endpoint protected by [HTTP Basic Authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication), provide the credentials with the `auth` option. Cypress base64-encodes them and attaches an `Authorization` header to the request.

```
cy.request({
  method: 'POST',
  url: 'https://api.example.com/query',
  auth: {
    username: 'jane.lane',
    password: 'password123',
  },
  body: {
    cpId: 709916,
  },
})
```

The `auth` option also accepts `user`/`pass` as aliases for `username`/`password`.

#### Download a PDF file

By passing the `encoding: binary` option, the `response.body` will be serialized binary content of the file. You can use this to access various file types via `.request()` like `.pdf`, `.zip`, or `.doc` files.

```
cy.request({
  url: 'http://localhost:8080/some-document.pdf',
  encoding: 'binary',
}).then((response) => {
  cy.writeFile('path/to/save/document.pdf', response.body, 'binary')
})
```

#### Get Data URL of an image

By passing the `encoding: base64` option, the `response.body` will be base64-encoded content of the image. You can use this to construct a [Data URI](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) for use elsewhere.

```
cy.request({
  url: 'https://docs.cypress.io/img/logo.png',
  encoding: 'base64',
}).then((response) => {
  const base64Content = response.body
  const mime = response.headers['content-type'] // or 'image/png'
  // see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
  const imageDataUrl = `data:${mime};base64,${base64Content}`
})
```

#### HTML form submissions using form option

Oftentimes, once you have a proper e2e test around logging in, there's no reason to continue to `cy.visit()` the login and wait for the entire page to load all associated resources before running any other commands. Doing so can slow down our entire test suite.

Using `cy.request()`, we can bypass all of this because it automatically gets and sets cookies as if the requests had come from the browser.

```
cy.request({
  method: 'POST',
  url: '/login_with_form', // baseUrl is prepend to URL
  form: true, // indicates the body should be form urlencoded and sets Content-Type: application/x-www-form-urlencoded headers
  body: {
    username: 'jane.lane',
    password: 'password123',
  },
})

// to prove we have a session
cy.getCookie('cypress-session-cookie').should('exist')
```

#### Using `cy.request()` for HTML Forms

[Check out our example recipe using `cy.request()` for HTML web forms](/llm/markdown/app/references/recipes.md#Logging-In)

### Request Polling

#### Call `cy.request()` over and over again

This is useful when you're polling a server for a response that may take awhile to complete.

All we're really doing here is creating a recursive function. Nothing more complicated than that.

```
// a regular ol' function folks
function req () {
  cy
    .request(...)
    .then((resp) => {
      // if we got what we wanted

      if (resp.status === 200 && resp.body.ok === true)
        // break out of the recursive loop
        return

      // else recurse
      req()
    })
}

cy
  // do the thing causing the side effect
  .get('button').click()

  // now start the requests
  .then(req)
```

## Notes

### JSON request and response bodies

#### Request body serialization

When `body` is a JavaScript **object or boolean** and `form` is not `true`, Cypress automatically:

1.  JSON-serializes the request body.
2.  Adds a `Content-Type: application/json` header to the request.

When `body` is a **string**, it is sent as-is and no `Content-Type` header is added automatically.

#### Response body parsing

Cypress always inspects the `Content-Type` header of the response. If that header's value ends in `json` (for example `application/json` or `application/vnd.api+json`), `response.body` is automatically parsed into a JavaScript object. Otherwise `response.body` is a string.

This means the automatic JSON parsing of `response.body` depends entirely on what the server returns in its `Content-Type` header — it is **not** affected by the type of the request `body`.

### Debugging

#### Request is not displayed in the Network Tab of Developer Tools

Cypress does not _actually_ make an XHR request from the browser. We are actually making the HTTP request from Cypress (in Node). So, you won't see the request inside of your Developer Tools.

### CORS

#### CORS is bypassed

Normally when the browser detects a cross-origin HTTP request, it will send an `OPTIONS` preflight check to ensure the server allows cross-origin requests, but `cy.request()` bypasses CORS entirely.

```
// we can make requests to any external server, no problem.
cy.request('https://www.google.com/webhp?#q=cypress.io+cors')
  .its('body')
  .should('include', 'Testing, the way it should be') // true
```

### Cookies

#### Cookies are automatically sent and received

Before sending the HTTP request, we automatically attach cookies that would have otherwise been attached had the request come from the browser. Additionally, if a response has a `Set-Cookie` header, these are automatically set back on the browser cookies.

In other words, `cy.request()` transparently performs all of the underlying functions as if it came from the browser.

Cookies are pulled from the cookie jar by domain match. A cookie set without `hostOnly: true` is a domain cookie, so it can be attached to a `cy.request()` aimed at a _different_ host that domain-matches it (for example a sibling subdomain on the same registrable domain). If a cookie shows up on a request unexpectedly, see [Cookie scope (host-only vs. domain cookies)](/llm/markdown/api/commands/setcookie.md#Cookie-scope-host-only-vs-domain-cookies) for how to scope it to a single exact host with `hostOnly: true`.

### [`cy.intercept()`](/llm/markdown/api/commands/intercept.md)

#### `cy.request()` sends requests to actual endpoints, bypassing those defined using `cy.intercept()`

The intention of `cy.request()` is to be used for checking endpoints on an actual, running server without having to start the front end application.

### User agent

Trying to change the `User-Agent`?

See [how to override the browser's default user agent](/llm/markdown/app/faq.md#Can-I-override-or-change-the-default-user-agent-the-browser-uses).

## Rules

### Requirements

*   `cy.request()` requires being chained off of `cy`.
*   `cy.request()` requires that the server sends a response.
*   `cy.request()` requires that the response status code be `2xx` or `3xx` when `failOnStatusCode` is `true`.

### Assertions

*   `cy.request()` will only run assertions you have chained once, and will not [retry](/llm/markdown/app/core-concepts/retry-ability.md).

### Timeouts

*   `cy.request()` can time out waiting for the server to respond.

## Command Log

**_Request comments endpoint and test response_**

```
cy.request('https://jsonplaceholder.typicode.com/comments').then((response) => {
  expect(response.status).to.eq(200)
  expect(response.body).to.have.length(500)
  expect(response).to.have.property('headers')
  expect(response).to.have.property('duration')
})
```

The commands above will display in the Command Log as:

When clicking on `request` within the command log, the console outputs the following:

## History

| Version | Changes |
| --- | --- |
| [15.20.0](/llm/markdown/app/references/changelog.md#15-20-0) | Added support for `QUERY` method. |
| [4.7.0](/llm/markdown/app/references/changelog.md#3-3-0) | Added support for `encoding` option. |
| [3.3.0](/llm/markdown/app/references/changelog.md#3-3-0) | Added support for options `retryOnStatusCodeFailure` and `retryOnNetworkFailure`. |
| [3.2.0](/llm/markdown/app/references/changelog.md#3-2-0) | Added support for any valid HTTP `method` argument including `TRACE`, `COPY`, `LOCK`, `MKCOL`, `MOVE`, `PURGE`, `PROPFIND`, `PROPPATCH`, `UNLOCK`, `REPORT`, `MKACTIVITY`, `CHECKOUT`, `MERGE`, `M-SEARCH`, `NOTIFY`, `SUBSCRIBE`, `UNSUBSCRIBE`, `SEARCH`, and `CONNECT`. |

## See also

*   [API Testing](/llm/markdown/app/guides/api-testing.md)
*   [`cy.task()`](/llm/markdown/api/commands/task.md)
*   [`cy.visit()`](/llm/markdown/api/commands/visit.md)
*   [Recipe: Logging In - Single Sign on](/llm/markdown/app/references/recipes.md#Logging-In)
*   [Recipe: Logging In - HTML Web Form](/llm/markdown/app/references/recipes.md#Logging-In)
*   [Recipe: Logging In - XHR Web Form](/llm/markdown/app/references/recipes.md#Logging-In)
*   [Recipe: Logging In - CSRF Tokens](/llm/markdown/app/references/recipes.md#Logging-In)
