npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ajperezbau/msw-devtools

v1.4.1

Published

A powerful browser-based UI for managing Mock Service Worker (MSW) handlers. Framework-agnostic — works with Vue, React, Svelte, and Vanilla JS.

Readme

MSW DevTools

A powerful browser-based UI for managing Mock Service Worker (MSW) handlers. Framework-agnostic. Dynamically switch between response scenarios, override responses on the fly, and inspect network activity handled by MSW.

Features

  • 🛠 Dynamic Scenario Switching: Define multiple response scenarios for a single endpoint and switch between them without reloading.
  • 🌐 Passthrough Mode: Instantly bypass mocks and forward requests to the real API. Toggle globally (saving your previous mock states) or set it per-handler.
  • ⏺️ Response Recording: Opt-in recording mode to capture and inspect real API responses directly in the Activity Log.
  • ✍️ Manual Overrides: Edit response status codes and bodies (JSON or Text) directly in the browser.
  • Network Simulation: Set global or per-handler delays to simulate different network conditions.
  • 📋 Activity Log: View a history of all requests handled by MSW, including request/response bodies with JSON path filtering.
  • 🔌 Zero-Config Discovery: Automatically detects existing MSW handlers without changing your code.
  • 💾 Persistence: All your settings (active scenarios, delays, overrides) are persisted in localStorage.
  • 🔗 URL Parameters Sync: Deep-link to specific mock scenarios using URL query parameters.
  • Custom Scenarios: Save manual overrides as reusable custom scenarios.
  • 🍱 Presets: Group multiple handler scenarios into "Recipes" to replicate complex application flows.

Installation

npm install @ajperezbau/msw-devtools
# or
pnpm add @ajperezbau/msw-devtools

Setup

Step-by-Step Integration

You can integrate the devtools with a single line in your application entry point:

import { setupWorker } from "msw/browser";
import { initMswDevtools } from "@ajperezbau/msw-devtools";

// 1. Setup MSW as usual
const worker = setupWorker();
await worker.start();

// 2. Initialize the devtools — worker is required
if (process.env.NODE_ENV === "development") {
  initMswDevtools({
    worker, // required
    // Optional: useful to modify the URLs as needed
    urlResolver: (url) => new URL(url, "https://some-base-url").toString(),
    // Optional: in QA you can start every handler in Real API mode
    initialScenarioMode: "passthrough",
    // Optional: hide the floating launcher until the user enables it again
    initialShowToggle: false,
    // Optional: shorthand that applies the same storage mode to everything
    persistence: "session",
  });
}

QA-Friendly Defaults

If you want to expose the devtools in a shared QA environment, use the runtime policy options in initMswDevtools() instead of changing each handler definition:

  • initialScenarioMode: "handler-default" | "passthrough" controls the scenario used when there is no URL override and no persisted state.
  • persistence accepts either a string shorthand or a bucketed object.

Recommended QA setup:

initMswDevtools({
  worker,
  initialScenarioMode: "passthrough",
  initialShowToggle: false,
  persistence: {
    runtimeState: "session",
    userPreferences: "local",
    authoredData: "local",
  },
});

This keeps the tool available for everyone while making Real API mode the default baseline, and still preserves changes across page reloads during the current browser session. If the user knows the keyboard shortcut, they can still open the panel and re-enable the floating launcher from inside the devtools.

Persistence Buckets

persistence supports two forms:

type StorageMode = "local" | "session" | "none";

initMswDevtools({
  worker,
  persistence: "session",
});

initMswDevtools({
  worker,
  persistence: {
    runtimeState: "session",
    userPreferences: "local",
    authoredData: "local",
  },
});
  • runtimeState: active scenarios, delays, overrides, global passthrough snapshot.
  • userPreferences: theme, floating toggle visibility and position, registry filters.
  • authoredData: custom scenarios and custom presets.

Toggle Launcher Visibility

Use initialShowToggle when you want the keyboard shortcut to be the only entry point on first load:

initMswDevtools({
  worker,
  initialShowToggle: false,
  persistence: {
    runtimeState: "session",
    userPreferences: "local",
    authoredData: "local",
  },
});
  • initialShowToggle only defines the initial recommendation.
  • If the user changes the launcher visibility from inside the panel, that preference is stored in userPreferences and takes precedence on later loads.
  • The keyboard shortcut remains available even when the floating launcher is hidden.

If you pass a string, the same storage mode is used for all buckets. If you pass an object, any omitted bucket falls back to local.

Zero Config Discovery

The plugin automatically detects any existing handlers you have already registered in your MSW worker. They will appear in the DevTools UI under a default scenario named "default", allowing you to immediately:

  • Set delays for existing handlers.
  • See them in the Activity Log.
  • Apply manual overrides.

No changes are needed to your existing MSW code beyond the initial setup!

Defining Handlers

Use defineHandlers to create handlers with multiple scenarios, then pass them to your MSW worker.

import { defineHandlers } from "@ajperezbau/msw-devtools";
import { setupWorker } from "msw/browser";
import { HttpResponse } from "msw";

// Define handlers with multiple scenarios
const devtoolsHandlers = defineHandlers({
  users: {
    url: "/api/users",
    method: "get",
    scenarios: {
      success: () => HttpResponse.json([{ id: 1, name: "John" }]),
      empty: () => HttpResponse.json([]),
      error: () => new HttpResponse(null, { status: 500 }),
    },
  },
});

// Pass the handlers to MSW worker
const worker = setupWorker(...devtoolsHandlers);
await worker.start();

Why defineHandlers?

While Zero Config Discovery is great for getting started, using defineHandlers offers several key advantages:

  • 🏗 Multiple Scenarios: Auto-discovery only captures the "original" behavior. defineHandlers allows you to define multiple states (e.g., success, error, loading) for the same endpoint.
  • 🏷 Custom Labeling: Instead of seeing [GET] /api/very/long/path/to/users, you can identify the handler with a simple, readable key like users.
  • 🎯 Preset Integration: Readable keys make it much easier to define and manage Presets in your codebase.
  • ⚙️ Default Scenarios: Specify which scenario should be active when the application starts.
  • 🔝 Explicit Priority: Fine-tune the matching order for overlapping routes.

Advanced Usage

Priority Handling

Handlers with higher priority will be matched first by MSW. Use the priority property in the handler configuration.

const handlers = defineHandlers({
  getUserAdmin: {
    url: "/api/user/admin",
    method: "get",
    priority: 10,
    scenarios: {
      default: () => HttpResponse.json({ role: "admin" }),
    },
  },
});

// Pass to MSW
const worker = setupWorker(...handlers);

Global Presets (Recipes)

Sometimes you want to set the state of multiple handlers at once to replicate a specific application flow (e.g., "First Time Journey", "Subscription Expired", "Admin Dashboard").

Defining Presets in Code

Use definePresets to register predefined configurations.

import { definePresets } from "@ajperezbau/msw-devtools";

definePresets([
  {
    name: "New User Journey",
    description:
      "Sets all user-related handlers to 'empty' or 'first-time' scenarios",
    scenarios: {
      users: "empty",
      profile: "first-login",
      notifications: "none",
    },
  },
  {
    name: "Happy Path - Premium",
    scenarios: {
      users: "success",
      billing: "active-subscription",
    },
  },
]);

Creating Presets from UI

The easiest way to create a preset is directly from the Registry tab:

  1. Click the Create Preset icon (list icon) in the top-right toolbar.
  2. Select the handlers you want to include (you can use the "Select Visible" checkbox in the header or click individual rows).
  3. Adjust the active scenarios for the selected handlers if needed.
  4. Enter a name in the selection toolbar and click Save Selected.

The app will automatically switch to the Presets tab where you can see and apply your new group.

These presets are persisted in localStorage and can be exported/imported along with your other configurations.

Global Delay

You can control network latency globally or per handler from the Devtools UI.

UI Usage

Once installed, a floating gear icon will appear in your application.

  • Global Passthrough: Click the globe icon in the header to instantly bypass all mocks (Real API mode). The tool takes a smart snapshot of your active scenarios and restores them when you disable the passthrough.
  • Record Passthrough: When passthrough is active, a red record button appears. Enabling it captures the real API responses so you can inspect them in the Activity Log or easily save them as new manual overrides. (Note: This duplicates requests in the browser's native Network tab).
  • Registry Tab: View all registered handlers, change active scenarios, set individual delays, and create Presets using selective grouping.
  • Activity Log Tab: See real-time request logs. Click on an entry to inspect request/response bodies.
  • Presets Tab: View and apply saved groups of scenarios ("Recipes") to instantly change your app's state.
  • Manual Override: Click the edit icon on any handler to manually define a fixed response.
  • Apply & Reload: Some changes might require a page reload to ensure consistency.

Keyboard Shortcuts

  • Ctrl + Shift + M: Toggle Devtools panel.
  • Ctrl + Enter: Apply changes and reload page (when panel is open).

Development

This project uses pnpm as its package manager. Please ensure you have it installed before contributing.

pnpm install
pnpm dev
pnpm test