Skip to content

Beyond the panel

Share & automate

What BevTools records can leave the in-app panel: into a window of its own, into the browser's DevTools, into a file a colleague opens, and into CI. Every one of them reads the same data through the same redaction, so none shows more than the panel does.

Three frontends, one protocol

In each .NET runtime BevTools records what happens and answers questions about it (BevToolsProtocol). A script on the page, the page hub, keeps one target per runtime that rendered a <BevToolsPanel /> - a Blazor Server circuit and the WebAssembly runtime can share a page - and three frontends read it:

FrontendWhereWhat it is best at
In-app panelInside the app, on every host: Server, WebAssembly, Auto, Blazor HybridLive object inspection, the profiler's batch views, panels that extensions contribute, nothing to install
Companion window⧉ in the panel header: a window of its own, same originEvery runtime of the page at once; renders nothing into the app, so on Blazor Server it adds no render batches to the circuit it measures; opens exported sessions offline
Browser extensionA Blazor panel in Chromium or Firefox DevToolsThe companion where developers already look; follows the Elements panel's selection (Chromium); no permissions, no content script
Live Renderer: Static · prerendering CtrlShiftD opens BevTools
Open the companion window

Ask the page hub does what the companion and the extension do: it lists the targets with window.__BIT_BEVTOOLS__.targets() and asks each one hello. The link opens the companion the way ⧉ does; a runtime appears in it once its panel has rendered. Set Ui.ShowBadge = false to keep the in-app panel out of sight and use only the companion or the extension.

Share what you found

About exports the session three ways, the same as >export, >report and >trace in CtrlK:

  • Export session (JSON): everything the panels show, in the bit-bevtools/1 format. The companion opens it offline (Open file, or drop it on the window), Profiler → Compare… compares against it, and bevtools checks it in CI.
  • Copy report (Markdown): the findings, the errors and their groups, the busiest endpoints and the costliest components, ready for an issue.
  • Export performance trace: the timeline in the Chrome Trace Event format, which ui.perfetto.dev and the Chrome DevTools Performance panel open as they are - render batches with each component's render nested inside, UI events, navigations, requests and interop calls on tracks of their own, and arrows from each event to what it caused. Export performance trace since the profiler baseline in the palette keeps only what happened after the last Reset.

Each contains exactly what the panels show, with the same redaction; browser storage previews are left out. To keep a busy app from pushing what you are reading out of the buffers first, pause capture (⏸ Pause in the header, or >pause): errors are still collected, and the resume marker says how many renders were skipped.

The browser extension

# from src/Utilities/BevTools
dotnet build Bit.BevTools                    # builds the companion bundle the extension hosts
cd Bit.BevTools.Extension && node build.mjs   # assembles the unpacked extension in dist/

Load dist/ unpacked (chrome://extensions → Developer mode → Load unpacked, or Firefox's about:debugging → Load Temporary Add-on), open DevTools on this site and pick the Blazor panel. It reaches the page only through DevTools while DevTools is open on the tab.

Compare two recordings

Profiler → Compare… reads an export from before a change and compares each component type with what has rendered since: regressed, improved, new or gone, with its renders and time before and after, warnings when the two recordings differ in how they were made, and Copy as Markdown. Render counts are compared exactly; times only beyond 5 ms and 50 %, because they vary between runs. The Products page has a fix to measure this way.

Fail a build on what BevTools found

The bevtools .NET tool (Bit.BevTools.Cli) reads export files - never a running app - writes Markdown and exits with 1 when the check fails (2 when an input cannot be read):

dotnet tool install --global Bit.BevTools.Cli

# the rules' findings: warnings and errors fail by default
bevtools check checkout.session.json --fail-on warning --ignore render.storm --report "$GITHUB_STEP_SUMMARY"

# a component type that renders more often, or clearly longer, than in the baseline
bevtools compare checkout.baseline.json checkout.session.json

Most rules look back 10 to 60 seconds when they run, so for a recording you will check, set o.Diagnostics.EvaluateWhileClosed = true: the rules then run as the app is used, not only while the panel is open. In a test, BevSessionCheck.Check(json) and BevProfileComparison.Compare(baseline, current) do the same without the tool.

A tool of your own

The page hub is the one way in for a frontend outside the panel, and it exists only while an enabled runtime is attached. A request goes to one runtime and comes back as JSON:

const hub = window.__BIT_BEVTOOLS__;
for (const target of hub.targets()) {
    const hello = await hub.request(target.id, "hello");
    // snapshot (the bit-bevtools/1 export, by section, or the timeline after an event id),
    // inspect, expand, command and export: documented on BevToolsProtocol
    const snapshot = await hub.request(target.id, "snapshot", { sections: ["diagnostics"] });
}

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please retry or reload the page.

An unhandled error has occurred. Reload 🗙