Meeterboard
Hand-drawn crayon illustration for: How Meeterboard uses Levels.fyi data (sources, cache, limits)

How Meeterboard uses Levels.fyi data (sources, cache, limits)

Technical and editorial explanation of our Levels.fyi integration: fetching, parsing, seven-day cache, snapshots, and what we do not claim.

Published:

Meeterboard's numbers stand on public compensation aggregates from Levels.fyi, not employer payroll integrations. That choice keeps onboarding friction low—you pick company and level instead of uploading HR exports—but it introduces coverage, freshness, and averaging constraints users must understand. This article documents the pipeline honestly for users, reviewers, and your internal finance partners.

What Levels.fyi provides

Levels.fyi publishes salary pages with level bands (e.g. Google L5 Software Engineer) showing average total compensation (TC), often split into base, stock, and bonus. Data comes from user submissions aggregated over time. Meeterboard consumes headline averages per band, not individual submissions.

We are not affiliated with Levels.fyi. Trademarks and data remain theirs.

How we fetch data

Server-side jobs request public HTML salary pages with a browser User-Agent (some endpoints return empty bodies to non-browser clients). We parse embedded `__NEXT_DATA__` JSON from the page—same technique many salary tools use. Parsing code lives in `src/lib/levels/parse.ts`.

Flows:

  1. Company search — slug probes + cached company list + curated seeds
  2. Job families index — `/companies/{slug}/salaries`
  3. Level averages — per family salary detail pages

Your browser never sends personal salary to Levels.fyi through Meeterboard.

Database cache (Supabase)

Parsed rows land in Postgres:

  • `companies` — slug, name, icon metadata
  • `pay_levels` — job family slug, level slug, labels, annual TC, components, `source_updated_at`

`ensurePayLevels()` returns cached rows when younger than seven days. Older rows trigger refresh on next request. Popular companies may be pre-seeded via `npm run seed:levels` or `POST /api/levels/seed`.

Onboarding warm path

First user picking a rare company may wait while `warmCompanyCache()` ingests up to five seed job families. UI shows a warming state ("You're the first…"). Subsequent users hit warm cache.

Meeting snapshots vs live cache

When an attendee joins a meeting, their band's TC copies into `annual_tc_snapshot` on the attendee row. In-flight meetings ignore later Levels.fyi updates for that attendee. New meetings pick up refreshed cache.

Reasons:

  • stable live clock and spectate
  • decisions anchored to join-time assumptions
  • avoids tick jumps mid-meeting

Search and aliases

Company search maps acronyms and legacy slugs (e.g. twitter → x) via `src/lib/levels/company-search.ts`. Not exhaustive fuzzy search across every employer worldwide.

Icons

Company icons prefer `static.levels.fyi` URLs when available (`src/lib/levels/icons.ts`).

What we display in the UI

  • Level labels (primary + secondary names)
  • Average TC formatted compactly ($250K, $1.2M)
  • Per-second cost while ticking (derived, not stored)

We do not show sample counts or confidence intervals from Levels.fyi unless they exist on parsed payload—coverage transparency is limited by source page content.

Error and staleness behavior

Fetch failures fall back to cached data when present. Missing families may show reduced level lists. Hard failures surface user-visible errors on onboarding.

Manual `refreshLevels()` exists for operators (API seed route); everyday users rely on automatic refresh windows.

Limitations (read carefully)

| Topic | Limitation |

|-------|------------|

| Individual comp | Averages only |

| Geo pay | Blended in many bands |

| Equity | Volatile; Levels methodology evolves |

| Non-tech employers | Sparse coverage |

| Contractors | Not modeled |

| Employer load | TC, not benefits + taxes + facilities |

| Business year | 52×40 US shorthand |

Terms restated in Terms of Service.

Privacy intersection

We store which company/level you select and meeting snapshots—not Levels.fyi account data (there is none for visitors). See Privacy Policy.

Reporting issues

Email hello@meeterboard.com with company slug, job family slug, level slug, and screenshot if UI looks wrong. We can force refresh and compare raw Levels page.

For developers auditing the repo

Key paths:

  • `src/lib/levels/parse.ts` — fetch + parse
  • `src/lib/levels/ingest.ts` — cache upsert + TTL
  • `src/app/actions.ts` — server actions wrapping ingest
  • `supabase/migrations` — schema

Methodology page: How it works.

Using data responsibly

Do not cite Meeterboard totals as official company spend in external communications without caveats. Prefer "illustrative labor estimate based on Levels.fyi averages."

Next

Meeting cost by company — how employer choice moves dollars

Calculator guide — user-facing walkthrough

Versioning cached rows

When Levels.fyi updates level taxonomy (splitting L5 into L5/L5+), slugs may shift. Meeterboard ingests what the public page shows; historical meetings keep old snapshots. Researchers comparing year-over-year meeting cost should note taxonomy drift.

Open-source audit trail

Developers can inspect `src/lib/levels/parse.ts` and migrations in our repository to verify we do not exfiltrate meeting content to Levels.fyi. Only server-side HTTP GETs to public salary URLs occur—no POST of user profiles to Levels.

Rate limits and polite fetching

We batch seed jobs and respect failure backoff to avoid hammering Levels.fyi. First visitor latency on uncached companies is a feature of polite architecture, not neglect.

Alternate data sources (not integrated)

Some teams ask about Radford, Option Impact, or internal comp bands. Meeterboard does not integrate them in v1—manual TC entry is intentionally omitted to keep onboarding honest to public benchmarks. Enterprise custom bands may be a future product direction; today use spreadsheet sidecars if needed.

Academic use

Researchers studying meeting culture may cite Meeterboard methodology with attribution. Cite formula and Levels.fyi source; do not cite live leaderboard totals as representative samples without statistical treatment—they reflect self-selected users.

Try the calculator

Pick your company and level, add attendees, and watch the bill climb in real time.

Open Meeterboard →

All articles· How it works· FAQ