# How OpenSEO Handles Lighthouse Audits: Workflow Architecture and Implementation

> OpenSEO manages Lighthouse audits within its workflow, fetching data, storing key details efficiently in Cloudflare R2, and serving results via server-side API functions.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: architecture
- Published: 2026-09-10

---

**OpenSEO handles Lighthouse audits by orchestrating them as a configurable phase within the site audit workflow, fetching raw data from the DataForSEO API, extracting only essential issue-level details for cost-efficient storage in Cloudflare R2, and serving curated results through dedicated server-side API functions.**

OpenSEO is an open-source SEO automation platform that integrates Google Lighthouse auditing into its comprehensive site analysis pipeline. Unlike storing bulky full reports, the system implements a lightweight, issue-centric approach that prioritizes actionable data while minimizing storage overhead. This article examines the technical implementation details found in the every-app/open-seo repository to explain exactly how the platform processes, stores, and delivers Lighthouse audit results.

## Workflow Orchestration: Controlling When Lighthouse Runs

The Lighthouse audit phase is governed by [`src/server/workflows/siteAuditWorkflowPhases.ts`](https://github.com/every-app/open-seo/blob/main/src/server/workflows/siteAuditWorkflowPhases.ts), which implements the **audit orchestration layer**. This workflow checks the `lighthouseStrategy` option in the audit request—supporting values `"auto"` (enabled) or `"none"` (disabled)—to determine whether to execute the Lighthouse phase.

When the strategy is `"auto"`, the workflow executes `selectLighthousePages` to generate a representative sample of pages from the site. It then schedules parallel fetch jobs for each selected URL and tracks completion and failure counts across the batch. If the strategy is `"none"`, the system skips the entire Lighthouse phase, conserving API calls and compute resources.

## Data Acquisition: Fetching Reports from DataForSEO

Individual fetch jobs invoke the DataForSEO **Lighthouse endpoint** at `/v3/on_page/lighthouse/live/json`. This interaction is wrapped by the `fetchLighthouseResult` function defined in [`src/server/lib/dataforseo/lighthouse.ts`](https://github.com/every-app/open-seo/blob/main/src/server/lib/dataforseo/lighthouse.ts).

The function handles the raw HTTP communication with the third-party API and returns the complete Lighthouse JSON payload. This abstraction isolates the external API dependency and provides a clean interface for the workflow to retrieve audit data without managing low-level network logic.

## Payload Processing and Cloud Storage Optimization

To prevent storage bloat, OpenSEO implements aggressive payload reduction through `readStoredLighthousePayload` in [`src/server/lib/lighthousePayload.ts`](https://github.com/every-app/open-seo/blob/main/src/server/lib/lighthousePayload.ts). This processing layer extracts only **issue-level data** and essential metadata (scores and key metrics) while discarding the heavy full Lighthouse report.

The trimmed payload is then persisted to **Cloudflare R2 object storage** via the utilities in [`src/server/lib/r2.ts`](https://github.com/every-app/open-seo/blob/main/src/server/lib/r2.ts). The audit record stored in the primary database (`site.lighthouse`) receives an `r2Key` identifier that points to the actual payload location. This design keeps database records lightweight while maintaining access to detailed results through the object storage layer.

## Server-Side API Functions for Data Retrieval

Two primary server functions expose Lighthouse data to the front-end in [`src/serverFunctions/lighthouse.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/lighthouse.ts):

- **`getAuditLighthouseIssues`** – Retrieves a specific audit result by `resultId`, fetches the payload from R2 using `getJsonFromR2`, and returns a curated object containing final URL, strategy (mobile/desktop), timestamps, scores, metrics, and the structured issues array.
- **`exportAuditLighthouseIssues`** – Generates downloadable export files by calling `buildLighthouseExportFile`. This function supports both `"category"` mode (filtering by specific Lighthouse categories like "performance") and `"full"` mode (exporting all issues).

Both functions utilize shared validation schemas to ensure data integrity before returning results to the client.

## Schema Validation and Type Safety

Data integrity is enforced through Zod schemas defined in [`src/types/schemas/lighthouse.ts`](https://github.com/every-app/open-seo/blob/main/src/types/schemas/lighthouse.ts). These schemas validate the shape of incoming requests and outgoing responses, guaranteeing that only required fields for UI display or export processing are accepted.

The schemas also provide default values for the `lighthouseStrategy` option and define the structure for `lighthouseAuditIssueSchema` and `lighthouseAuditExportSchema`, ensuring type safety across the server function layer.

## Practical Implementation Examples

### Requesting Lighthouse Issues for a Specific Result

To retrieve processed Lighthouse data for display in the UI:

```typescript
import { getAuditLighthouseIssues } from "@/serverFunctions/lighthouse";

await getAuditLighthouseIssues({
  resultId: "abcd‑1234",        // Lighthouse result identifier
});

```

This function re-hydrates the stored payload from R2 and returns an object shaped like:

```typescript
{
  id: string;
  finalUrl: string;
  strategy: "mobile" | "desktop";
  createdAt: Date;
  hasIssueDetails: boolean;
  scores: Record<string, number> | null;
  metrics: Record<string, number> | null;
  issues: Array<LighthouseIssue>;
}

```

### Exporting Lighthouse Data for Reporting

To generate downloadable audit reports:

```typescript
import { exportAuditLighthouseIssues } from "@/serverFunctions/lighthouse";

await exportAuditLighthouseIssues({
  resultId: "abcd‑1234",
  mode: "category",          // or "full"
  category: "performance",  // required when mode === "category"
});

```

The function returns a downloadable file (CSV or JSON) generated by `buildLighthouseExportFile`, making it ideal for sharing audit results with stakeholders or archiving historical performance data.

### Configuring Lighthouse Strategy in Audit Requests

When creating a new site audit, control Lighthouse execution via the strategy parameter:

```typescript
await fetch("/api/audit", {
  method: "POST",
  body: JSON.stringify({
    urls: ["https://example.com"],
    lighthouseStrategy: "auto",   // "none" disables Lighthouse
    // …other audit options
  }),
});

```

Setting `lighthouseStrategy` to `"none"` completely bypasses the Lighthouse phase, reducing API usage and processing time for audits where Core Web Vitals analysis is unnecessary.

## Summary

OpenSEO implements Lighthouse auditing through a cost-efficient, multi-layered architecture:

- **Orchestration** in [`siteAuditWorkflowPhases.ts`](https://github.com/every-app/open-seo/blob/main/siteAuditWorkflowPhases.ts) controls execution based on the `lighthouseStrategy` option
- **Data acquisition** via `fetchLighthouseResult` interfaces with the DataForSEO API to retrieve raw reports
- **Storage optimization** through `readStoredLighthousePayload` reduces data to issue-level essentials before storing in Cloudflare R2
- **API exposure** via `getAuditLighthouseIssues` and `exportAuditLighthouseIssues` provides flexible access to audit results
- **Type safety** enforced by Zod schemas in [`src/types/schemas/lighthouse.ts`](https://github.com/every-app/open-seo/blob/main/src/types/schemas/lighthouse.ts) ensures reliable data handling across the pipeline

## Frequently Asked Questions

### How does OpenSEO decide which pages to audit with Lighthouse?

The `selectLighthousePages` function within [`src/server/workflows/siteAuditWorkflowPhases.ts`](https://github.com/every-app/open-seo/blob/main/src/server/workflows/siteAuditWorkflowPhases.ts) automatically selects a representative sample of pages from the site when `lighthouseStrategy` is set to `"auto"`. This sampling approach balances comprehensive coverage with API cost efficiency, focusing on diverse page templates rather than auditing every single URL.

### Where does OpenSEO store the actual Lighthouse report data?

Rather than storing full reports in the primary database, OpenSEO persists processed payloads to **Cloudflare R2 object storage** and stores only the `r2Key` reference in the audit record (`site.lighthouse`). This architecture significantly reduces database size and costs while maintaining rapid access to detailed issue data when needed.

### Can I disable Lighthouse auditing to save API credits?

Yes. When creating an audit request, set `lighthouseStrategy` to `"none"` in the request payload. According to the orchestration logic in [`siteAuditWorkflowPhases.ts`](https://github.com/every-app/open-seo/blob/main/siteAuditWorkflowPhases.ts), this value causes the workflow to skip the entire Lighthouse phase, eliminating DataForSEO API calls for Lighthouse data while still performing other SEO analysis tasks.

### What data is included in the Lighthouse export files?

The `exportAuditLighthouseIssues` function generates files containing the curated issue list, scores, and metrics extracted during payload processing. Depending on the `mode` parameter (`"category"` or `"full"`), the export includes either issues filtered to a specific Lighthouse category (such as performance or accessibility) or the complete issue set, formatted as CSV or JSON for stakeholder reporting.