Running E2E tests against production can feel like juggling chainsaws, but it’s surprisingly achievable and often necessary to catch those elusive, environment-specific bugs. The key isn’t just if you run them, but how you isolate and control the impact.

Let’s see it in action. Imagine a simple e-commerce checkout flow. We want to simulate a real user purchasing an item on our live production site.

# First, ensure you have a dedicated test user and a way to isolate their data
# Then, launch Cypress in interactive mode pointing to the production URL
npx cypress open --e2e --config baseUrl=https://your-production-domain.com

When the Cypress runner opens, you’d select your test file, say cypress/e2e/purchase_item.cy.js.

// cypress/e2e/purchase_item.cy.js
describe('Purchase Item Flow', () => {
  it('should successfully purchase an item', () => {
    // Visit a specific product page
    cy.visit('/products/widget-pro');

    // Add the item to the cart
    cy.get('[data-cy="add-to-cart-button"]').click();

    // Proceed to checkout
    cy.get('[data-cy="checkout-button"]').click();

    // Fill in test user details (ensure these are non-production sensitive)
    cy.get('[data-cy="email-input"]').type('testuser@example.com');
    cy.get('[data-cy="name-input"]').type('Cypress Test User');
    // Use a test credit card number that the payment gateway will accept for testing
    cy.get('[data-cy="card-number-input"]').type('4111111111111111');
    cy.get('[data-cy="expiry-date-input"]').type('12/26');
    cy.get('[data-cy="cvc-input"]').type('123');

    // Submit the order
    cy.get('[data-cy="submit-order-button"]').click();

    // Verify the order confirmation page
    cy.url().should('include', '/order-confirmation');
    cy.get('[data-cy="order-success-message"]').should('contain', 'Thank you for your order!');
  });
});

This test, when run against production, is designed to be a "read-only" operation as much as possible, or at least operate on data that won’t cause issues.

The core problem this solves is the discrepancy between staging/testing environments and the live production site. Configurations, data volumes, third-party integrations, and even subtle network latency can all behave differently in production. By testing against production, you gain confidence that your application functions correctly under its most critical conditions.

Internally, Cypress works by injecting a small script into your web pages. This script communicates with the Cypress test runner via a WebSocket. The runner orchestrates the browser, executing your test commands by interacting with the browser’s DOM and network layers. For production testing, the baseUrl configuration is the primary lever. You point Cypress directly at your live domain. The crucial part is ensuring your test actions don’t have unintended side effects. This means using dedicated test accounts, test credit card numbers (provided by your payment gateway for sandbox environments), and potentially targeting specific, isolated data within your production database if absolutely necessary and permissible.

The actual levers you control are primarily within your Cypress configuration and your test scripts. The baseUrl is paramount. You can also control viewportWidth and viewportHeight to ensure responsiveness tests work on production layouts. Environment variables (env in cypress.config.js) are critical for injecting sensitive (but test-specific) credentials or API keys that might be needed for certain integrations, though for pure UI E2E, these are often minimized. More importantly, you need robust strategies for data management within your tests.

To execute tests against production safely, you must establish a clear separation for test data and test users. This often involves creating a dedicated test user account with minimal privileges and ensuring that any data created or modified by tests is either ephemeral (e.g., a temporary cart that expires) or can be easily cleaned up. For instance, if your test involves creating an order, ensure that the order is flagged internally as a "test order" and that your backend processes are configured not to trigger real-world actions like shipping notifications or inventory deductions for these test orders. This can be achieved through feature flags, specific user roles, or dedicated test environments for payment gateways.

The next logical step after verifying basic flows on production is to explore testing the resilience of your application under load, perhaps by running scaled Cypress tests against a production-like replica or by integrating performance testing tools alongside your E2E suite.

Want structured learning?

Take the full Cypress course →