AI app demo links: four kinds of object hiding behind one word
Every AI app maker promises a demo link. The word does not commit to anything about what the link actually is. Open the inspector and you will find the URL is one of four very different objects, and the choice has user-visible consequences nobody talks about. Here is the taxonomy, the trade-offs, and the exact 23 line proxy that makes mk0r’s links work.
The thesis: a demo link is not one thing
When you read a comparison page about AI app makers, the demo link tends to get one row in a feature matrix: shareable URL, yes or no. That row hides four very different implementations, each with a different bet about who clicks the link, when, and what state they should see. The bets are not interchangeable. The wrong choice is the difference between a friend opening your prototype on the train and a friend seeing a 404.
The four shapes I have run into building, hosting, and poking at these tools, in roughly increasing order of how well they survive the moment a non-builder taps them:
- Editor iframe wrapper. The URL points to the platform’s own editor chrome, with the running app rendered inside an iframe. Common on in-browser IDE platforms.
- Static export on a CDN. The platform bundles your app to HTML, CSS, and JS and uploads it to a host like Netlify, Vercel, or its own static bucket. The link is permanent but frozen.
- Redeploy artifact. The platform runs a separate deploy step that produces a new app on a managed runtime, then hands you a URL to that production environment. Detached from the build session.
- Wildcard subdomain proxy. The platform owns a wildcard apex (everything under *.example.com), and each demo gets a unique subdomain that routes through a small piece of middleware to the actual dev server still running in a sandbox VM.
All four are reasonable bets. They just produce different experiences for the visitor, and the difference is invisible from the marketing copy. The rest of this page walks through what each one feels like, then drops into the code that makes the wildcard subdomain pattern work because it is the one mk0r picked and the one that gets asked about most.
Shape 1: editor iframe wrapper
The link looks like https://platform.com/edit/abc123. You tap it, and the page loads the platform’s own editor. Somewhere in that editor there is a preview pane, and inside that pane an iframe is running your app. From the platform’s point of view this is elegant: the link doubles as an entry into the editor, so a visitor can both look at the app and start tinkering with it.
From a stranger’s point of view this is friction. The visitor lands in a developer tool first, not in your app. They have to figure out which pane is the preview. They have to scroll past a navbar that says new project and explore templates. Mobile is rough, because editor UIs are not optimized for thumb scrolling on a 5.5 inch screen. And the link is not portable: you cannot embed the preview in a Slack message and have it render the running app, because Slack is going to unfurl the editor URL as a developer tool, not as your app.
This pattern is the right answer when the link is going to another developer who wants to fork. It is the wrong answer for showing a non-developer the thing you built.
Shape 2: static export on a CDN
The link looks like https://my-app-abc123.netlify.app or some similar generic platform host. The platform took your code, ran a build, produced a static folder, and uploaded it to a CDN. The link is fast (CDN edges everywhere) and permanent (it does not depend on a VM being awake somewhere).
The trade-off is that the artifact is frozen. If your AI app maker generated a Vite plus React app and you ran it against a static export, the build is what shipped at the moment you clicked deploy. A follow-up prompt that adds a new feature does not show up at the link until you click deploy again. Anything that called a server (auth, database, AI completion) is going to fail unless you also wired up an external backend. Static export is the cleanest possible URL but the most divorced from the interactive build loop.
This is the right answer when the demo is finished and frozen and you want it to load in 100 ms from anywhere on the planet. It is the wrong answer when you are still iterating on the prompt and want every change to be visible at the same URL.
Shape 3: redeploy artifact
The link looks like https://abc123.vercel.app or similar, except the platform is running it on its own production hosting, not on a CDN of static files. There is real server side rendering, real Node.js runtime, real databases under the hood. This is what the bigger AI app makers tend to do for their share-link path: the link is a production deployment of the app you just built.
The downside is the deploy step. Between you clicking the share button and the visitor opening the URL, there is a CI step. The platform has to bundle, push, wait for the host’s build to succeed, and then promote the new deployment. That can take 30 seconds for a small app and several minutes for a non-trivial one. During that window the link does not work yet, and after that window the link still points at whatever your last deploy was, not your current edits. Iteration speed pays the bill: every change you want strangers to see is another full deploy cycle.
This pattern is the right answer when the demo is going to stick around and you want the URL to behave like production. It is the wrong answer when you want every change in your prompt to land at the URL within seconds.
Shape 4: wildcard subdomain proxy (the mk0r pattern)
The link looks like https://<vmId>.mk0r.com. The vmId is the unique identifier for the sandbox the agent is building inside. The hostname IS the route. There is no deploy step, no build artifact, no CDN cache. When a visitor types or taps that URL, three things happen in order, all of them visible in the source.
First, the request hits the static IP for the Google Cloud HTTPS load balancer (35.186.212.31). The wildcard cert appmaker-wildcard-cert terminates TLS for *.mk0r.com, no per-preview cert provisioning. Second, Next.js middleware in src/proxy.ts reads the Host header, validates the subdomain against a regex, and rewrites the request hostname to 3000-<vmId>.e2b.app. Third, E2B sees the inbound request, resumes the sandbox if it was paused, and the dev server inside answers. That is the entire pipeline. The link your friend opens is the dev server you have been staring at while building.
What follows is the actual code, because the angle on this page is that no other guide on demo links shows it.
The 23 line proxy that makes the wildcard subdomain work
This is the production middleware. The whole file is short enough to read in one breath.
src/proxy.ts (production source)
import { NextResponse, type NextRequest } from "next/server";
// VM IDs are 15-30 char lowercase alphanumeric strings.
const VM_ID_RE = /^[a-z0-9]{15,30}$/;
// Domains we own (apex variants).
const KNOWN_APEX = ["mk0r.com", "staging.mk0r.com"];
function extractVmId(host: string): string | null {
const hostname = host.split(":")[0];
for (const apex of KNOWN_APEX) {
if (hostname.endsWith(`.${apex}`)) {
const sub = hostname.slice(0, -(apex.length + 1));
if (!sub.includes(".") && VM_ID_RE.test(sub)) {
return sub;
}
}
}
return null;
}
export function proxy(request: NextRequest) {
const vmId = extractVmId(request.headers.get("host") ?? "");
if (!vmId) return NextResponse.next();
const target = new URL(request.url);
target.port = "";
target.protocol = "https:";
target.hostname = `3000-${vmId}.e2b.app`;
return NextResponse.rewrite(target);
}Read it carefully because every choice in those lines is load-bearing for the demo link experience. The regex limits the subdomain to 15 to 30 lowercase alphanumeric characters, which is the same shape E2B sandbox IDs use, so the subdomain doubles as the routing key. The Host header is the input; the request URL is preserved (port stripped, protocol normalized). The rewrite hops to 3000-<vmId>.e2b.app, which is the public hostname E2B exposes for the dev server on port 3000. There is no auth check inside the proxy, no cookie inspection, no allowlist, because the design choice was that any visitor with the URL should see the running app.
The anatomy of the URL itself
A wildcard subdomain proxy URL is not arbitrary. The shape tells you what is going on at the network layer.
Anatomy of an mk0r demo link
https://abc123def456ghij.mk0r.com
┗━━━━━━━━━━━━━━━┗ ┗━━━━┗
vmId apex
15-30 lowercase static IP
alphanumeric 35.186.212.31
chars
- Apex. The single static IP at 35.186.212.31 is the Google Cloud load balancer. One IP, one TLS terminator, all demos.
- vmId. Validated by
/^[a-z0-9]{15,30}$/in src/proxy.ts. This is also the routing key into E2B. - No path. Identity lives entirely in the host. A path of
/hits the dev server’s root, deeper paths hit deeper routes inside your app. - No token. The privacy boundary is unguessability of the vmId, not an auth token in the URL.
What happens between click and pixel
A friend taps the link. Here is the chain that turns that tap into the running app appearing on their screen.
DNS resolves to a single static IP
The wildcard A record in Google Cloud DNS sends every *.mk0r.com hostname to 35.186.212.31, the static IP of the appmaker load balancer. There is no per-preview DNS provisioning.
Load balancer terminates TLS
The wildcard cert appmaker-wildcard-cert in Certificate Manager handles every preview hostname under one cert, mapped through appmaker-cert-map. New demos do not need a new cert issued.
Next.js middleware reads the Host header
src/proxy.ts runs on the request, extracts the subdomain, validates it against the 15 to 30 char regex, and bails out if it does not match (the request falls through to the regular app).
Request rewrites to the E2B sandbox
If the vmId validates, the proxy rewrites the URL hostname to 3000-<vmId>.e2b.app and returns NextResponse.rewrite(target). The visitor's browser still sees mk0r.com in the address bar.
E2B resumes a paused sandbox if needed
Sandboxes are created with { onTimeout: 'pause', autoResume: true } in src/core/e2b.ts, so an inbound request to a paused sandbox wakes it. First hit after a long pause is slower because Vite has to recompile entry chunks.
Vite dev server answers
The same Vite plus React server you watched while building responds. The artifact at the URL is the artifact you tested. There is no CI deploy in between.
Side by side: what each shape means for the visitor
The four shapes feel different the moment somebody who is not you opens the link. The rows are the dimensions that actually matter on a phone in a coffee shop.
| Feature | Other shapes | Wildcard subdomain proxy (mk0r) |
|---|---|---|
| Time to URL after build | Editor iframe: instant. Static export and redeploy: 30 seconds to several minutes. | Instant. The URL exists the moment the sandbox does. |
| URL after a follow-up prompt change | Static export and redeploy: same URL, stale content until you redeploy. Editor iframe: same URL, current content (the editor is live). | Same URL, new content (Vite hot reload). |
| Visitor lands directly on the running app | Editor iframe: lands in the editor first. Static export and redeploy: yes. | Yes. The hostname is the app. |
| Mobile experience | Editor iframe: editor is desktop-shaped. Static export and redeploy: plain HTTPS. | Plain HTTPS, opens like any other site. |
| Anonymous viewer with no platform account | Often gated behind a workspace login on editor iframe and some redeploy hosts. | Yes. Wildcard proxy has no auth check. |
| Survives the build session ending | Static export and redeploy: yes. Editor iframe: depends on the platform's preview lifecycle. | Yes, autoResume wakes the paused VM. |
| Real backend code (DB, server actions) | Static export: no. Editor iframe and redeploy: yes. | Yes, the dev server runs inside the VM. |
| Provisioning cost per new demo | Static export and redeploy: a deploy job per preview. Editor iframe: a slot in the platform. | Zero. One DNS record, one cert, one middleware. |
The honest limits
The wildcard subdomain pattern is not better in every dimension. It is a different bet, and the cases where it loses to a static export or a redeploy are real.
- Cold start latency. The first request after a long pause has to wake the sandbox and recompile entry chunks. A static export on a CDN edges that out by hundreds of milliseconds.
- Long term durability. E2B sandboxes do eventually expire if untouched for long enough. A static export on a CDN does not. If you want a demo URL that survives indefinitely with no future visit, the right path is the publish flow, not the wildcard preview.
- Public by default. The proxy has no auth check. Anyone who guesses or is shared the vmId can open the running app. That is a feature, not a bug, but it does mean private demos need a different path (custom domain plus auth wired into the app itself).
- Concurrent traffic ceiling. A dev server in a single VM is not a CDN. If your demo link goes viral, it will saturate the VM long before it saturates the CDN that a static export would sit on. For a small audience this is fine. For a Hacker News front page it is the wrong shape.
The mental model: the wildcard subdomain proxy is the right shape for the iterative phase of the build, when you want every change visible at the same URL within seconds. When the app graduates into something that should outlive the original VM, the publish flow points a custom domain at the VM and the link is for keeps. The two paths live next to each other on purpose.
What to look for in any AI app maker’s demo links
A short checklist that works regardless of which platform you are evaluating. Run it the next time a tool hands you a shareable URL.
Demo link checklist
- The hostname tells you which shape: a path on the builder's domain (iframe wrapper), a generic CDN host (static export), a hosting provider's host (redeploy), or a unique subdomain on the builder's apex (wildcard proxy).
- Anonymous open in a private window on a device that has never seen the platform: works or fails. Most failures are auth gates dressed up as the link itself.
- After a follow-up prompt change the same URL reflects the change without any extra click. If you have to redeploy, the link is detached from the build.
- After an hour idle the link still works on first hit. If the platform garbage collects previews, the URL was a preview slot, not a real demo.
- Mobile Safari on a phone you have never logged in on opens the running app, not an editor or a sign in wall.
- A demo URL is not a substitute for a published URL. If the link is meant to live forever, ask the platform what shape the published URL is and how it differs.
Want to see your demo link survive the click?
Build a tiny app on mk0r in two minutes, copy the wildcard subdomain link, and we will walk through the trade-offs against whatever your team currently uses on a quick call.
Frequently asked questions
What is an AI app demo link, technically?
It is whatever string the platform hands you when you click share. The trap is that the word does not commit to any particular implementation. On one platform the link is an iframe wrapper around an editor sandbox; on another it is a static HTML export sitting on a CDN; on a third it is a redeploy of your code into the platform's production hosting; on mk0r it is a wildcard subdomain that proxies to a live development VM. Same word, four different objects, four different behaviors. The first thing to do when somebody hands you a demo link is to look at the URL and figure out which kind you are holding.
How can I tell which kind of demo link I have just by looking at it?
Read the hostname. If the URL is a path on the builder's own marketing domain (e.g. builder.com/preview/abc), it is almost always an iframe wrapper. If the hostname is a subdomain of a platform-as-a-service host like vercel.app or netlify.app, it is a deployed artifact and lives on that platform's infrastructure independently of your editor session. If the hostname is a unique alphanumeric string under the builder's own apex (like xyz123abc456.example.com), it is a wildcard subdomain proxy or a per-preview deploy slot, and the only way to tell those two apart is to close the editor and try the link an hour later. If the link works without you doing anything else, it is a wildcard subdomain proxy with auto resume.
What does mk0r's demo link look like, exactly?
The shape is https://<vmId>.mk0r.com, where vmId is a 15 to 30 character lowercase alphanumeric string. The regex is literally /^[a-z0-9]{15,30}$/, defined as VM_ID_RE on line 15 of src/proxy.ts. There is no path, no query string, no token. The identifier IS the subdomain. That choice is what lets the same URL be both the live preview you watch while you build and the link a stranger opens later, because the hostname routes to a single object inside E2B and the rest of the URL behaves like any normal site.
Why a subdomain proxy instead of a normal deploy?
Two reasons. First, a deploy adds a step. The user has to click deploy, the platform has to bundle the code, push it somewhere, wait for the build to succeed, and only then is there a URL. The whole point of a demo link is to skip that, so you can show a friend something five seconds after the AI finishes typing. Second, a deploy detaches the link from the build. Once the artifact is up on a CDN, the link is frozen against whatever you shipped. If you change one word in the prompt the deploy URL is stale until you redeploy. With a subdomain proxy, the link points at the actual development server inside the VM, so the next change ships into the live URL the moment Vite hot reloads. The trade off is that a subdomain proxy needs a wake on demand mechanism, which is the autoResume flag on the E2B sandbox.
What infrastructure does the wildcard subdomain pattern require?
Three pieces. A wildcard DNS record (the A record `*` -> 35.186.212.31 in our case, which is the static IP of the Google Cloud HTTPS load balancer at appmaker-ip). A wildcard TLS certificate (appmaker-wildcard-cert, which terminates *.mk0r.com under the appmaker-cert-map). And one small piece of host-aware routing code (the 23 lines in src/proxy.ts that read the Host header, validate the subdomain against the regex, and rewrite the request hostname to 3000-<vmId>.e2b.app). All three exist whether you have one demo link or ten thousand. The cost of provisioning an additional preview is zero.
Why does the proxy have no auth check?
Because the entire purpose of the demo link is for someone with no account on the platform to be able to open it. If the proxy ran auth, every link would gate behind a workspace login, which is the failure mode of most every-other-platform demo links. The decision is conscious and load bearing: the wildcard subdomain proxy in src/proxy.ts is a flat HTTP rewrite, no cookies inspected, no session lookup, no allowlist. The privacy boundary is the unguessability of a 15 to 30 character lowercase alphanumeric vmId. If you want a private preview, the right move is to use the publish flow in src/app/api/publish/route.ts and put a custom domain in front of the VM. The wildcard subdomain is intentionally public-by-default.
Will the demo link still work tomorrow if nobody opens it?
Yes. The E2B sandbox is created with `{ onTimeout: "pause", autoResume: true }`, which means an idle VM is paused (disk image preserved, RAM serialized) rather than destroyed. The vmId is persisted into Firestore under app_sessions, so the routing still has somewhere to send the request. When a stranger taps the link the next day, E2B sees the inbound request to a paused sandbox and resumes it. The first request after a long pause has a cold start (sandbox wake plus dev server compile of entry chunks); subsequent requests are normal latency. If you need the demo to feel snappy on first hit, ping the URL yourself a minute before you share it.
What about iframe-wrapped previews from editor-style platforms?
An iframe-wrapped preview is the URL you get when the share button on a platform like StackBlitz or a similar in-browser IDE produces a link to their own editor at /edit/abc with the preview rendered inside an iframe in their UI. It is fine for fellow developers, but the visitor lands in an editor first, has to find the preview pane, and the page often will not run on a phone because the editor itself is not a mobile experience. The demo URL pattern on mk0r is host-only, no editor chrome, no platform UI in the way. The visitor sees the running app the way you intend them to see it.
What about static-export demo links?
Static export is the cleanest pattern for a frozen demo. The platform builds your app into a folder of HTML, CSS, and JS, uploads it to a CDN, and the URL points at index.html. Loads are instant, there is no VM to wake, no cold start. The downside is that anything dynamic stops working: API calls go to localhost in the export, server side state does not exist, and a follow up prompt to change the app does not show up at the URL until you redeploy. Static export is the right answer when the app is frozen. The wildcard subdomain proxy is the right answer when the app is still being iterated on. mk0r picks the latter because the iterative case is the more common one for a vibe coding session.
Is the demo link the same thing as a published app?
No, and the distinction matters. The demo link (a wildcard subdomain) is the live development server. The published URL is what the publish flow creates when you map a real domain at the VM and submit the deploy request through src/app/api/publish/route.ts. Both can coexist. The demo link is for sharing a draft with a friend right now; the published URL is for putting the app somewhere it lives even after the original VM session is long gone. Treat the demo link as the warm fast path and the publish flow as the cold permanent path.
What is the simplest test to run on any AI app maker's demo links?
Build a tiny app, copy the link, close every tab on every device, walk away, and an hour later open the link in a private window on a phone you have never opened that platform on. Then look at three things: did the app load, did it look like the app you built (not an editor, not a marketing page), and did it require any tap beyond the initial paste. If all three are yes, the platform produces real demo links. If any of them are no, you are holding one of the weaker shapes (iframe wrapper, expired preview, or sign in gate). No marketing copy distinguishes the four kinds. The link in your hand is the only honest test.