How to Analyze Cypress Performance: Built‑In Metrics, TelemetryManager, and CI Reporting

Analyze Cypress performance using Node's perf_hooks API, the TelemetryManager class for structured marks and measures, and the system‑tests performance reporter to export data to external services.

The Cypress test runner ships with comprehensive instrumentation for tracking startup times, bundle lifecycles, and custom benchmarks. This guide explains how to leverage the built‑in performance infrastructure—found in packages/server/lib/util/performance_benchmark.ts and packages/server/lib/cloud/studio/telemetry/TelemetryManager.ts—to measure and report performance data in both local development and CI environments.

Global Startup Timing: Binary and Server Initialization

Cypress captures two critical timestamps during initialization that survive the V8 snapshot process. These values are stored on the global object so they remain accessible throughout the application's lifecycle.

cypressBinaryStartTime originates from performance.timeOrigin, marking when the Node process began.

cypressServerStartTime is recorded via performance.now() when the server starts listening for connections.

These timestamps enable elapsed‑time calculations for any subsequent operation. The debugElapsedTime(event) helper in packages/server/lib/util/performance_benchmark.ts computes the duration since cypressServerStartTime and emits debug logs when DEBUG=cypress:* is enabled.

// packages/server/lib/util/performance_benchmark.ts
import { debugElapsedTime } from '@packages/server/lib/util/performance_benchmark'

// Log elapsed time since server started
debugElapsedTime('after-webpack-compile')

This approach provides immediate visibility into cold‑start latency without requiring external infrastructure.

Structured Performance Telemetry with TelemetryManager

For complex, multi‑phase operations, Cypress uses TelemetryManager at packages/server/lib/cloud/studio/telemetry/TelemetryManager.ts. This class wraps Node's perf_hooks with a convenient API for grouping related marks and measures while preventing memory leaks.

Creating Marks and Measures

A mark records a specific point in time. A measure calculates the duration between two marks.

import { telemetryManager } from '@packages/server/lib/cloud/studio/telemetry/TelemetryManager'

// Mark the start of a phase
telemetryManager.mark('bundle:start')

// ... perform work ...

// Mark the end and retrieve duration
telemetryManager.mark('bundle:end')
const bundleTime = telemetryManager.getMeasure('bundle:duration')

console.log(`Bundle compilation took ${bundleTime.toFixed(2)} ms`)

The TelemetryManager automatically clears consumed marks and measures to avoid memory leaks, making it safe for long‑running processes.

Built‑In Telemetry Categories

Cypress uses this system to track several internal operations:

  • Bundle lifecycle – start, compile, and end phases of webpack bundling
  • Initialization sequences – plugin loading and configuration parsing
  • Custom benchmarks – user‑defined performance checkpoints

Because marks are defined centrally, you can add new performance checkpoints without modifying downstream reporting logic.

Exporting Metrics: The System‑Tests Performance Reporter

For CI environments, Cypress aggregates performance data and ships it to a configurable endpoint. The reporter lives in system-tests/lib/performance.js and assembles a JSON payload enriched with commit metadata, CI identifiers, and build environment details.

Environment Configuration

Variable Purpose
PERF_API_URL Target endpoint for performance data
PERF_API_KEY Authentication token for the API

If PERF_API_KEY is absent, the track() function silently skips sending data—ensuring local development remains unaffected.

Using the track() Function

import { track } from '@system-tests/lib/performance'

// Report a custom metric with automatic CI context
track('custom-metrics', {
  'myPhase duration': durationMs,
  'test count': 150
})

The track() function is invoked throughout the Cypress codebase for:

  • Startup times – test runner size and binary startup duration
  • Bundle lifecyclebundle:duration from TelemetryManager
  • Proxy performance – network interception latency
  • cy.visit performance – page load timing in real test scenarios

End‑to‑End Performance Tracking Example

This complete example demonstrates marking phases, extracting measures, and conditionally reporting to a remote service:

// 1️⃣ Import telemetry infrastructure
import { telemetryManager } from '@packages/server/lib/cloud/studio/telemetry/TelemetryManager'
import { track } from '@system-tests/lib/performance'
import { debugElapsedTime } from '@packages/server/lib/util/performance_benchmark'

// 2️⃣ Start measurement
telemetryManager.mark('spec-execution:start')
debugElapsedTime('spec-execution-start')

// 3️⃣ Execute your test logic
await runTestSuite()

// 4️⃣ Complete measurement and extract duration
telemetryManager.mark('spec-execution:end')
const executionTime = telemetryManager.getMeasure('spec-execution:duration')

// 5️⃣ Local debugging
debugElapsedTime('spec-execution-complete')

// 6️⃣ CI reporting (automatically skipped without PERF_API_KEY)
track('test-run-metrics', {
  'spec execution ms': executionTime,
  'spec count': specs.length,
  'failure count': failures
})

Key Files for Cypress Performance Analysis

Understanding these source locations accelerates debugging and extension:

Summary

  • Global timestamps in performance_benchmark.ts provide baseline measurements for server startup and binary initialization.
  • TelemetryManager offers a structured, memory‑safe API for multi‑phase performance tracking using Node's perf_hooks.
  • track() function enriches metrics with CI context and transmits data only when PERF_API_KEY is configured.
  • Debug logging via debugElapsedTime enables local performance inspection without external dependencies.
  • Memory management is built‑in: marks and measures clear automatically after consumption.

Frequently Asked Questions

How do I enable performance logging in local development?

Set DEBUG=cypress:* or DEBUG=cypress:performance* in your environment. The debugElapsedTime function and related instrumentation emit structured logs to stderr when this prefix matches.

Can I use TelemetryManager in my own Cypress plugins or support files?

Yes. Import from @packages/server/lib/cloud/studio/telemetry/TelemetryManager and call telemetryManager.mark() and telemetryManager.getMeasure() following the same pattern used internally. Your marks will coexist with Cypress's internal telemetry.

What happens if PERF_API_URL is set but PERF_API_KEY is missing?

The track() function returns silently without sending data. This design prevents CI failures or local errors when performance reporting is not configured, as implemented in system-tests/lib/performance.js.

How accurate are the duration measurements from TelemetryManager?

Measurements use performance.now() from Node's perf_hooks, which provides sub‑millisecond precision (typically 1µs or better in modern Node versions). Durations are returned as milliseconds with floating‑point precision.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →