# What Data Does the OpenSEO Site Audit Collect? A Complete Technical Breakdown

> Discover the comprehensive technical SEO data collected by OpenSEO site audits. Understand HTTP status codes, metadata, Core Web Vitals, and structured data.

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

---

**OpenSEO's site audit collects technical SEO data across three database tables (`audits`, `audit_pages`, `audit_issues`) plus optional Lighthouse performance metrics, capturing everything from HTTP status codes and HTML metadata to Core Web Vitals and structured data detection.**

The **OpenSEO site audit** is a fully-featured crawler designed for comprehensive technical SEO analysis. According to the `every-app/open-seo` source code, it stores crawled data in a structured relational schema that enables detailed reporting, issue detection, and performance benchmarking. This article breaks down exactly what data points are collected, where they're stored, and how you can access them.

---

## Audit Metadata: Tracking Every Crawl

When a site audit initiates, OpenSEO creates a record in the **`audits`** table defined in [`src/db/audit.schema.ts`](https://github.com/every-app/open-seo/blob/main/src/db/audit.schema.ts)【/cache/repos/github.com/every-app/open-seo/main/src/db/audit.schema.ts#L15-L40】.

This row captures:

- **Identifiers**: `id`, `projectId`, `startedByUserId` — link the audit to your workspace and user
- **Crawl origin**: `startUrl` — the seed URL where crawling began
- **Progress tracking**: `status`, `currentPhase`, `pagesCrawled`, `pagesTotal`
- **Configuration**: `config` (JSON) — stores `maxPages` (crawl budget) and Lighthouse strategy settings
- **Lifecycle timestamps**: `startedAt`, `completedAt`
- **Failure diagnostics**: `errorCode`, `errorDetail`, `failedPhase` — when crawls fail, you know exactly where and why

The `audits` table serves as the parent record for every crawl, with one-to-many relationships to page-level and issue-level data.

---

## Page-Level Data: Complete On-Page SEO Signals

For every URL the crawler discovers, OpenSEO writes a row to **`audit_pages`** with exhaustive technical SEO data. The column definitions reside in [`src/db/audit.schema.ts`](https://github.com/every-app/open-seo/blob/main/src/db/audit.schema.ts)【/cache/repos/github.com/every-app/open-seo/main/src/db/audit.schema.ts#L58-L22】.

### HTTP and Response Data

- `statusCode` — HTTP response code
- `redirectUrl` — target if the URL returns a redirect
- `responseTimeMs` — raw server response time
- **`fetchClass`** — critical categorization: whether the fetch succeeded, was **blocked** by a WAF/bot challenge, or errored

### HTML Metadata

- `title` — page title tag content
- `metaDescription` — meta description content
- `canonicalUrl` — canonical tag value
- `robotsMeta` — robots meta directive

### Social and Structured Data

- **Open Graph fields**: `ogTitle`, `ogDescription`, `ogImage`
- **`hasStructuredData`** — boolean flag for JSON-LD/microdata presence
- **`hreflangTagsJson`** — serialized hreflang annotations for international SEO

### Content Analysis

- **Heading structure**: `h1Count` through `h6Count` plus `headingOrderJson` (serialized hierarchy)
- `wordCount` — total word count for thin content detection
- **`contentHash`** — hash of page content for duplicate page identification

### Link and Image Metrics

- **`imagesTotal`**, **`imagesMissingAlt`**, `imagesJson` — image inventory with alt text gaps
- `internalLinkCount`, `externalLinkCount` — link distribution metrics

### Indexability and Crawl Context

- **`isIndexable`**, `xRobotsTag`, `headerCanonicalUrl` — full indexability picture
- `crawlDepth` — distance from start URL
- `inSitemap` — whether URL appeared in robots.txt or XML sitemap reference

---

## Issue-Level Data: Detected SEO Problems

The audit engine runs a catalog of SEO checks against every page. Each detected problem creates a row in **`audit_issues`**:

- **`auditId`** — parent crawl reference
- **`pageId`** / **`pageUrl`** — where the issue was found
- **`issueType`** — registry key (e.g., `"blocked-page"`, `"missing-title"`, `"duplicate-content"`)
- **`severity`** — `"critical"`, `"warning"`, or `"info"`
- **`detailsJson`** — issue-specific context (e.g., broken link target URL, duplicate content hash match)

The complete issue type registry with human-readable descriptions and remediation guidance lives in [`src/shared/audit-issues.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/audit-issues.ts)【/cache/repos/github.com/every-app/open-seo/main/src/shared/audit-issues.ts#L18-L154】. This registry drives the presentation layer and ensures consistent severity classification.

---

## Lighthouse Performance Metrics (Optional)

When `runLighthouse: true` is set in the audit configuration, OpenSEO runs Google Lighthouse on a representative sample of up to **10 pages**. Results are stored in **`audit_lighthouse_results`**:

### Quality Scores

- `performanceScore`
- `accessibilityScore`
- `bestPracticesScore`
- `seoScore`

### Core Web Vitals

- `lcpMs` — Largest Contentful Paint
- `cls` — Cumulative Layout Shift
- `inpMs` — Interaction to Next Paint
- `ttfbMs` — Time to First Byte

### Storage Metadata

- `r2Key` — location of full Lighthouse JSON payload
- `payloadSizeBytes` — stored result size
- Error messages when Lighthouse fails to run

These fields are defined in [`src/db/audit.schema.ts`](https://github.com/every-app/open-seo/blob/main/src/db/audit.schema.ts) under the `audit_lighthouse_results` table【/cache/repos/github.com/every-app/open-seo/main/src/db/audit.schema.ts#L54-L71】.

---

## How to Access Collected Data: Code Examples

### Starting a Site Audit

The `runSiteAuditTool` handler in [`site-audit-tools.ts`](https://github.com/every-app/open-seo/blob/main/site-audit-tools.ts)【/cache/repos/github.com/every-app/open-seo/main/src/server/mcp/tools/site-audit-tools.ts#L71-L73】 creates the audit record and triggers the crawl workflow:

```typescript
import { runSiteAuditTool } from "@/server/mcp/tools/site-audit-tools";

await runSiteAuditTool.handler(
  {
    projectId: "proj_123",
    url: "https://example.com",
    maxPages: 200,
    runLighthouse: true,
  },
  /* context provided by MCP auth middleware */
);

```

### Retrieving Issue Reports

Access structured issue data through the MCP tool layer:

```typescript
import { getAuditIssuesTool } from "@/server/mcp/tools/site-audit-tools";

const response = await getAuditIssuesTool.handler(
  { projectId: "proj_123", auditId: "audit_456" },
  /* auth context */
);

console.log(response.structuredContent.issues);
// Array of: { issueType, severity, pageUrl, details }

```

The response maps each `issueType` to its human-readable descriptor from `AUDIT_ISSUE_TYPES`.

### Direct Database Queries

For custom analysis, query the Drizzle ORM schema directly:

```typescript
import { db } from "@/db/provider";
import { auditPages } from "@/db/audit.schema";

const pages = await db
  .select()
  .from(auditPages)
  .where(eq(auditPages.auditId, "audit_456"));

pages.forEach(p => {
  console.log(p.url, p.title, p.fetchClass, p.responseTimeMs);
});

```

---

## Key Source Files

| File | Purpose |
|------|---------|
| [`src/db/audit.schema.ts`](https://github.com/every-app/open-seo/blob/main/src/db/audit.schema.ts) | Table definitions for `audits`, `audit_pages`, `audit_issues`, `audit_lighthouse_results` |
| [`src/shared/audit-issues.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/audit-issues.ts) | Registry of all issue types with severity levels and descriptions |
| [`src/server/mcp/tools/site-audit-tools.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/tools/site-audit-tools.ts) | Public API: `run_site_audit`, `get_audit_status`, `get_audit_issues`, `get_audit_pages`, `get_audit_performance` |
| [`src/server/workflows/SiteAuditWorkflow.ts`](https://github.com/every-app/open-seo/blob/main/src/server/workflows/SiteAuditWorkflow.ts) | Core orchestration: crawling, issue detection, Lighthouse integration |

---

## Summary

- **Audit metadata** in `audits` tracks crawl lifecycle, configuration, and failure states
- **Page-level data** in `audit_pages` captures 25+ technical SEO signals per URL including metadata, headings, links, images, indexability, and content fingerprints
- **Issue detection** in `audit_issues` records categorized problems with severity and contextual details
- **Performance metrics** via optional Lighthouse integration store Core Web Vitals and quality scores
- All data is accessible through MCP tools or direct database queries using the published schema

---

## Frequently Asked Questions

### What determines which pages get Lighthouse tested?

OpenSEO selects up to 10 representative pages from the crawled set when `runLighthouse: true` is configured. The selection strategy prioritizes diversity across page templates while respecting the crawl budget.

### Can I export raw audit data for external analysis?

Yes. The database schema in [`src/db/audit.schema.ts`](https://github.com/every-app/open-seo/blob/main/src/db/audit.schema.ts) uses standard Drizzle ORM definitions, enabling direct SQL queries or ORM-based exports. The `contentHash` field particularly supports duplicate content analysis in external tools.

### How does OpenSEO handle pages blocked by WAFs or bot protection?

The `fetchClass` column in `audit_pages` explicitly categorizes fetches as successful, blocked, or errored. Blocked pages still create records with `issueType: "blocked-page"` in `audit_issues`, ensuring you discover crawlability problems that other tools might miss entirely.

### Where is the complete list of detectable SEO issues defined?

All issue types, their severity classifications, and remediation descriptions are centralized in [`src/shared/audit-issues.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/audit-issues.ts). This registry drives both the detection engine and the reporting UI, with 30+ issue types covering technical, content, and performance categories.