Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

First find out where the browser actually landed. After cy.visit() or the action that triggers navigation, capture cy.url() or cy.location(), then determine whether the change came from an HTTP redirect, a form or link, or application JavaScript. A redirect can be correct while the next Cypress command fails: if navigation crossed an origin boundary, interacting with the destination requires cy.origin(). For an external site your team does not control, the more stable check is usually the outbound link’s href, not a visit to that site.

Capture the final URL before diagnosing the failure

Do not infer the destination from the address you passed to cy.visit() or from what another browser session displayed. Record the requested URL, then inspect the browser location immediately after the visit or the user action that causes navigation.

cy.visit('/start')
cy.url().should('include', '/expected-path')

cy.location().then((location) => {
  cy.log(`${location.protocol}//${location.host}${location.pathname}${location.search}`)
})

cy.url() gives the current URL; cy.location() can assert or inspect individual location properties. Cypress documents redirect assertions using these commands: cy.visit() and cy.location().

Also note the conditions under which cy.visit() resolves: it follows redirects and waits for the remote page’s load event. Its documented requirements include an HTML response, a 2xx status after redirect following, and a load event that eventually fires. A test timing out or failing after a visit is not, by itself, evidence that Cypress changed the destination. See the visit command requirements.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Classify what caused the navigation

Once you have the final location, identify the transition that produced it. Cypress treats server redirects, form submissions, anchor navigation, and JavaScript-driven navigation as distinct cases. Check the application route and network behavior rather than assuming every change was an HTTP 301 or 302. The Cypress cross-origin guide discusses these navigation paths.

  • Unexpected URL after the initial visit: inspect server redirects, authentication state, the requested path, and any application routing that runs on startup.
  • Unexpected URL after a click or submit: confirm the element, its destination or form action, and whether application code changes window.location.
  • Expected URL, but the next command fails: check whether the destination is a different origin before treating the redirect itself as wrong.

For startup requests, register intercepts before the visit. The app can send requests during initialization, before cy.visit() resolves:

cy.intercept('/api/session', { fixture: 'session.json' })
cy.visit('/app')

See Cypress’s guidance on route registration and visit timing.

Check whether the destination is a different origin

An origin is the combination of scheme, hostname, and port. Changing any of those components—for example, moving from https://app.example.test to https://login.example.test—creates a different origin. The browser’s same-origin boundary determines which page Cypress can control; it is not the same question as whether the redirect reached the intended URL.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Cypress states in its cross-origin testing guide: “Different origins per test require cy.origin().” If the test needs to interact with a controlled secondary origin, put the commands for that origin inside cy.origin():

cy.visit('/login')
cy.get('#continue').click()

cy.origin('https://identity.example.test', () => {
  cy.url().should('include', '/authorize')
})

Replace the example origin with the destination’s exact scheme, hostname, and port. Subsequent commands that inspect or operate on that page belong in the cy.origin() callback. The cy.origin() API describes how commands execute in a secondary origin.

Version matters. Starting with Cypress v14, Cypress no longer injects document.domain by default. Tests that relied on older cross-subdomain behavior may therefore need cy.origin(). The documented injectDocumentDomain compatibility option is transitional and deprecated; consult the version-specific cross-origin guide and origin API when updating an existing suite.

Choose the assertion that matches what you need to prove

There are three useful evidence levels. Choose the one that answers the test’s actual question instead of making every test depend on a remote page.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Approach What it verifies Best fit What it does not prove
Assert a link’s href The application exposes the expected outbound destination string. A third-party destination the team does not control. That the remote service is available or renders the expected page.
Inspect with cy.request() HTTP-level response and redirect information, including redirectedToUrl. Debugging a server-side redirect separately from browser behavior. That a browser rendered the destination or Cypress can interact with it.
Navigate in the browser The final browser location and, within Cypress’s origin boundaries, rendered-page behavior. A destination controlled by your team whose page behavior is part of the test. Reliable control of an unrelated third-party origin without the appropriate origin handling.

For an external link, verify the destination without following it

If your team does not control the destination, Cypress recommends asserting the link’s href rather than visiting the external site. This keeps the test focused on your application and avoids depending on the third party’s availability or behavior. The recommendation appears in the cross-origin guide and common error messages.

cy.visit('/')
cy.get('a.external')
  .should('have.attr', 'href', 'https://partner.example/path')

For an HTTP redirect, inspect the request separately

cy.request() is not bound by browser CORS and exposes a redirectedToUrl property when a request is redirected. Use it to inspect HTTP behavior, not to claim that the browser rendered or interacted with the destination:

cy.request('/start').then((response) => {
  cy.log(response.redirectedToUrl)
})

A relative request uses the visited host if a page has already been visited; before a visit, Cypress resolves it against the configured baseUrl. Confirm the base when comparing the request with browser navigation. See the cy.request() API.

Record the test context and reproduce the same path

Redirect behavior can be difficult to compare if the Cypress run and the external application are not using equivalent inputs. Record these details with the failing run:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Cypress version and browser.
  • Configured baseUrl and the exact requested URL.
  • The final URL after the visit or triggering action.
  • Whether navigation began with a visit, form, link, or JavaScript.
  • Whether the destination changed scheme, hostname, or port.
  • Authentication, session, cookies, or other state that might affect server or client routing.
  • If applicable, whether the run uses Cypress’s legacy or native network path.

Cypress’s native network guide documents behavior for Cypress 16. Treat its network-path details as version- and path-specific, not as a description of every Cypress version: Native network interception. Cypress’s documentation also explains its hosted URL and network interception behavior; do not assume generally that Cypress deliberately changes an application’s redirect destination. For the implementation and limitations, see the cross-origin guide.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot common redirect symptoms

The URL is unexpected immediately after cy.visit()

  • Inspect the final cy.url() or cy.location() before adding assertions about page content.
  • Check whether authentication state, server response behavior, or client routing sent the browser somewhere else.
  • Compare the exact URL, including scheme, hostname, port, path, and query string, with the external run.

The URL is correct, but commands after navigation fail or time out

Compare the starting and final origins. If the test is now on a controlled secondary origin, move the destination-page commands into cy.origin(). Cypress documents that cross-origin navigation can cause commands to time out or fail without the appropriate origin handling; see its cross-origin guide and error reference.

A redirect check passes in cy.request(), but browser behavior differs

That is not necessarily a contradiction. The request check supplies HTTP-level evidence; it does not establish that a browser loaded the page, ran its application code, or could interact with it. Compare it with the browser’s final URL and the relevant rendered behavior separately. The distinction follows from the documented scope of cy.request() and cy.visit().

The failure involves HTTPS changing to HTTP

Check the scheme as well as the hostname and port. Cypress’s cross-origin documentation notes errors for HTTPS-to-HTTP navigation; inspect the destination’s security behavior and the exact transition in the guide.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The destination is inside a cross-origin iframe

Do not treat an iframe as a top-level redirect. cy.origin() addresses top-level origin navigation; it does not grant access to a cross-origin iframe’s DOM. Cypress makes this distinction in its FAQ.

Or skip the browser setup

If the debugging task is to capture a page for visual inspection rather than to exercise Cypress’s redirect logic, ScreenshotNeo can return a screenshot or PDF from one GET request. Its clean-shot options accept cookie or consent banners before capture and remove 60+ known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. ScreenshotNeo also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for AI agents.

Here is the cURL form, using the target URL shown in the command. See the ScreenshotNeo documentation for API details:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Free includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots. Those are ScreenshotNeo plan allowances and prices, not Cypress pricing. Sign up for ScreenshotNeo’s free plan.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

FAQ

Does cy.visit() stop at the first redirect?

No. Cypress documents that cy.visit() follows redirects and resolves after the remote page fires its load event. Inspect the final location to see where the browser landed.

Should every external destination be tested by visiting it?

No. When the destination is a third-party site outside your control, assert the application’s outbound href unless there is a specific need to test the remote response.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.