Getting Started
This guide walks you through onboarding a repo to report its Lighthouse scores to a
self-hosted LHCI server: installing the CLI, registering your repo as a project, wiring
your lighthouserc.js upload config, and adding a CI step that runs on every PR.
Throughout this guide, replace https://your-lhci-server.onrender.com with the URL of
your own deployed LHCI server.
Prerequisites
- A deployed LHCI server (see the Skills Catalog if you still need to stand one up).
- The server's basicAuth credentials (
LHCI_BASIC_AUTH_USERNAME/LHCI_BASIC_AUTH_PASSWORD). These gate every route on the server, including the build-upload endpoint - not just the dashboard. - Node.js and a repo you want to track Lighthouse scores for.
1. Install the CLI
Install @houses/lighthouse-cli globally to get the lhci-toolkit binary:
npm install -g @houses/lighthouse-cli
2. Register your repo
Register your repo as a project on the server. This prints a build token (for CI) and a one-time admin token (save it somewhere safe - it's the only way to rename or delete the project later, and it's shown exactly once):
lhci-toolkit --server-url=https://your-lhci-server.onrender.com \
--admin-username=<username> --admin-password=<password> \
register <repo-name>
--server-url- base URL of your deployed LHCI server (required).--admin-username/--admin-password- the server's basicAuth credentials. These are required if the server has basicAuth enabled: registration hits the same gate as the dashboard and 401s without them.register <repo-name>also accepts an optional--base-branch <branch>flag (defaults tomain) to set the base branch used for diff comparisons.
You can list every project already registered on the server with:
lhci-toolkit --server-url=https://your-lhci-server.onrender.com \
--admin-username=<username> --admin-password=<password> \
list
3. Wire lighthouserc.js
In the repo you just registered, add a lighthouserc.js. The server's basicAuth is
mounted in front of every route, including the build-upload endpoint - so the upload
block needs both token and basicAuth. Omitting basicAuth produces a 401 in CI
even with a correct, valid build token:
module.exports = {
ci: {
collect: {
url: ['http://localhost:3000/'],
startServerCommand: 'npm run start',
},
upload: {
target: 'lhci',
serverBaseUrl: 'https://your-lhci-server.onrender.com',
// Project-specific - printed by `lhci-toolkit register` in step 2.
token: process.env.LHCI_BUILD_TOKEN,
// Server-wide - the same credentials used to register the project.
// Shared across every onboarded repo, not regenerated per repo.
basicAuth: {
username: process.env.LHCI_BASIC_AUTH_USERNAME,
password: process.env.LHCI_BASIC_AUTH_PASSWORD,
},
},
},
};
Adjust collect.url / startServerCommand to match how your app builds and serves
locally.
4. Add the GitHub Actions CI step
Add a workflow that runs npx @lhci/cli autorun, with three repo/org secrets set as env
vars: LHCI_BUILD_TOKEN (project-specific, from step 2) and
LHCI_BASIC_AUTH_USERNAME / LHCI_BASIC_AUTH_PASSWORD (server-wide, shared across every
onboarded repo). Also set GITHUB_TOKEN on the upload step so LHCI posts its score and
comparison link directly on the PR, instead of only a link in the Actions log:
name: Lighthouse CI
on:
pull_request:
push:
branches: [main]
jobs:
lhci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm run build
- run: npx @lhci/cli autorun
env:
LHCI_BUILD_TOKEN: ${{ secrets.LHCI_BUILD_TOKEN }}
LHCI_BASIC_AUTH_USERNAME: ${{ secrets.LHCI_BASIC_AUTH_USERNAME }}
LHCI_BASIC_AUTH_PASSWORD: ${{ secrets.LHCI_BASIC_AUTH_PASSWORD }}
# Enables LHCI's automatic PR status check (score + comparison
# link posted on the PR itself) instead of only a log link.
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5. Verify it worked
- Confirm registration succeeded: re-run the
listcommand from step 2 and check that your repo shows up by name. - Confirm the upload config is correct: run
npx @lhci/cli autorunlocally withLHCI_BUILD_TOKEN,LHCI_BASIC_AUTH_USERNAME, andLHCI_BASIC_AUTH_PASSWORDset - it should complete with an uploaded-report URL, not a 401. - Confirm CI is wired correctly: open a real pull request and check that the Lighthouse
CI workflow run goes green with a report link, and that a Lighthouse status check with
a score appears directly on the PR (thanks to
GITHUB_TOKENin step 4).
If the upload step 401s in CI despite a build token that worked when pasted straight
after register printed it, double check that upload.basicAuth is set in
lighthouserc.js - the server-wide gate, not the token, is what's rejecting the request.