Using cy.intercept() to Stub Network Requests in Cypress: A Practical Guide
Stub XHR/fetch at the browser boundary with cy.intercept() to make UI tests deterministic — registering, verifying, and recovering from silent pass-through.
30 Sept 2025, 00:17 UTC

The problem: UI tests that don't depend on a live backend
End-to-end tests that hit a real API are slow, flaky, and often block CI when a third-party service hiccups. The takeaway: Cypress's cy.intercept() lets you stub or spy on XHR/fetch requests at the browser boundary, so your specs render known application states deterministically. This guide covers registering intercepts, synchronizing with aliases, verifying the stub actually matched, and what to do when it silently doesn't.
Prerequisites
You need a Cypress project with a configured baseUrl, an app under test, and knowledge of the endpoint you plan to intercept: HTTP method, URL shape, and response body. Decide up front which requests to stub (third-party APIs, slow services) and which to let through to the real server. This guide assumes Cypress 6+ where cy.intercept() replaced the deprecated cy.route().
Registering an intercept
Call cy.intercept() before the action that triggers the request — typically in a beforeEach or right before cy.visit(). Intercepts only apply to requests issued after registration, so ordering matters.
// cypress/e2e/user-profile.cy.js
describe('User profile', () => {
beforeEach(() => {
cy.intercept('GET', '/api/users/*', { fixture: 'user.json' }).as('getUser');
cy.visit('/profile');
});
it('renders the user name', () => {
cy.wait('@getUser').its('response.statusCode').should('eq', 200);
cy.get('[data-testid="user-name"]').should('contain', 'Ada');
});
});Run this in the Cypress runner (npx cypress open) — no special permissions needed beyond your project setup. The cy.wait('@getUser') synchronizes with the stubbed response instead of arbitrary sleeps.
Verifying the stub matched
Check the Command Log: the alias should show the request was intercepted, and the network panel confirms the response came from the stub, not the real server. Assert on the captured call:
cy.wait('@getUser').then((interception) => {
expect(interception.request.body).to.have.property('id');
expect(interception.response.statusCode).to.eq(200);
});If the alias never resolves, verify the URL matcher — glob wildcards (*) and query strings are common pitfalls. Unmatched requests pass through to the real server, which can silently produce real-data failures.
Recovery options
If the stub isn't matching, check registration order: intercepts registered after the triggering request has already been sent will not apply. Confirm the matcher with a temporary change to the stubbed body — if the UI doesn't update, the stub is not in effect. Unmatched requests pass through, so a real-data failure often means your matcher missed.
Limitations and trade-offs
Stubbing responses can mask breaking API contract changes and serialization errors that only appear against the real backend. Keep a thin layer of unstubbed end-to-end specs to catch integration regressions. Also note that API surface and matching rules vary across Cypress versions — check your installed version's documentation for the exact cy.intercept() signature and behavior you rely on.
Summary
Register intercepts before the triggering action, use aliases to synchronize, and assert on the captured request and response so the test fails loudly when the call shape changes. If the alias never resolves, suspect the matcher or ordering first.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.