You're building a screen. The frontend runs on your laptop at localhost:5173, and the data you need lives on the staging backend. It should be one environment variable: point the app at staging and go.
Then the page shows an error. Staging wants an Authorization token that your local login can't produce, and an X-Tenant header that in production a gateway adds for you. And the feature you're building sits behind a flag that staging has switched off.
The usual fixes all touch something: a hack in the code that adds the headers, a mock server, a change to the staging config. This post uses two Mittelware rules instead. One adds the headers to every request on its way out, and one edits a single response on its way back. Your code and the server stay as they are.
The setup#
To keep this repeatable we used a small local server standing in for staging, at http://api-staging.localtest.me:4060. It behaves like many real staging servers:
- Every request needs an
Authorizationheader, or it answers401. - Every request also needs an
X-Tenantheader, or it answers400. GET /api/configreturns the feature flags, withbetaCheckoutswitched off.GET /api/ordersreturns a list of orders.- It sends no CORS headers at all.
The frontend is a small dashboard on localhost:5173 that calls those two endpoints. It sends no auth headers, because on your laptop it has none.
Before you start, two things for your own setup:
- Open the browser through Mittelware. On the Applications page, open your browser from Mittelware (the isolated option leaves your own windows alone). See Opening apps through Mittelware.
- HTTPS needs the certificate. A real staging API is almost certainly
https://. Trust Mittelware's certificate once and its traffic becomes readable: see HTTPS & certificates. Our stand-in uses plainhttp, so we didn't need that step.
1. See what staging says#
Open the app. This is what the page shows with no rules:

The page can display that 401 message, and that's worth a pause. A browser app on localhost calling another origin is blocked from reading the answer unless the server sends CORS headers, and our server sends none. Mittelware takes care of that by default: it makes every response readable by the page. See CORS errors and Mittelware. Without it you'd be looking at a CORS error instead of the real message, which tells you nothing about what's missing.
Now open Flows and search for the staging host:

Click a row and read the response. Staging tells you exactly what it wants: Missing Authorization header. Once that is fixed, it will say Missing X-Tenant header. We'll add both at once.
2. Rule one: add the headers#
Open Rules, click Create Rule, and fill it in:
- App: your browser (here Microsoft Edge). Only its traffic is touched.
- Label:
Staging: add auth and tenant - When… Domain
isapi-staging.localtest.me - Then… choose Modify Request, click Add action, choose Headers, and add two rows, both set to Set:
Authorization→Bearer dev-service-tokenX-Tenant→acme-dev

Save it and reload the app:

The app didn't change. It still sends a request with no token, and Mittelware adds the headers on the way out. You can check what staging really received. In Flows, open the request and look at Headers, Request: the rule's two headers are at the bottom:

Notice origin: http://localhost:5173 in the same list. That's the page's own address, still there, and still what staging sees.
TIP
Real tokens expire. When yours does, open this one rule, change the value and save (Ctrl + S, or Cmd + S on macOS). Every request picks up the new token straight away. It's the only place the token lives, so it never reaches your code, your config or your git history.
3. Rule two: change one response#
The orders load, but the feature you're building is behind betaCheckout, and staging has it off. The dashboard shows the new checkout panel only when /api/config says true.
Don't ask a colleague to change staging, and don't edit your code to ignore the flag. Change that one answer instead.
Modify Response replaces a response's status, headers or body. For a body, the way to "change a bit" is to start from the real one. In Flows, open /api/config, go to the Response tab and click Copy:

Create a second rule:
- App: your browser.
- Label:
Staging: beta checkout on - When… two conditions (both must match): Domain
isapi-staging.localtest.me, and Pathis/api/config - Then… choose Modify Response, set Behavior to After the server responds (the page still gets the real response, with only your change), click Add action, choose Body, paste the copied JSON and change
betaCheckouttotrue.

Reload the app:

Everything else on the page is still real staging data. Only /api/config was touched, because the rule's Path condition is narrow.
NOTE
A body is replaced as a whole, not edited in place. The copy is a snapshot: if staging adds a flag tomorrow, your copy won't have it until you copy again. That's fine for a small config document, which is what flags usually are. For a long list, change something smaller, such as a header or the status code, or use a mock: Mock an API before it exists.
4. Two rules, one request#
Open the /api/config request in Flows again. Both rules acted on it: the first added the headers on the way out, and the second replaced the answer on the way back.

A request can be changed on its way out and again on its way back, so a Modify Request rule and a Modify Response rule work together, in either order. For /api/orders only the first rule matches, so its badge names just that one. See Order, and when two rules act on one request.
When you're done#
Both rules have switches on the Rules page:

Switch them off and you're back to the plain 401. Switch them on tomorrow and you're back at work. Because these are ordinary rules, you can also export them to a file and give it to a teammate. Look at the file first, though: it contains the token you typed.
Things to watch for#
- Scope tightly. The headers rule matches only the staging domain, so the token is never sent to any other host. Keep it that way: a token in a rule that matches
acmeloosely could leak to a different service. - Use a token meant for development. A short-lived or low-privilege service token is a better fit for a rule than your personal admin token.
- Calls your dev server makes are invisible. If your dev server forwards
/apito staging itself (a Vite or webpack proxy), the browser only talks tolocalhost, and the call to staging comes from the dev server, outside the browser. Mittelware sees what goes through its proxy, so for this recipe point the frontend straight at the staging URL. - Test the real login before you ship. The rule gets you working data today. It doesn't prove your login flow works, so don't leave it as the only thing you've tested.
Related#
- Point a production app at your local server: the same idea in the other direction
- Rule tricks you'll use every day
- Modify Request and Modify Response
- CORS errors and Mittelware