図解でわかるlighthouse パフォーマンス|仕組み・活用・注意点
【書き出し(300-500文字)】
2024年のChrome UX Reportでは、モバイルでCore Web Vitalsに合格するオリジンは約4割にとどまり、INP導入以降は合格率が低下した。¹² 検索流入・CVR・広告品質スコアに直結する「体感速度」は依然として競争優位の源泉だが、実プロダクトで安定して改善を積み重ねるには、実験→計測→回帰防止の閉ループが要る。Lighthouseはこの循環の中心に位置する検証ツールだが、スコアの意味・測定条件・CIへの組み込みを誤ると投資対効果が希薄になる。本稿は、Lighthouseの仕組みを分解し、現場導入で成果を出す手順・コード・ベンチマーク・リスクまでを一気通貫で提示する。検索のページエクスペリエンス評価やランキングの一要素としての位置づけ³、広告のランディングページ評価との関係⁴も踏まえ、実務での意思決定精度を高める。
前提と技術仕様の整理
まず、Lighthouse(v11+想定)の測定前提を正しく固定する。ここが曖昧だと比較不能になり、議論が空転する。
- 前提条件:
- 計測対象: SPA/MPAいずれも可(SSR/SSG含む)
- 目的: パフォーマンスカテゴリの安定運用(CIゲート/回帰検知)
- 環境: Node.js 18+、Chromium/Chrome 安定版、CIはGitHub Actions or GitLab CI
- 計測モード: Mobile(Simulated throttling)⁵
技術仕様(デフォルト測定条件):
| 項目 | 値 | 補足 |
|---|---|---|
| フォームファクタ | Mobile | Moto G4エミュレーション相当⁵ |
| Network | RTT 150ms / Down 1.6Mbps / Up 0.75Mbps | Simulated Throttling(Lantern)⁵ |
| CPU Slowdown | 4x | 単一スレッドに対する遅延係数⁵ |
| ストレージ | クリーン(キャッシュ・Service Worker無効) | 毎回初回訪問相当 |
| 計測回数 | 1回(推奨は3-5回の中央値) | 変動対策 |
| スコア重み | FCP 10, SI 10, LCP 25, TBT 30, CLS 15, INP 10 | 合計100(v11スコアリング)⁵ |
主要指標の目標レンジ(Core Web Vitals準拠):
| 指標 | 目標(良好) | 重点改善の観点 |
|---|---|---|
| LCP | ≤ 2.5s⁶ | 画像最適化、初期HTML/critical CSS、プリロード |
| INP | ≤ 200ms² | JS実行時間短縮、優先度制御、input応答 |
| CLS | ≤ 0.1⁷ | サイズ指定、フォント/広告のレイアウト保護 |
| TBT | ≤ 200ms(目安)⁵ | 長タスク分割、コード分割、Web Worker |
| FCP | ≤ 1.8s(目安)⁵ | 初期描画経路短縮、サーバ応答 |
| SI | 相対指標 | レンダリングの段階的可視化 |
仕組みを正しく理解する(スコアの作られ方)
スコア計算と変動要因
Lighthouseは、トレース(Performance trace)とネットワークログを収集し、Lanternモデルで「シミュレーション」した指標を算出する。このため、DevToolsの実測スロットリングとは一致しない。スコアは各指標のLog-normal曲線に当てはめた正規化値の加重平均で計算される。⁵ 変動要因は主に以下に集約される。
- サーバおよびCDNの瞬間負荷(TTFBのブレ)
- JSバンドルのキャッシュ無効化による初回ダウンロード
- 第三者スクリプトの応答遅延
- クライアントマシンのリソース競合(CIワーカーのノイズ)
運用では、3~5回測定の中央値を採用し、ベースラインを更新するのが再現性の観点で最適だ。
ラボデータとフィールドデータ
- ラボ(Lighthouse/PSIのラボ指標): コード変更の影響を迅速に検証できる。A/BテストやPR単位の回帰検知に向く。
- フィールド(CrUX/Real User Monitoring): 実ユーザ環境の分布。プロダクションKPI。SLOの妥当性確認に用いる。⁸
両者は補完関係であり、ラボで改善仮説を検証し、フィールドで成果を確定させる。⁸
活用:実装と自動化(完全コードつき)
以下は、実務で機能する最小セットから拡張までを段階的に示す。
実装手順(推奨):
- 測定条件の固定(config + flags)
- プログラマティック実行(Node API)
- 認証付きルートの監視(Puppeteer統合)
- CIゲート(PRでスコア/指標しきい値チェック)
- 通知・可視化(Slack/BI/Datadog)
- ベースライン更新・パフォーマンスバジェット運用
コード例1:Node APIでLighthouseを実行(JSON保存)
import fs from 'node:fs';
import path from 'node:path';
import lighthouse from 'lighthouse';
import chromeLauncher from 'chrome-launcher';
async function runLighthouse(url) {
const chrome = await chromeLauncher.launch({
chromeFlags: ['--headless', '--no-sandbox', '--disable-gpu']
});
const options = {
port: chrome.port,
output: 'json',
logLevel: 'info',
throttlingMethod: 'simulate',
formFactor: 'mobile',
screenEmulation: { mobile: true }
};
const config = { extends: 'lighthouse:default', settings: { onlyCategories: ['performance'] } };
try {
const runnerResult = await lighthouse(url, options, config);
const reportJson = runnerResult.report;
const outputPath = path.resolve(process.cwd(), 'lh-report.json');
fs.writeFileSync(outputPath, reportJson);
const score = runnerResult.lhr.categories.performance.score;
console.log('Performance score:', Math.round(score * 100));
} catch (e) {
console.error('Lighthouse run failed', e);
process.exitCode = 1;
} finally {
await chrome.kill();
}
}
runLighthouse(process.argv[2] || 'https://example.com');
ポイント:
- throttlingMethodはsimulateを明示。DevToolsのdevtools設定と混同しない。⁵
- 出力JSONはCIアーティファクトとして保存。
コード例2:認証が必要なダッシュボードを計測(Puppeteer連携)
import puppeteer from 'puppeteer';
import lighthouse from 'lighthouse';
import fs from 'node:fs';
async function auditAuthenticated(url, credentials) {
const browser = await puppeteer.launch({
headless: true,
args: ['--remote-debugging-port=9222', '--no-sandbox']
});
try {
const page = await browser.newPage();
await page.goto(credentials.loginUrl, { waitUntil: 'networkidle0' });
await page.type('#email', credentials.email);
await page.type('#password', credentials.password);
await Promise.all([
page.click('button[type=submit]'),
page.waitForNavigation({ waitUntil: 'networkidle0' })
]);
const options = { port: 9222, output: 'json', logLevel: 'error' };
const { lhr, report } = await lighthouse(url, options);
fs.writeFileSync('lh-auth.json', report);
console.log('LCP(ms):', Math.round(lhr.audits['largest-contentful-paint'].numericValue));
} catch (err) {
console.error('Audit failed', err);
process.exitCode = 1;
} finally {
await browser.close();
}
}
auditAuthenticated('https://app.example.com/dashboard', {
loginUrl: 'https://app.example.com/login',
email: process.env.EMAIL,
password: process.env.PASSWORD,
});
ポイント:
- 認証状態の再現で「本番に近い」ラボ計測が可能。
- ログイン後リダイレクト完了まで待機し、測定対象URLを走査。
コード例3:PageSpeed Insights APIでLighthouse JSONを取得(Python)
import os
import time
import json
import requests
API = "https://www.googleapis.com/pagespeedonline/v5/runPagespeed"
def fetch_lighthouse(url: str, strategy: str = "mobile") -> dict:
params = {
"url": url,
"strategy": strategy,
"category": "PERFORMANCE",
"locale": "ja",
"key": os.environ.get("PSI_API_KEY", "")
}
try:
res = requests.get(API, params=params, timeout=120)
res.raise_for_status()
data = res.json()
return data.get("lighthouseResult", {})
except requests.RequestException as e:
raise SystemExit(f"PSI request failed: {e}") from e
if __name__ == "__main__":
start = time.time()
lhr = fetch_lighthouse("https://example.com")
score = lhr["categories"]["performance"]["score"]
lcp = lhr["audits"]["largest-contentful-paint"]["numericValue"]
print(json.dumps({"score": score, "lcp": lcp, "elapsed_ms": int((time.time()-start)*1000)}))
ポイント:
- PSIはGoogle側インフラで実行されるため、CIノイズの影響を受けにくい。⁹
- APIクォータ管理とキャッシュ(ETag)を設計する。
コード例4:LHRをSlackへ通知(TypeScript)
import fs from 'node:fs';
import axios from 'axios';
type LHR = {
categories: { performance: { score: number } };
audits: Record<string, { numericValue?: number; displayValue?: string }>;
};
async function notifySlack(file = 'lh-report.json') {
const lhr: LHR = JSON.parse(fs.readFileSync(file, 'utf-8'));
const score = Math.round(lhr.categories.performance.score * 100);
const lcp = Math.round(lhr.audits['largest-contentful-paint'].numericValue || 0);
const inp = Math.round(lhr.audits['interaction-to-next-paint'].numericValue || 0);
const tbt = Math.round(lhr.audits['total-blocking-time'].numericValue || 0);
const text = `Lighthouse: ${score}\nLCP: ${lcp} ms | INP: ${inp} ms | TBT: ${tbt} ms`;
try {
await axios.post(process.env.SLACK_WEBHOOK_URL as string, { text });
console.log('Sent to Slack');
} catch (e) {
console.error('Slack notification failed', e);
process.exit(1);
}
}
notifySlack();
ポイント:
- チームにしきい値逸脱を即時通知。回帰を最短で検知。
コード例5:配信最適化(Expressでimmutableキャッシュ)
import express from 'express';
import compression from 'compression';
import path from 'node:path';
const app = express();
app.use(compression({ level: 6 }));
app.use((req, res, next) => {
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
next();
});
app.use('/static', express.static(path.join(process.cwd(), 'public'), {
setHeaders: (res, filePath) => {
if (/\.(js|css|woff2|png|svg)$/.test(filePath)) {
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
}
}
}));
app.get('/healthz', (_req, res) => res.status(200).send('ok'));
app.listen(3000, () => console.log('server on 3000'));
ポイント:
- キャッシュ安定化はLCP/TBT双方に効く(ネットワークI/O削減+初期パース負荷低減)。⁶
コード例6:Next.js middlewareでpreload/preconnect
import type { NextRequest } from 'next/server';
import { NextResponse } from 'next/server';
export function middleware(req: NextRequest) {
const res = NextResponse.next();
res.headers.set('Link', [
'</fonts/myfont.woff2>; rel=preload; as=font; type="font/woff2"; crossorigin',
'<https://cdn.example.com>; rel=preconnect; crossorigin',
].join(','));
return res;
}
ポイント:
- 先読み・接続の前倒しでLCPとFCPを直接短縮。⁶
- フォントはpreloadとdisplay: swapの併用、Font Loading APIの活用などが有効。¹⁰
ベンチマークと運用(成果に結びつける)
検証対象: EC商品詳細ページ(SSR、初期JS 240KB gzip、Hero画像 160KB、第三者タグ 2本)
測定条件: Lighthouse Mobile/Simulated、3回実行の中央値、CI専用Runner(2vCPU固定)
施策:
- 画像の適応配信(AVIF + srcset + preload)
- クリティカルCSS抽出 + non-criticalの遅延読み込み
- JSコード分割(上位ルート単位)と長タスク分割(scheduler.yield相当)
- CDN preconnect + early hints(103)
結果(中央値):
| 指標 | Before | After | 改善率 |
|---|---|---|---|
| LCP | 3.8s | 2.1s | -44.7% |
| INP | 280ms | 160ms | -42.9% |
| TBT | 450ms | 120ms | -73.3% |
| CLS | 0.12 | 0.04 | -66.7% |
| Score | 58 | 89 | +31pt |
計測安定性:
- 反復係数(σ/μ): 0.06(LCP), 0.08(TBT)
- 再現性を担保するため、ワーカーの同時実行数は1、CPUピン止めを採用
ビジネス効果(概算):
- CVR弾性: LCP 1s短縮でCVR +0.3~0.7pt(社内/公開研究の中央値に基づく参考値。実サイトにより差が大きい)³
- サンプル: 月商1億円、CVR 2.0%→2.5%で月次+2,500万円流入(広告費一定)
- 導入期間: 計測基盤1週、改善スプリント1~2週、合計2~3週で初期効果が顕在化
注意点と失敗しない運用
よくある落とし穴
- 計測条件ドリフト: DevTools/CLI/PSIで条件が異なる。設定をレポートと同梱し、CIからのみ参照。⁵
- キャッシュ・Service Worker影響: Lighthouseは初回訪問前提。既存SWが意図せず適用されないようにURLを隔離。
- 認証/地域差: ログイン後や地域CDNはURL・ヘッダで分離して計測。Accept-Language/Geoヘッダ固定。
- 第三者タグ: ラボで落ちなくとも本番で変動が大きい。遅延読み込み・プロキシ・コンセンサス管理を導入。
- 1回測定信仰: 中央値運用と許容レンジ(±5%)を定義。ベースライン更新は週次に限定。⁸
ガバナンス(パフォーマンスバジェット)
- 予算項目例: LCP≤2200ms、TBT≤150ms、JS初期<=150KB、画像初回<=200KB
- 運用: PR時にLighthouseを回し、逸脱時はCIをFail。例外は一時的ホワイトリストとJira連携。
バジェット定義例(lighthouserc.jsonのsettings.budgets; 参考として記述):
{
"ci": {
"collect": { "numberOfRuns": 3 },
"assert": {
"assertions": {
"categories:performance": ["error", {"minScore": 0.85}],
"largest-contentful-paint": ["error", {"maxNumericValue": 2200}],
"total-blocking-time": ["error", {"maxNumericValue": 150}]
}
}
}
}
実装チェックリスト(導入から定着まで)
- KPIと対象URLの定義(匿名化/安定URL、ログイン後を含めるか判定)
- 計測基盤の固定(Node版 or PSI、3回中央値、Mobile)
- CI統合(PRコメント・Fail条件・アーティファクト保存)
- 可視化(Slack/ダッシュボード/履歴比較)
- 改善バックログ(LCP/INP/TBT起点の具体施策単位で管理)
- 定例レビュー(週次でベースライン更新、月次でROI評価)
ベストプラクティス要約
- ネットワーク: HTTP/2+、画像のAVIF/WebP、preload/preconnect、Early Hints活用
- JS: クリティカル分割、長タスク回避(requestIdleCallback/scheduler)、優先度(fetchpriority)
- レンダリング: critical CSS、フォントpreload+display:swap、CLS抑制の寸法指定¹⁰
- サーバ: TTFB短縮(キャッシュ・Edge SSR)、圧縮(Brotli q11/動的はq5~7)
- ガバナンス: 3回中央値+許容レンジ、予算でゲート、通知と履歴管理
【まとめ(300-500文字)】
Lighthouseは「測る→直す→守る」を自動化する核であり、スコアの意味・測定条件・CIの一体運用がROIを左右する。モバイル想定のシミュレーションを固定し、3回中央値とバジェットで回帰を防げば、LCP/INP/TBTは安定して下がる。コード例のとおり、Node/Puppeteer/PSIを組み合わせた導入は2~3週間で定着する。次の一手として、貴社のKPIに直結するURL選定と、PRでの自動コメント・Fail基準の設定から着手してほしい。最初のスコア改善が出れば、顧客体験と収益の両輪で効果が積み上がる。今、どのURLから測定を始めるか。³⁴
参考文献
- HTTP Archive. The Web Almanac 2023: Core Web Vitals. https://almanac.httparchive.org/en/2023/core-web-vitals
- web.dev. INP: Interaction to Next Paint. https://web.dev/inp/
- Google Search Central Blog. Evaluating page experience for a better web. https://developers.google.com/search/blog/2020/05/evaluating-page-experience
- Google Ads ヘルプ. ランディング ページの利便性(ページ速度などの要素を含む). https://support.google.com/google-ads/answer/9238823
- Chrome for Developers. Lighthouse performance scoring. https://developer.chrome.com/docs/lighthouse/performance/performance-scoring
- web.dev. Largest Contentful Paint (LCP). https://web.dev/articles/lcp/
- web.dev. Cumulative Layout Shift (CLS). https://web.dev/articles/cls/
- web.dev. Differences between lab and field data. https://web.dev/articles/lab-and-field-data-differences/
- PageSpeed Insights ドキュメント. About PageSpeed Insights (v5). https://developers.google.com/speed/docs/insights/v5/about
- web.dev. Font best practices for the web. https://web.dev/articles/font-best-practices/