| name | web-performance |
| description | Find and fix why a website is slow by capturing and analyzing a Firefox performance profile, or by analyzing a profile the user already has (a saved file or a profiler.firefox.com share link). Use for slow page loads, janky scrolling or animation, slow interactions or a slow STR, long tasks, layout thrashing, or heavy JavaScript. |
Work from a real profile, find the cause in the user's code, report it honestly, and if asked, fix it and prove the fix worked. The firefox-devtools MCP drives Firefox and records a profile when there is none yet; profiler-cli queries the profile, whether you captured it or the user brought it. Report in web-platform terms (LCP, main-thread blocking, reflow, render-blocking resources), not Gecko internals - unless the target is Firefox itself rather than a page, in which case platform frames are the subject and the fix lands in mozilla-central.
Step 0: Prerequisites
profiler-cli needs Node.js >= 24:
command -v profiler-cli >/dev/null 2>&1 || npm install -g @firefox-devtools/profiler-cli@latest
npx @firefox-devtools/profiler-cli@latest also works but re-resolves on every call.
The rest of this step is only for capturing. Skip it when the user already has a profile.
The profiler tools need Firefox 154+. Check with get_firefox_info, which also launches it. If Firefox is missing or older, stop and ask the user to install a current release or point the server at one with --firefox-path. The profiler tools also need the developer tool preset: if profiler_start is absent, ask the user to restart the server with --tool-preset developer, since the default basic preset has no profiler.
Step 1: Pick the scenario
If the user already has a profile - a saved .json.gz, or a share.firefox.dev / profiler.firefox.com link - there is nothing to capture: skip to Step 3 and load it directly. Ask what they were doing while it recorded, since the capture type decides the entry point in the playbook. Verifying a fix (Step 6) still needs a capture, so if you cannot reach their setup, hand them the recipe and ask for an after profile.
Otherwise ask if unclear: page load, interaction / STR (one slow action), or ongoing jank (scroll stutter, dropped frames, CPU pinning). Each has a recipe in references/capture-recipes.md.
Step 2: Capture
Follow that recipe. Keep the window tight - start late, stop early - and keep the profile path profiler_stop returns.
Step 3: Analyze
- Run
profiler-cli guide and read the entire output; it is the command reference for everything below. Do not skim, and make sure that Bash did not truncate it.
profiler-cli load <path>, or profiler-cli load <share-url> for a profile the user shared.
- Work through
references/analysis-playbook.md: thread selection, the entry point for each capture type, and a symptom-to-command map.
Run the commands and interpret the output yourself; do not print commands for the user to run.
Step 4: Find the cause in the source
Grep/Glob/Read the project for the code behind a hot function or request, and confirm the mechanism. If you cannot connect a finding to real source, say so instead of inventing a code path.
Step 5: Report with explicit confidence
Label every finding:
- Confirmed - in the profile and cross-checked (stack traced to source, a measured before/after, a
performance.measure you captured). State the evidence.
- Likely - strong single-source evidence, not cross-checked. Say what would confirm it.
- Hypothesis - a plausible reading of ambiguous data. Say so, and how to validate it.
If sampling is sparse, the window was wrong, or the time is mostly idle, call it inconclusive and re-capture instead of guessing.
Per finding: what is slow -> evidence (function/marker/request and its cost) plus confidence -> why -> the fix in the developer's terms. Biggest confirmed wins first.
When a "likely" or "hypothesis" finding is worth acting on, get more evidence first. references/validation.md covers instrumenting the page with User Timing and reading navigation, resource, paint, LCP and Event Timing entries.
Step 6: Fix and verify
Implement only if asked, keeping the change minimal and tied to the confirmed finding. Then re-capture like-for-like (see the before/after section of the recipes) and compare the metric that was slow. Quantify the gain; if it did not improve, or something else regressed, say so and reconsider.
Step 7: Clean up
profiler-cli stop - the daemon holds a port and memory until stopped. Stop the Firefox profiler if profiler_is_active, and remove instrumentation you injected unless the user wants it kept.