Automated auditing, performance metrics, and best practices for the web.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Lighthouse provides a comprehensive configuration system and extensibility framework for customizing audits, creating custom gatherers, and adapting the tool to specific testing requirements. This system enables deep customization while maintaining compatibility with the core Lighthouse architecture.
The main configuration interface that controls all aspects of Lighthouse behavior.
interface LH.Config {
// Core configuration
extends?: 'lighthouse:default' | 'lighthouse:desktop' | string;
settings?: LH.Config.Settings;
// Audit configuration
audits?: LH.Config.AuditDefn[];
categories?: Record<string, LH.Config.Category>;
groups?: Record<string, LH.Config.Group>;
// Extension points
plugins?: string[];
passes?: LH.Config.Pass[];
gatherers?: LH.Config.GathererDefn[];
}Runtime settings that control Lighthouse execution behavior.
interface LH.Config.Settings {
// Output configuration
output?: LH.OutputMode | LH.OutputMode[];
outputPath?: string;
locale?: string;
// Runtime configuration
maxWaitForFcp?: number;
maxWaitForLoad?: number;
pauseAfterFcpMs?: number;
pauseAfterLoadMs?: number;
networkQuietThresholdMs?: number;
cpuQuietThresholdMs?: number;
// Throttling configuration
throttlingMethod?: 'devtools' | 'simulate' | 'provided';
throttling?: LH.ThrottlingSettings;
// Device emulation
screenEmulation?: LH.Config.ScreenEmulationSettings;
emulatedUserAgent?: string;
// Audit filtering
onlyAudits?: string[];
skipAudits?: string[];
onlyCategories?: string[];
// Advanced options
disableStorageReset?: boolean;
disableDeviceEmulation?: boolean;
clearStorageTypes?: string[];
budgets?: LH.Budget[];
}Usage Examples:
import lighthouse, { defaultConfig, desktopConfig } from 'lighthouse';
// Basic custom configuration
const customConfig = {
extends: 'lighthouse:default',
settings: {
onlyCategories: ['performance', 'accessibility'],
throttlingMethod: 'simulate',
screenEmulation: {
mobile: false,
width: 1920,
height: 1080,
deviceScaleFactor: 1,
},
},
};
const result = await lighthouse('https://example.com', {}, customConfig);
// Desktop configuration
const result = await lighthouse('https://example.com', {}, desktopConfig);
// Performance-only configuration
const perfConfig = {
extends: 'lighthouse:default',
settings: {
onlyCategories: ['performance'],
throttling: {
rttMs: 40,
throughputKbps: 10240,
cpuSlowdownMultiplier: 1,
},
},
};Framework for creating and configuring custom audits.
/**
* Base class for creating custom audits
*/
class Audit {
/**
* Audit metadata
*/
static get meta(): LH.Audit.Meta;
/**
* Main audit logic
* @param artifacts - Collected artifacts from gatherers
* @param context - Audit execution context
* @returns Audit result with score and details
*/
static audit(
artifacts: LH.Artifacts,
context: LH.Audit.Context
): LH.Audit.Product | Promise<LH.Audit.Product>;
/**
* Generate audit result structure
* @param score - Audit score (0-1 or null)
* @param options - Additional result options
* @returns Formatted audit result
*/
static generateAuditResult(
score: number | null,
options?: {
displayValue?: string;
explanation?: string;
errorMessage?: string;
warnings?: string[];
details?: LH.Audit.Details;
}
): LH.Audit.Product;
}Custom Audit Example:
import { Audit } from 'lighthouse';
class CustomPerformanceAudit extends Audit {
static get meta() {
return {
id: 'custom-performance-audit',
title: 'Custom Performance Check',
description: 'Checks for custom performance criteria',
requiredArtifacts: ['traces', 'devtoolsLogs'],
};
}
static audit(artifacts, context) {
const traces = artifacts.traces[Audit.DEFAULT_PASS];
const devtoolsLogs = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
// Custom audit logic
const customMetric = calculateCustomMetric(traces, devtoolsLogs);
const score = customMetric < 2000 ? 1 : customMetric < 4000 ? 0.5 : 0;
return Audit.generateAuditResult(score, {
displayValue: `${customMetric}ms`,
details: {
type: 'table',
headings: [{key: 'metric', text: 'Custom Metric'}],
items: [{metric: `${customMetric}ms`}],
},
});
}
}
// Configuration with custom audit
const config = {
extends: 'lighthouse:default',
audits: [CustomPerformanceAudit],
categories: {
performance: {
title: 'Performance',
auditRefs: [
{id: 'first-contentful-paint', weight: 10},
{id: 'custom-performance-audit', weight: 5},
],
},
},
};Framework for creating custom data gatherers.
/**
* Base class for creating custom gatherers
*/
class Gatherer {
/**
* Gatherer metadata
*/
meta: LH.Gatherer.GathererMeta;
/**
* Start instrumentation for data collection
* @param passContext - Gatherer execution context
*/
startInstrumentation(passContext: LH.Gatherer.Context): Promise<void> | void;
/**
* Start sensitive instrumentation (user interactions, etc.)
* @param passContext - Gatherer execution context
*/
startSensitiveInstrumentation(passContext: LH.Gatherer.Context): Promise<void> | void;
/**
* Stop sensitive instrumentation
* @param passContext - Gatherer execution context
*/
stopSensitiveInstrumentation(passContext: LH.Gatherer.Context): Promise<void> | void;
/**
* Stop instrumentation and finalize data collection
* @param passContext - Gatherer execution context
*/
stopInstrumentation(passContext: LH.Gatherer.Context): Promise<void> | void;
/**
* Get the collected artifact
* @param passContext - Gatherer execution context
* @returns Collected artifact data
*/
getArtifact(passContext: LH.Gatherer.Context): LH.Gatherer.PhaseResult;
}Custom Gatherer Example:
import { Gatherer } from 'lighthouse';
class CustomMetricsGatherer extends Gatherer {
constructor() {
super();
this.meta = {
supportedModes: ['navigation', 'timespan', 'snapshot'],
};
}
async startInstrumentation(context) {
// Initialize data collection
this.customData = {};
}
async getArtifact(context) {
const {driver} = context;
// Collect custom metrics using Chrome DevTools Protocol
const customMetrics = await driver.executionContext.evaluate(() => {
return {
customLoadTime: performance.now(),
resourceCount: document.querySelectorAll('img, script, link').length,
domComplexity: document.querySelectorAll('*').length,
};
}, {useIsolation: true});
return customMetrics;
}
}
// Configuration with custom gatherer
const config = {
extends: 'lighthouse:default',
passes: [{
passName: 'defaultPass',
gatherers: ['custom-metrics'],
}],
gatherers: [{
path: CustomMetricsGatherer,
options: {},
}],
};Lighthouse supports plugins for packaging custom audits and gatherers.
// Plugin structure
interface LH.Plugin {
audits: LH.Config.AuditDefn[];
groups?: Record<string, LH.Config.Group>;
category: LH.Config.Category;
}Plugin Example:
// lighthouse-plugin-custom.js
module.exports = {
audits: [
{path: 'lighthouse-plugin-custom/audits/custom-audit.js'},
],
groups: {
'custom-group': {
title: 'Custom Checks',
description: 'Custom performance and functionality checks',
},
},
category: {
title: 'Custom Category',
description: 'Custom audits for specialized requirements',
auditRefs: [
{id: 'custom-audit', weight: 1, group: 'custom-group'},
],
},
};
// Configuration using plugin
const config = {
extends: 'lighthouse:default',
plugins: ['lighthouse-plugin-custom'],
};Performance budgets for monitoring resource usage and performance metrics.
interface LH.Budget {
path?: string; // URL path pattern
resourceSizes?: LH.Budget.ResourceBudget[];
resourceCounts?: LH.Budget.ResourceBudget[];
timings?: LH.Budget.TimingBudget[];
}
interface LH.Budget.ResourceBudget {
resourceType: LH.Budget.ResourceType;
budget: number; // Size in bytes or count
}
interface LH.Budget.TimingBudget {
metric: LH.Budget.TimingMetric;
budget: number; // Time in milliseconds
}Budget Example:
const budgetConfig = {
extends: 'lighthouse:default',
settings: {
budgets: [{
path: '/*', // Apply to all pages
resourceSizes: [
{resourceType: 'script', budget: 500000}, // 500KB JS
{resourceType: 'image', budget: 1000000}, // 1MB images
{resourceType: 'stylesheet', budget: 100000}, // 100KB CSS
],
resourceCounts: [
{resourceType: 'script', budget: 10}, // Max 10 scripts
{resourceType: 'image', budget: 50}, // Max 50 images
],
timings: [
{metric: 'first-contentful-paint', budget: 2000}, // 2s FCP
{metric: 'largest-contentful-paint', budget: 4000}, // 4s LCP
],
}],
},
};// Development configuration
const devConfig = {
extends: 'lighthouse:default',
settings: {
throttlingMethod: 'provided', // No throttling for local dev
screenEmulation: {disabled: true}, // Use actual viewport
onlyCategories: ['performance'], // Focus on performance
},
};
// CI configuration
const ciConfig = {
extends: 'lighthouse:default',
settings: {
throttlingMethod: 'simulate', // Consistent throttling
maxWaitForLoad: 60000, // Longer timeout for CI
output: ['json', 'html'], // Multiple outputs
},
};
// Production monitoring configuration
const prodConfig = {
extends: 'lighthouse:default',
settings: {
throttlingMethod: 'simulate',
throttling: { // Production-like conditions
rttMs: 150,
throughputKbps: 1638,
cpuSlowdownMultiplier: 4,
},
budgets: [/* performance budgets */],
},
};function validateConfig(config) {
const errors = [];
// Validate required fields
if (config.audits && !Array.isArray(config.audits)) {
errors.push('config.audits must be an array');
}
// Validate category references
if (config.categories) {
Object.values(config.categories).forEach(category => {
category.auditRefs?.forEach(auditRef => {
const auditExists = config.audits?.some(audit =>
audit.path?.includes(auditRef.id) || audit === auditRef.id
);
if (!auditExists) {
errors.push(`Audit ${auditRef.id} referenced but not defined`);
}
});
});
}
return errors;
}
// Usage
const configErrors = validateConfig(customConfig);
if (configErrors.length > 0) {
throw new Error(`Configuration errors: ${configErrors.join(', ')}`);
}function createDynamicConfig(options = {}) {
const baseConfig = {
extends: 'lighthouse:default',
settings: {
throttlingMethod: options.throttling || 'simulate',
},
};
// Add mobile-specific settings
if (options.mobile) {
baseConfig.settings.screenEmulation = {
mobile: true,
width: 375,
height: 667,
deviceScaleFactor: 2,
};
}
// Add category filtering
if (options.categories) {
baseConfig.settings.onlyCategories = options.categories;
}
// Add custom audits
if (options.customAudits) {
baseConfig.audits = options.customAudits;
}
return baseConfig;
}
// Usage
const mobileConfig = createDynamicConfig({
mobile: true,
categories: ['performance', 'accessibility'],
throttling: 'simulate',
});// Debug configuration loading
import lighthouse, { defaultConfig } from 'lighthouse';
console.log('Default config structure:', JSON.stringify(defaultConfig, null, 2));
try {
const result = await lighthouse('https://example.com', {}, customConfig);
console.log('Configuration applied successfully');
} catch (error) {
if (error.code === 'INVALID_CONFIG') {
console.error('Configuration error:', error.message);
console.error('Config details:', error.details);
} else {
console.error('Lighthouse error:', error.message);
}
}// Enable debug logging for custom components
class DebugAudit extends Audit {
static audit(artifacts, context) {
console.log('Debug audit running with artifacts:', Object.keys(artifacts));
console.log('Audit context:', context);
try {
// Audit logic
const result = performAuditLogic(artifacts);
console.log('Audit result:', result);
return result;
} catch (error) {
console.error('Audit error:', error);
return Audit.generateAuditResult(null, {
errorMessage: error.message,
});
}
}
}