# How Open SEO's Lighthouse Integration Works for Page Performance Auditing

> Discover how Open SEO leverages Lighthouse for page performance auditing. It analyzes up to 10 pages, uses DataForSEO or local Chrome, and normalizes results for storage and export.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: deep-dive
- Published: 2026-07-30

---

**Open SEO implements a multi-layered Lighthouse integration that samples up to 10 representative pages from each site audit, executes performance audits via the DataForSEO API or local Chrome instances, and normalizes the results into a typed schema for storage and export.**

The open-source Open SEO repository (`every-app/open-seo`) provides an optional Lighthouse integration within its site audit workflow to measure page performance, accessibility, best practices, and SEO metrics. This integration operates as a discrete phase in the audit pipeline, processing a curated sample of pages to generate actionable reports without impacting core crawling functionality.

## Workflow Orchestration and Page Sampling

The Lighthouse phase is orchestrated through `runLighthousePhase` in [`src/server/workflows/siteAuditWorkflowPhases.ts`](https://github.com/every-app/open-seo/blob/main/src/server/workflows/siteAuditWorkflowPhases.ts). This function triggers after the crawler completes its collection of site pages, checking the `runLighthouse` flag (default `true`) to determine whether to execute performance auditing.

When enabled, the workflow selects a representative sample using `selectLighthousePages`, which internally calls `selectLighthouseSample` to choose up to 10 pages based on URL depth and response time. This sampling strategy ensures the audit captures diverse page types while respecting API quota limits.

For each selected page, the workflow invokes `fetchAndStoreLighthouseResult`, which communicates with the external DataForSEO Lighthouse API or a locally-run Chrome instance to execute the audit.

## Data Normalization and Storage

Raw Lighthouse JSON payloads undergo normalization before persistence. The conversion logic in [`src/server/lib/lighthouseStoredPayload.ts`](https://github.com/every-app/open-seo/blob/main/src/server/lib/lighthouseStoredPayload.ts) transforms verbose API responses into the compact `StoredLighthousePayload` schema defined by `storedLighthousePayloadSchema`.

The normalization process extracts two primary data structures:

- **`buildStoredLighthouseMetrics`** – Captures numeric performance metrics including First Contentful Paint (FCP), Largest Contentful Paint (LCP), Total Blocking Time (TBT), and Cumulative Layout Shift (CLS)
- **`buildStoredLighthouseIssues`** – Extracts per-category issues across performance, accessibility, best-practices, and SEO audits

These normalized structures are persisted to the audit's `lighthouse_results` table via `AuditRepository.insertLighthouseResults`, enabling efficient querying without parsing raw JSON on each request.

## Retrieving Results and Building Export Reports

Server-side functions expose stored Lighthouse data to the UI layer. The TanStack Server-Function `exportAuditLighthouseIssues` in [`src/serverFunctions/lighthouse.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/lighthouse.ts) handles client requests for audit results.

The retrieval flow utilizes several specialized functions:

- **`getAuditLighthouseData`** – Reads the stored payload and returns a typed object
- **`readStoredLighthousePayload`** – Parses the JSON and optionally filters by category (performance, accessibility, best-practices, or seo)
- **`buildLighthouseExportFile`** – Generates downloadable CSV or JSON reports from the normalized data

The system reports progress through the `Lighthouse progress` field, allowing the front-end to display loading states while audits complete.

## Type Safety and Category Constants

All Lighthouse categories are strictly typed via the shared definition in [`src/shared/lighthouse.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/lighthouse.ts), ensuring compile-time safety across the server and client boundaries:

```typescript
export const LIGHTHOUSE_CATEGORIES = [
  "performance",
  "accessibility", 
  "best-practices",
  "seo"
] as const;

export type LighthouseCategory = (typeof LIGHTHOUSE_CATEGORIES)[number];

```

This type definition guarantees that category filtering in `readStoredLighthousePayload` and `exportAuditLighthouseIssues` only accepts valid Lighthouse audit categories.

## Implementation Example

Trigger a site audit with Lighthouse enabled via the API:

```typescript
// Start a site audit with Lighthouse phase enabled
await fetch("/api/start_audit", {
  method: "POST",
  body: JSON.stringify({ 
    url: "https://example.com", 
    runLighthouse: true 
  })
});

```

Poll for audit status to monitor Lighthouse progress:

```typescript
// Check audit status including Lighthouse phase completion
const status = await fetch(`/api/get_audit_status?auditId=${id}`)
  .then(r => r.json());

```

Retrieve performance-specific results after completion:

```typescript
// Fetch performance audit results
const { report } = await fetch("/api/export_audit_lighthouse_issues", {
  method: "POST",
  body: JSON.stringify({ 
    auditId: id, 
    category: "performance" 
  })
}).then(r => r.json());

```

Export results as CSV for external analysis:

```typescript
// Generate CSV export of all Lighthouse issues
await fetch("/api/export_audit_lighthouse_issues", {
  method: "POST",
  body: JSON.stringify({ 
    auditId: id, 
    format: "csv" 
  })
});

```

## Summary

- **Optional Integration**: The Lighthouse phase runs only when `runLighthouse` is enabled, allowing lightweight crawls without performance auditing overhead.
- **Intelligent Sampling**: `selectLighthousePages` limits audits to 10 representative pages selected by depth and response time to optimize API usage.
- **Normalization Pipeline**: Raw JSON transforms into `StoredLighthousePayload` via [`src/server/lib/lighthouseStoredPayload.ts`](https://github.com/every-app/open-seo/blob/main/src/server/lib/lighthouseStoredPayload.ts), extracting metrics and issues separately.
- **Type-Safe Categories**: The `LIGHTHOUSE_CATEGORIES` constant in [`src/shared/lighthouse.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/lighthouse.ts) enforces valid category types across the entire stack.
- **Exportable Results**: Server functions in [`src/serverFunctions/lighthouse.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/lighthouse.ts) provide filtered data retrieval and CSV/JSON export capabilities.

## Frequently Asked Questions

### How many pages does Open SEO audit with Lighthouse per site audit?

Open SEO audits a maximum of 10 pages per site. The `selectLighthouseSample` function in [`src/server/workflows/siteAuditWorkflowPhases.ts`](https://github.com/every-app/open-seo/blob/main/src/server/workflows/siteAuditWorkflowPhases.ts) selects this representative sample based on URL depth and response time metrics, ensuring coverage of diverse page types while maintaining reasonable execution times.

### Can I run a site audit without Lighthouse performance auditing?

Yes. The Lighthouse integration is optional and controlled by the `runLighthouse` parameter passed to the audit workflow. When set to `false` or when using the strategy `none`, the workflow skips the `runLighthousePhase` entirely and proceeds directly to report generation without making Lighthouse API calls.

### What specific performance metrics does the integration capture?

The integration captures standard Lighthouse metrics through `buildStoredLighthouseMetrics` in [`src/server/lib/lighthouseStoredPayload.ts`](https://github.com/every-app/open-seo/blob/main/src/server/lib/lighthouseStoredPayload.ts), including First Contentful Paint (FCP), Largest Contentful Paint (LCP), Total Blocking Time (TBT), and Cumulative Layout Shift (CLS). It also extracts issue counts for accessibility, best-practices, and SEO categories.

### Where does Open SEO store Lighthouse audit results?

Results are stored in the audit's `lighthouse_results` table after normalization. The `fetchAndStoreLighthouseResult` function persists the data via `AuditRepository.insertLighthouseResults`, storing the compact `StoredLighthousePayload` schema rather than raw API responses to optimize database storage and query performance.