Capture
July 18, 2026 · View on GitHub
- Introduction
- Capturing Frame Data
- Saving and Loading Captures
- Reopening a Capture in a New Tab or Window
- Frame Commands
- Render Pass Textures
- Command Stacktrace
- Command Inspection
- Uniform and Storage Buffer Inspection
- Vertex Buffer Data
- Pixel History
- Debug Groups
- Frame Stats
- Shader Debugger
Introduction
Back to top
Capture all rendering commands used to render a frame, letting you inspect each command, as well as providing information about the rendering state at each command. It also captures the image results of each render pass.
Capturing Frame Data
Back to top
Press the Capture button to capture a frame from the page.
Capture Mode
Capture has two modes: Immediate and Specific Frame.
Immediate Capture

Immediate capture will record the current frame on the page.
Frames indicates how many frames to capture.
Specific Frame Capture

Specific frame capture will record a specific frame from the load of the page. Using this capture mode will cause the page to refresh, and start recording at the indicated frame.
A start frame of 0 will record all commands from the start of the page load, including those outside of a requestAnimationFrame frame. This allows you to capture commands for pages that do not use requestAnimationFrame.
Frames indicates how many frames to capture once it has started recording.
For pages that do not use requestAnimationFrame, the Frames value does not do anything. In that case, recording will continue until the GPU device has been destroyed or garbage collected, or you press the inspector overlay on the page to stop the recording.
Max Buffer Size
The Max Buffer Size value specifies the maximum buffer size Capture will record, for Uniform and Storage buffers. Sending buffer data to the DevTools panel can be slow, so limiting the buffer size can help capture performance. Large buffers are typically used for storage buffers.
Stacktraces
The Stacktraces checkbox controls whether a stacktrace is recorded for each captured command. It is off by default, because recording a stacktrace per command can significantly increase the size of a capture for frames with many commands. Enable it when you need to know where in the page's code a command was issued. See Command Stacktrace.
Profile Passes
The Profile Passes checkbox injects GPU timestamp queries around each render and compute pass so the capture can report per-pass GPU duration. It is on by default.
This requires the page's adapter to support the timestamp-query feature. If the adapter doesn't grant it, the injection is silently skipped and no timing data is produced.
When timing data is available, it is presented in several places:
- A GPU pass timeline at the top of the frame's command list, showing each render/compute pass as a bar sized to the fraction of the frame it took. A dashed frame-budget marker shows where the display refresh interval falls, so you can see how much of the budget the GPU work fills — passes crossing the marker mean the GPU can't keep up with the refresh rate.
- Each pass header in the command list is annotated with its
Duration:<N>ms. - The Frame Stats panel includes a Frame Bound card and a Pass Timings breakdown.
The Frame Bound card estimates whether the frame is CPU-, GPU-, or vsync-bound by comparing the main-thread submit time and the total GPU time against the frame budget (the display refresh interval), with bars showing each against the budget. The CPU submit time and frame budget come from the live page's frame metrics, so the verdict is most meaningful for captures taken from a running page; GPU time comes from the pass timestamps.
Because the timing data travels with the capture, the timeline, pass timings, and Frame Bound card also appear for saved/loaded captures.
Note
Frame capture works best when requestAnimationFrame is used, as Capture uses that to identify what commands to capture for a frame. Immediate capture will not work without requestAnimationFrame. In that case, use Specific Frame capture with frame 0, to start recording after page load.
Saving and Loading Captures
Back to top
Captures can be saved to disk as a file and re-opened later in the panel. This is useful for sharing a frame capture in bug reports, comparing captures from different builds, or returning to a capture after closing the DevTools.
The Save / Load actions live in the hamburger (☰) menu on the left side of the Capture panel's toolbar, next to the Capture button.
Save Capture
Save Capture is enabled whenever a capture tab is active. Selecting it downloads the active tab as a webgpu_capture_frame_<N>.wgpuc file, where <N> is the captured frame index.
The file is a binary container: an ASCII WGPUCAP header line and the capture metadata as JSON (both readable if you open the file in a text editor), followed by the raw buffer/texture payload bytes. Storing the payloads as raw binary instead of base64-encoded JSON keeps files ~25% smaller and lets even very large captures save without memory pressure. The file contains everything the panel needs to fully reconstruct the capture:
- The full GPU object graph (adapters, devices, buffers, textures, texture views, samplers, bind groups, bind group layouts, pipeline layouts, render and compute pipelines, render bundles, shader modules) with their descriptors and stacktraces.
- The recorded command list for the frame, with arguments, results, and captured stacktraces.
- The image data for each render pass color/depth attachment that was read back during capture, stored as per-mip payload data on the corresponding Texture record.
- The buffer data captured for
setVertexBuffer,setIndexBuffer, indirect draws/dispatches, and any Uniform / Storage buffer bound for inspection, attached to the command record it belongs to. - Validation errors raised during the capture.
The file is self-contained, so once saved it can be shared and opened on any machine without needing the original page.
Load Capture
Load Capture opens a file picker; selecting a previously-saved capture file opens it as a new tab in the Capture panel alongside any live or already-loaded captures. Both the binary .wgpuc format and the older JSON / NDJSON capture files are accepted. The loaded tab supports all of the same inspection features (command list, render pass thumbnails, BindGroup / vertex buffer / pipeline inspection, frame stats), driven entirely off the data in the file.
Imported textures with serialized image data are uploaded back onto the inspector's WebGPU device when the tab is built, so render-pass thumbnails and BindGroup texture previews render the same way they did in the original live capture. Textures that didn't have image data captured (e.g. resources that weren't bound or written to as an attachment) show their descriptor without a preview.
Each imported capture lives in its own ID namespace, so loading multiple captures (or loading a capture while a live capture is also open) won't cause object ID collisions between them.
Capturing Outside DevTools
The same capture format can also be produced without the DevTools panel by loading webgpu_inspector.js directly via a <script> tag and using the page-side capture API (initialize() / beginFrameCapture() / endFrameCapture() / saveCaptureData()). Files produced that way are loadable here through Load Capture the same as panel-produced files. See the Local Capture API for the script-side workflow.
Reopening a Capture in a New Tab or Window
Back to top
Right-clicking on a capture tab handle opens a context menu with two actions for duplicating the capture without going through a file on disk:
- Open in New Tab — Serializes the active capture to the same data Save Capture would write, then immediately re-imports it as a fresh tab in the Capture panel. The new tab is fully independent of the original (its own ID namespace, its own selection state) and survives the original tab being closed.
- Open in New Window — Same serialization, but the result is handed off to a new browser window loading the inspector panel as a standalone page. Useful for putting two captures side-by-side across monitors, or keeping a reference capture visible while you continue capturing in DevTools.
Both actions operate purely in memory — nothing is written to the filesystem. The "Open in New Window" handoff goes through IndexedDB (rather than localStorage) so captures larger than a few megabytes — including ones with full mip data for render-pass attachments — transfer cleanly.
The standalone window opened by Open in New Window is a viewer: it loads the capture and provides the same inspection features as a loaded capture file, but it isn't attached to a DevTools-inspected page, so the Inspect and Record tabs won't show live data there. Use the original DevTools panel for live capture and inspection.
Frame Commands
Back to top
Capture will record all GPU commands issued during a frame, including their arguments, and the stackrace of where it was called.
Selecting a command will display information about the command, including associated GPU objects.
Render Pass Textures
Back to top
The color and depth-stencil texture attachments of Render Passes will be captured and displayed in the capture panel.
Selecting a Render Pass image will select the associated beginRenderPass command.

Command Stacktrace
Back to top
When the Stacktraces capture option is enabled, each command records the stacktrace of where it was executed. The stacktrace is shown in the command's inspection panel. Stacktraces are off by default — see Stacktraces under Capturing Frame Data.

Command Inspection
Back to top
Selecting a command will display information about the command, including its arguments and information about objects related to the command.

Uniform and Storage Buffer Inspection
Back to top
If you select a Draw or Dispatch command, it will inspect the BindGroups and Pipeline active for the command. It will inspect the Buffer objects associated with the BindGroups, and parse their data based on the shaders associated the the Pipeline. This lets you inspect buffer data as the shader will see it during the Draw or Dispatch command.
Affected By lists the commands that have written to this particular buffer.
Format lets you customize the format of the buffer data. See Formatting Buffer Data for more information.
Array Data
Array data can be quite large. To improve performance and readability, if the array has more than 100 elements, only a subset of array data is viewed.
Offset is the starting index of the array to view.
Count is the number of elements of the array to view.
Vertex Buffer Data
Back to top
If you select a Draw command, it will inspect any Vertex Buffers bound for the draw call. It will parse the data from the RenderPipeline descriptor, and the shader, to present the data as the shader will see it.
Pixel History
Back to top
Pixel History traces every draw in the captured frame that touched a single pixel of a render-pass attachment, similar to RenderDoc's pixel history. It answers questions like "why is this pixel the wrong color?", "which draw overwrote my geometry?", or "why did my object not render here?".
Select a beginRenderPass, draw, or end command and press the Pixel History button next to one of the pass's color or depth-stencil attachments. This opens the attachment in a capture texture viewer tab:
- The image shows the texture's most recently captured contents (a note is shown if a later pass in the frame also writes it). The viewer has the same display controls as the Inspector's texture viewer: Zoom (a percentage, also CTRL + mouse-wheel), Exposure, a channel selector (RGB / Red / Green / Blue / Alpha / Luminance), and Auto Range for HDR and depth content. Hovering the image shows a tooltip with the pixel coordinates and value.
- Click a pixel to select it — its history is computed automatically and shown in the panel on the right. Click other pixels to explore.
The history panel lists, in order, every event in the frame that touched the selected pixel of that texture:
- The pass's clear or load value, labeled with the render pass's
labeland the debug groups it is nested in, when present. - Every fragment generated at the pixel — the draw command, its shader module's
label(when set), the primitive (triangle) index and instance — together with what happened to it: the value it wrote (with the shader's output and blend result when blending is enabled), or the reason it didn't contribute: failed the depth or stencil test, outside the scissor or viewport, depth clipped, discarded by the fragment shader, or masked out by the target's write mask. Backface/frontface-culled fragments are counted in the summary but not listed (every pixel of a closed mesh sees its backfaces) — unless culled fragments are all that touched the pixel, where they are shown collapsed, since "it was culled" is then the answer to why nothing rendered. - The value at the end of each pass.
Each fragment entry has a Go to button that jumps to the draw command in the command list, and a Debug button that opens the fragment shader debugger pre-seeded with that pixel, instance and primitive — so you can step through exactly the fragment you're looking at, even if it was later overdrawn or failed a test.
Overdraw
The viewer's Overdraw checkbox overlays a heatmap of how many fragments the frame rasterized at each pixel of the texture, from green (1×) through red to white (8× or more). Counts are fragments after face culling, viewport, scissor, and depth clipping, but before the depth/stencil tests and the fragment shader — the pixel's fragment-shading cost — so depth-test failures and discard do not reduce them. Hovering a pixel shows its exact count in the tooltip, and clicking it still opens its full pixel history.
The overlay is computed by GPU replay: the frame's draws are re-executed on the DevTools panel's own GPU device, re-creating the pipelines, buffers, and bind groups from the capture, with each draw's original vertex stage but a stub fragment shader that additively counts fragments. This makes it fast on heavy frames and counts indirect draws, whose argument buffers are captured. Because it replays the captured buffer bytes, large buffers truncated by Max Buffer Size replay with incomplete contents — the overlay reports this; capture with a larger limit for faithful geometry. Draws that can't be re-created (e.g. render bundles, or resources that weren't captured) are excluded from the counts and reported. When GPU replay isn't possible, the overlay falls back to a CPU simulation using the pixel-history interpreter, which is slower on geometry-heavy frames and skips indirect draws; the status line shows which engine produced the counts. Either way the result is cached for the viewer tab.
Pixel history is computed by re-running the pass's vertex and fragment shaders on the inspector's CPU WGSL interpreter and re-doing the rasterizer's work (triangle coverage, perspective-correct interpolation, depth/stencil tests, blending) at the selected pixel. When a pass loads an attachment instead of clearing it, the earlier passes in the frame that wrote that texture (including depth pre-passes) are replayed at the pixel first, so the depth test and blending see the right prior state.
To keep this fast on geometry-heavy frames, the frame's draws are first GPU-replayed with a 1×1 scissor at the pixel and an occlusion query per draw (the same replay layer the Overdraw view uses, with culling disabled so culled-but-covering draws are still found) — the CPU interpreter then only simulates the draws that actually rasterized fragments at that pixel. When GPU replay isn't possible, every draw is simulated.
Because it is a CPU simulation of the frame capture, it has some limitations:
- All vertex/index buffers used by the pass need to have been captured (see Max Buffer Size).
- Indirect draws and render bundles are reported in the history but not simulated.
- Multisampled attachments are simulated at pixel centers with a single sample.
- If an attachment is loaded and the frame never establishes its value (its content comes from a previous frame), values that depend on it are reported as unknown.
- Sampled textures use their most recently captured contents, which can differ from their contents at the time of an earlier draw.
Debug Groups
Back to top
If the page pushes/pops Debug Groups, they will be used to group commands in the capture. This is useful for organizing rendering commands to make it easier to identify what the commands are contributing to the render.
Frame Stats
Back to top
The Capture tool can provide various statistics about the capture. Press the Frame Stats to show the capture statistics. These include how many graphics commands were called; how many draw calls; and so on. When Profile Passes is enabled, Frame Stats also includes a Frame Bound card (CPU-/GPU-/vsync-bound verdict with CPU/GPU-vs-budget bars) and a Pass Timings breakdown of per-pass GPU duration.
Shader Debugger
Back to top
Frame captures include the ability to debug shaders. This is an experimental feature.