What Midstream is
Midstream turns moments in your Playwright tests into live copies of your app that a reviewer can open and click.
Midstream turns the moments you care about in your end-to-end tests into live, running copies of your app. Every pull request links to the ones it touches, and opening one drops you into the app at exactly the moment your change takes effect.
A diff does not tell you whether it works
Reading a diff tells you what changed. It does not tell you whether the feature works. Layout breaks, dead buttons, a flow that is fine on the happy path and wrong on the second attempt — none of that is visible in the code.
The usual answers each fall short in the same place:
- Screenshots and recordings are one frame of one moment. You cannot click anything, you cannot try the case you are actually worried about, and they go stale the next time someone pushes.
- Preview environments hand you a running app at its front door. You still have to sign in, create the data, and click through eleven screens to reach the thing that changed.
- Pulling the branch and running it locally works, and costs you twenty minutes per review.
So most changes get approved on the strength of the diff and a hope. That was survivable when people wrote all the code. It is not survivable now that a single afternoon can produce more pull requests than a team can honestly read.
The loop
Midstream adds one line to a test you already have, and gets you a live app in return.
1. Mark the moment. In a Playwright test, at the point where the state on screen is the state you would want a reviewer to see, add a scene call:
import { test, expect } from "@playwright/test";
import { midstreamScene } from "@midstream/sdk/playwright";
test("shopper sees the items in their cart", async ({ page }) => {
await page.goto("/products/espresso-beans");
await page.getByRole("button", { name: "Add to cart" }).click();
await page.goto("/cart");
await expect(page.getByRole("heading", { name: "Your cart" })).toBeVisible();
await midstreamScene(page, "cart-with-items");
});That call marks a scene. (The function keeps its old name for now; it marks a scene.) On your laptop it does nothing at all, so your normal test runs are unchanged.
2. CI captures it. When your test suite runs in CI, the call registers a capture: the scene as it stood on that commit, with a screenshot, an accessibility snapshot of the page, and the test that produced it. No extra job, no new infrastructure — it rides along with the suite you already run.
3. The pull request carries the links. Midstream adds a check to the pull request saying how many scenes the change touches, and a deployment link into Midstream's view of that pull request, where those scenes are listed.
Midstream also comments on the pull request with a link to each scene the change touches, so you can go from a line in the diff to the moment it changes without leaving GitHub.
4. A reviewer opens one. Clicking a scene stands up a live copy of your app from that exact commit and puts the reviewer's browser into the state the test was in — signed in, cart full, form half-completed, whatever the moment was. They land on the change and start clicking.
What you land in is the real thing
This is not a rendering of your app; it is your app, built from your repository at the commit under review, running your own install and start commands. You can click anything. You can try the edge case that worried you. You can hand the link to a designer.
Two things follow from that:
- You arrive at the moment, not the front door. The difference between a thirty-second review and a ten-minute one is usually the nine and a half minutes of clicking to get to the change.
- It is live, so it does not go stale. The next commit produces its own capture of the same scene.
The first person to open a given scene waits while we clone your repository, install, start your app, and run the test up to the marked moment. That takes minutes, not seconds. Opens after that are quick. Each person gets their own copy, so one reviewer clicking around never disturbs another.
Test coverage stops feeling like a tax
Every scene you mark for review value is a real end-to-end test that has to pass to produce it. The test has to reach the moment, which means the flow has to work.
That flips the incentive. Teams usually write end-to-end tests out of duty, against the pull of everything else on the list. Here you write them because you want the review to be faster, and the coverage arrives as a side effect. The reviewer's link and the regression test are the same artifact.
What Midstream needs from you
- Playwright tests. Playwright is the only test framework the SDK supports.
- A repository on GitHub. You connect it once with the Midstream GitHub App, and you sign in to Midstream through GitHub.
- An app that can start from a clean checkout. Midstream runs your install and start commands in a fresh container with your repository at one commit. Anything your app needs — migrations, seed data, a local database — has to come from those commands.
- A
midstream.jsonfile in your repository root telling us how to install, start, and test your app.
One caution before you start: capturing a scene captures the browser session at that moment, including cookies and stored data. Mark scenes in tests that use test accounts and seeded data, never tests that sign in to real production data.
Where to go next
- Scene, Capture, Instance, Deploy — four words, and how they nest. Ten minutes here saves confusion everywhere else.
- Quickstart: your first scene — from an empty account to a live instance you can click.
After that, the rest of this knowledgebase covers marking scenes in your tests, configuring your project, reviewing changes with your team, running a workspace, and what to do when a scene will not load.