Skip to content
KendorDocs

What happens to localhost URLs in a coding challenge's preview

For challenge authors ·

Browser code that calls http://localhost:4000 is sent to port 4000 in the sandbox, with CORS, redirects and cookies handled. For the few cases it can't reach, use a relative path or routing.<service>.url.

A project's frontend often calls its API at http://localhost:4000, from an env file such as NEXT_PUBLIC_API_URL or hardcoded in the code. In a Kendor preview the page runs in the viewer's browser, where localhost is their own computer, not the sandbox. Kendor redirects those calls to the right port in the sandbox, so most projects work without edits. This article covers what is redirected, what isn't, and the explicit way to build URLs when you'd rather not rely on it.

What Kendor redirects

Any URL whose host is localhost, 127.0.0.1, 0.0.0.0 or [::1], on any port, made from the preview page or from its web workers:

  • requests with fetch and XMLHttpRequest (and so axios and most other HTTP libraries)
  • WebSockets, including socket.io and hot reload, and server-sent events (EventSource)
  • images, scripts, stylesheets, video, iframes, links and forms, whether they're in the served HTML, set from JavaScript, or inserted as markup
  • redirects from your server to http://localhost:…

It doesn't matter where the URL comes from: an env variable baked into the bundle, a hardcoded string, or one built at runtime.

Where a redirected URL goes

  • If the challenge's routing sends that path to that port, the URL goes to the preview address itself. For example, http://localhost:4000/api/users goes to https://<preview-address>/api/users when /api routes to the service on port 4000. Frontend and API then share one address, so there's no CORS at all.
  • Otherwise it goes to that port's own address, https://4000-<preview-address>/api/users, the same address the Processes view opens for that port.

The first time a port is redirected, the browser console says so:

[kendor] localhost:4000 is the sandbox's port 4000 here, reached at https://4000-<preview-address>.

CORS, redirects and cookies

A call from the preview to another port's address is cross-origin, so Kendor makes it look the way it did on your machine:

  • CORS. Your API receives Origin: http://localhost:3000 (the port the page came from), so an allow-list written for local development passes. Its answer is mapped back to the preview address. Only calls from the challenge's own preview get this; any other site's requests are left as they are.
  • Redirects. A Location: http://localhost:3000/dashboard header is rewritten to the preview address.
  • Cookies. The preview shows inside the editor, on another site, where browsers drop ordinary cookies. Kendor marks your app's cookies as partitioned (SameSite=None; Secure; Partitioned), so a cookie login works there too. A cookie with Domain=localhost has that domain removed.

Server-side code needs none of this. Inside the sandbox, localhost already reaches the right process, so a Next.js server component or an API calling another service on http://localhost:4000 works as it does on your machine.

What isn't redirected

  • A CSS url() pointing at localhost, such as background: url(http://localhost:4000/bg.png).
  • Workers created from a blob or data URL, rather than from a script file.
  • Page navigation set in code, such as location.href = 'http://localhost:3000/login', in Firefox. Chrome, Edge and Safari are covered.
  • OAuth callback URLs registered with a provider such as Google or GitHub as localhost. Update them at the provider, or sign in with a test account another way.
  • A server that listens only on 127.0.0.1. The preview can't reach it at all. Listen on $HOST (0.0.0.0) instead.

When the page still loads something from localhost, the browser console says which URL:

[kendor] This page loaded http://localhost:4000/bg.png (css). That address is the viewer's own
computer, not the sandbox, and Kendor couldn't redirect this one.

Chrome may also ask the viewer for permission to access their local network. Both mean the same thing: change that URL as described below.

The explicit way

Instead of relying on the redirect, you can give the browser the right address yourself. Either way works in the sandbox and on your machine.

  • A relative path. With routing sending /api to your API, call fetch('/api/users'). The frontend and the API share the preview address. See multi-service apps.
  • A reference in dev.env.vars. Set your frontend's API variable to the API's public URL:
kendor.yaml
services:
  web:
    dev:
      command: npm run dev -- --port $PORT
      port: 5173
      env:
        vars:
          VITE_API_URL: routing.api.url

routing.api.url resolves to the preview address plus the API's route, before any service starts.

Every dev command also gets KENDOR_PUBLIC_HOST, the preview's host name, for code that builds URLs itself. A port's own address is that host with <port>- in front.

Turning it off

If your app maps its own URLs and you want its pages served exactly as written, send the header x-kendor-no-rewrite on its HTML responses. Kendor then leaves those pages alone.

Was this article helpful?