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

> Analyze Cypress performance with built in metrics, TelemetryManager, and CI reporting. Learn how to use perf_hooks and export data to external services for deeper insights.

- Repository: [Cypress.io/cypress](https://github.com/cypress-io/cypress)
- Tags: performance
- Published: 2026-08-06

---

**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`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/util/performance_benchmark.ts) and [`packages/server/lib/cloud/studio/telemetry/TelemetryManager.ts`](https://github.com/cypress-io/cypress/blob/main/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`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/util/performance_benchmark.ts) computes the duration since `cypressServerStartTime` and emits debug logs when `DEBUG=cypress:*` is enabled.

```typescript
// 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`](https://github.com/cypress-io/cypress/blob/main/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.

```typescript
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`](https://github.com/cypress-io/cypress/blob/main/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

```typescript
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 lifecycle** – `bundle: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:

```typescript
// 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:

- **[`packages/server/lib/util/performance_benchmark.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/util/performance_benchmark.ts)** – Global timestamp initialization and `debugElapsedTime` helper
- **[`packages/server/lib/cloud/studio/telemetry/TelemetryManager.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/cloud/studio/telemetry/TelemetryManager.ts)** – Central API for structured marks, measures, and memory‑safe cleanup
- **[`system-tests/lib/performance.js`](https://github.com/cypress-io/cypress/blob/main/system-tests/lib/performance.js)** – CI payload assembly and `track()` implementation
- **[`packages/telemetry/README.md`](https://github.com/cypress-io/cypress/blob/main/packages/telemetry/README.md)** – OpenTelemetry wrapper documentation used across the monorepo
- **[`packages/server/test/performance/cy_visit_performance_spec.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/test/performance/cy_visit_performance_spec.ts)** – Production example of performance testing with real Cypress commands

## Summary

- **Global timestamps** in [`performance_benchmark.ts`](https://github.com/cypress-io/cypress/blob/main/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`](https://github.com/cypress-io/cypress/blob/main/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.