Share a React Router or Remix app, actions included
React Router refuses actions from a link's origin with 400 until allowedActionOrigins lists it; Remix v2 takes them as it is. Both tested.
Updated
A React Router app in framework mode shares through ouicu with its pages and hot reload as they are, but refuses every action sent from the link, with 400 Bad Request. One line in react-router.config.ts, allowedActionOrigins, lets the link's name in. Remix v2 takes the same actions with nothing to change.
| React Router | |
|---|---|
| Dev server port | 5173 |
| On your Wi-Fi | npm run dev -- --host |
| Host check | server.allowedHosts |
| Build folder to upload | build/client, from react-router build |
| Through the link | What it takes |
|---|---|
| The page | Works, nothing to change |
| Hot reload | Works, nothing to change |
| A form action | Needs allowedActionOrigins: ["*.ouicu.app"] |
Bad Request, and where the reason is
Send a <Form method="post"> through the link and nothing happens on the page: the request got 400, and the terminal running the dev server says only Error: Bad Request. The reason is logged when the form is sent without JavaScript, as a plain page POST, which gets Bad Request and this in the terminal:
The `request.url` origin does not match `origin` header from a forwarded action request. Aborting the action.React Router builds request.url from Host, which ouicu sets to localhost:5173, while the browser's Origin is the link's. The check came in 7.12.0, released on 7 January 2026; its changelog entry reads: “Add additional layer of CSRF protection by rejecting submissions to UI routes from external origins.”
Add allowedActionOrigins to react-router.config.ts
export default { ssr: true, allowedActionOrigins: ["*.ouicu.app"],} satisfies Config;Restart the dev server and the action runs through the link. The docs describe the setting as “An array of allowed origin hosts for action submissions to UI routes (does not apply to resource routes).” and “Supports micromatch glob patterns (* to match one segment, ** to match multiple).” So *.ouicu.app covers any one ouicu name, and another site's origin is still refused: we sent one, and it got 400.
The setting goes into the build, so it counts in production too. Built and served with react-router-serve, the action was refused through the link without it and ran with it. Keep it to the builds you share, or to your reserved name.
Remix v2 takes the action as it is
Remix v2 checks actions too, but it compares Origin with X-Forwarded-Host when a proxy sends one, and only then with Host. ouicu sends the link's name in X-Forwarded-Host, so in Remix 2.17.5, made from its own template, the action ran through the link with nothing changed. Without that header, as through a tunnel that sets Host to localhost and sends no forwarded name, Remix refuses it and logs:
host header does not match `origin` header from a forwarded action request. Aborting the action.Moving a Remix app to React Router brings the stricter check with it, so add allowedActionOrigins as part of the move.
Share react-router dev with ouicu
npm run dev# in a second terminalouicu share 5173The dev server runs on Vite, whose host check would refuse a tunnel that keeps your public name in Host; through ouicu it passes as it is (share a Vite dev server). Hot reload connects to the link's own port, and a change to a route shows in place on every screen with the link open. On Free, a share runs for up to 2 hours.
Upload a single-page build
With ssr: false in the config, react-router build writes a single-page app to build/client. The docs add that “you'll need to configure your host to direct all URLs to the index.html of the client build.” --spa does that on ouicu:
npx react-router buildouicu deploy build/client --spaAn upload has no server, so server actions don't run there; for those, share the dev server or react-router-serve (Uploading a built site).
Phones, and who can open it
ouicu prints the link as a QR code for a phone on any network (QR codes). On the same Wi-Fi without a link, Vite needs npm run dev -- --host, as in how to open localhost on your phone. A link reaches every route and action, so for a client ask for a password, on Hobby and Pro: ouicu share 5173 --password.
Tested with React Router 8.4.0 on , with Node 24.21.0: the default template from create-react-router with a route that has an action, shared with ouicu share through ouicu's edge and opened in Chromium at its https link: react-router dev with an edit, the action before and after allowedActionOrigins, in development and built, and an SPA build; and Remix's v2 template, the same action, in remix vite:dev.
Sources
Prices, defaults and quotes about other products, and the day each was last checked at its source.
- Server Options, Vite docs. Checked .
- Single Page App (SPA), React Router docs. Checked .
- lib/actions.ts, React Router on GitHub. Checked .
- packages/react-router/CHANGELOG.md, React Router on GitHub. Checked .
- react-router: versions, npm. Checked .
- react-router.config.ts, React Router docs. Checked .
- remix-server-runtime/actions.ts (v2), Remix on GitHub. Checked .