Hold, edit, and mock HTTP traffic for one tab — from a side panel, with no backend.
Mockingbird works on one tab at a time — the tab you “arm.”
Every request the armed tab makes appears newest-first: method, path, host, status, and duration. Click a row to open its detail — request line, query params, headers, response/request bodies (pretty-printed JSON), and a timing breakdown.
4xx+ errors chip.A mock returns a synthetic response without touching the network. Fastest path:
GET, Mockingbird fetches it in the background to seed the editor.)Mocks are an ordered list, first match wins — reorder with the ▲▼ buttons, toggle each on/off, and set optional latency (seconds) to simulate a slow endpoint.
OPTIONS preflights) so a mock for a third-party API isn’t blocked by the browser. Set your own Access-Control-Allow-Origin to override.Mock bodies (and header values) can contain {{ … }} tokens that are filled in per request — so one rule behaves like a real API instead of returning a frozen blob. No eval, no scripting; just a fixed set of lookups and helpers.
| Token | Resolves to |
|---|---|
{{request.body.userId}} | a field from the request JSON body (also {{body.items[0].sku}}) |
{{query.page}} | a URL query parameter (?page=3 → 3) |
{{header.x-tenant}} | a request header (case-insensitive) |
{{method}} · {{path}} · {{url}} | request line parts |
{{rawBody}} | the raw request body (for XML/SOAP/form that isn’t JSON) |
{{uuid()}} | a fresh UUID |
{{now()}} · {{now(unix)}} · {{timestamp()}} | ISO time · unix seconds · epoch ms |
{{randomInt(1,100)}} | a random integer in range |
{
"id": "{{uuid()}}",
"echo": {{request.body.qty}},
"createdAt": "{{now()}}",
"tenant": "{{header.x-tenant}}"
}
Unknown lookups render as empty — templates never throw or break the response.
Need a rule that responds differently each call — e.g. fail once then succeed, or page through results? In a synthetic mock, turn on “Sequenced — respond differently on each call.”
500, step 2 = 200 → tests your retry logic. Or three pages of a list to test pagination.Per-call position is tracked per rule for the session; use Reset hits (Rules tab) to rewind sequences back to step 1.
Sometimes you want the real response, lightly modified. Choose Passthrough + rewrite as the rule type. Mockingbird lets the request hit the network, then on the way back:
$.user.plan = "free" $.items[0].price = 0 $.flags.beta = true
The right-hand side is parsed as JSON (so true, 0, "text", arrays all work). Rows rewritten this way show an edited tag.
Choose Redirect as the rule type to send a matching request to a different URL on the network — e.g. point production traffic at a local mock server. With a regex pattern you can reuse captured groups:
| Pattern | Redirect to | Result |
|---|---|---|
/\/api\/(.*)/ | https://localhost:3000/mocks/$1 | /api/orders/42 → …/mocks/orders/42 |
Use $1…$9 for capture groups and $0 for the whole match. The request hits the network at the rewritten URL (subject to that target’s CORS).
Mockingbird works on any HTTP API, not just REST/JSON:
/graphql, a URL pattern can’t tell operations apart. Fill in the GraphQL operation field on a rule (e.g. GetUser) and it matches only that operationName (read from the request body, or inferred from the query text). Leave it blank for REST/SOAP.{{rawBody}}.application/x-www-form-urlencoded bodies are parsed so {{body.fieldName}} works.Rules live in named scenarios (profiles) so you can keep several worlds ready and flip between them instantly — empty-state, error-storm, logged-out, slow-network.
A breakpoint holds a real request on the wire so you can edit it before it continues.
Right-click a row → Breakpoint on request or on response (or create one in the Rules tab with a URL pattern + method + stage). Armed rows show a BP·→ marker. The Break on all toggle (Rules) pauses everything for quick exploration.
Tip: from a held response you can Save as mock to capture it as a reusable rule. Resolve hands-free with keyboard shortcuts — ⌘/Ctrl+Enter to continue, ⌘/Ctrl+Backspace to abort.
Re-send a request, or build one from scratch.
GET/HEAD auto-send so you see the response immediately.Move requests in and out as curl commands — the fastest on-ramp from docs, a terminal, or a teammate.
-X, -H, -d/--data-raw, -b, line continuations, and quoting).In a request’s detail, use Compare to another request to pick a second capture. You’ll get a line-by-line body diff (green added / red removed) plus highlighted header and status differences — handy for spotting what changed between two calls.
| Type | Example | Matches |
|---|---|---|
| Substring | /api/users | any URL containing that text (case-insensitive) |
| Glob | */api/v2/* | * matches any characters, including / |
| Regex | /\/orders\/\d+/i | wrap in slashes; flags optional |
The rule form shows the detected type and how many captured requests currently match — so you can confirm a pattern before saving.
Test how your app behaves on a slow or flaky connection. In Settings, under Network conditions, set any of:
| Control | Effect |
|---|---|
| Throttle (ms) | baseline delay added to every request that hits the network |
| Jitter (ms) | extra random delay of 0…jitter on top, for realistic variance |
| Fail rate (%) | that percentage of requests are dropped with a synthetic network error |
These apply to traffic going to the real network (not to synthetic mocks, which have their own latency). Dropped requests show a failed tag. Set everything to 0 to turn chaos off.
When a mock “silently doesn’t fire,” these remove the guesswork:
N×) — how many times it matched this session..har file for other tools..har — record traffic in DevTools or another tool, import here, then enable the mocks you want. Non-text bodies are skipped; duplicate method+URL entries keep the last.| Setting | What it does |
|---|---|
| Break on all requests | Pause every request at the request stage — exploratory. |
| Intercept responses | Capture response bodies for every request (needed to inspect bodies & “Save as mock”). Slightly higher overhead. |
| Persist capture log | Keep a metadata-only history across restarts (no bodies stored). |
| Max retained body size | Cap on stored body size; larger bodies are truncated with a marker. |
| Throttle / Jitter (ms) | Network conditions — delay every networked request (+ random jitter). |
| Fail rate (%) | Drop a percentage of requests with a synthetic network error. |
While a request is held at a breakpoint, you can resolve it without the mouse:
| Keys | Action |
|---|---|
| ⌘/Ctrl + Enter | Continue the shown held request (sending any edits) |
| ⌘/Ctrl + Backspace | Abort the shown held request |
| Esc | Close the right-click menu |
With several requests paused, the shortcut acts on the one currently shown in the queue strip.
A paused request could otherwise hang a page forever. Mockingbird guarantees it won’t:
DeveloperToolsAvailability policy). Mockingbird can’t attach in that case.chrome://extensions → Details → “Allow in Incognito”).Usually a cross-origin response without CORS headers — Mockingbird adds them automatically, but if you set custom headers, make sure they don’t remove Access-Control-Allow-Origin.
Turn on Intercept responses in Settings, or add a response breakpoint — bodies are only readable at the response stage.
By design — it keeps one banner, one clear “armed here” model, and a much simpler (and safer) held-request state machine. You’re debugging a page, not the whole browser.
No — Chrome shows it for any tool that uses the debugger (that’s what lets Mockingbird pause and rewrite live traffic). It appears only while a tab is armed and disappears the moment you disarm. It’s expected, not a bug (see ADR-0001).