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

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. 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 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 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, ensuring compile-time safety across the server and client boundaries:

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:

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

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

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

// 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, extracting metrics and issues separately.
  • Type-Safe Categories: The LIGHTHOUSE_CATEGORIES constant in src/shared/lighthouse.ts enforces valid category types across the entire stack.
  • Exportable Results: Server functions in 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 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, 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.

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 →