Guide

AI App Maker, No Signup: how mk0r skips the form without faking the auth

Saying no signup is easy. Most tools that advertise it either pop a form the second you press Generate, or they keep your work in browser memory so a refresh wipes it. mk0r took a different route: give every visitor a real backend identity on first paint, warm a VM before they type, and migrate ownership cleanly if they ever decide to sign in.

M
Matthew Diakonov
9 min
4.8from 10K+ creators
Anonymous auth on first paint
VM prewarm before first keystroke
Zero data loss on upgrade

The trick is not skipping auth, it is making auth invisible

When you load mk0r, the auth provider has already run. Inside src/components/auth-provider.tsx there is an onAuthStateChanged listener that, the moment Firebase reports no current user, calls signInAnonymously(auth) and waits for the next state event. By the time the textarea renders, you are a real Firebase user. You just do not know it.

That distinction matters. A real user has a stable UID and a real ID token, so every API call we make on your behalf can be authenticated server-side, rate-limited the same way a signed-in user is, and attached to documents in Firestore that survive a page refresh. None of that is true for the typical no-signup builder, where the only thing carrying state is whatever you stuffed into window.localStorage.

src/components/auth-provider.tsx

Two identifiers, one frictionless front door

mk0r actually issues two identifiers on first paint. The first is the Firebase anonymous UID we just discussed. The second is a session key generated by crypto.randomUUID() and written to localStorage under the key mk0r_session_key. That session key is what binds your VM to your tab.

The Firebase UID owns Firestore documents. The session key owns VM lifecycle. Together they are everything an account would have given you, minus the form.

Identity flow on first paint

Browser load
useEffect fires
mk0r
signInAnonymously(auth)
crypto.randomUUID()
POST /api/vm/prewarm

The VM is already warming before you type

Most builders that say no signup wait until you press Generate before they touch any backend. That is when their cold start shows. mk0r does the opposite. The home page mount fires a POST to /api/vm/prewarm as a fire-and-forget side effect, which calls topupPool() in src/core/vm.ts and ensures an E2B sandbox is on its way before you have decided what to build.

Because the prewarm route accepts requests without any user token in this configuration, an anonymous visitor triggers the same warming behavior a signed-in user would. The pool fills, the VM template (mk0r-app-builder, ID 2yi5lxazr1abcs2ew6h8 in production) is ready, and the only thing left waiting is your keystroke.

What anonymous mode actually triggers on the server

What lives in the ID token (this is the part nobody else has)

Every authenticated request to the mk0r backend carries a Firebase ID token. The server verifies it in src/lib/auth-server.ts, and the decoded payload includes a field most no-signup builders never get to see, because they never minted a token in the first place.

src/lib/auth-server.ts

Because we know whether the caller is anonymous, we can let an anonymous visitor build, save, and revisit projects, while still gating things that genuinely need accountability (publishing to a custom subdomain, billing, OAuth credential reuse) behind a sign-in upgrade.

What it costs you to skip the form (in numbers)

0Form fields on first build
0API calls before your first keystroke
0Identifiers issued (Firebase UID + session key)
0Firestore batch on upgrade

What happens the first time you actually sign in

Eventually some users want a real account, usually because they want to publish, share between devices, or pay. The interesting part is what happens to all the work they did before they signed in. mk0r does not throw it away and it does not ask you to re-import anything.

When you click Sign in with Google, the client first tries linkWithPopup. That attaches the Google credential to your existing anonymous user, which means the UID does not change at all and every existing document still references the right owner. If linking fails because the Google account already has a different UID (for example, you signed in here from another browser before), the client falls back to /api/auth/migrate. That route runs the function below, which is the actual code that prevents data loss.

src/lib/auth-server.ts

One batch, two collections, every document attached to your old anonymous UID gets stamped with the new one. From the user's perspective, all their projects are simply still there.

The seven moments between landing and first generated app

1

Page mounts

Browser loads /. No cookies, no localStorage, no Firebase user.

2

Firebase wakes up

onAuthStateChanged fires with null. The auth provider calls signInAnonymously(auth) immediately.

3

Session key is minted

crypto.randomUUID() generates a fresh UUID and writes it to localStorage under mk0r_session_key.

4

VM prewarm fires

POST /api/vm/prewarm goes out as fire-and-forget. The server calls topupPool() so an E2B sandbox starts warming before any user input.

5

Auth provider fires again

onAuthStateChanged returns with the anonymous Firebase user. setUser hydrates. The UI is now interactive and authenticated.

6

You type a prompt

The textarea sends your first message. Behind it, the Bearer token in the header is the anonymous ID token Firebase already minted.

7

Build streams back

Quick mode streams HTML into an iframe. VM mode attaches your session key to a warm sandbox and streams the agent's actions back live.

Want to see anonymous mode running live?

Walk through the auth flow, the prewarm, and the migration on a real call. Bring questions about your own onboarding.

mk0r vs. the typical no-signup builder

FeatureTypical no-signup toolmk0r
Backend identity on first paintNone, or browser-only tokenReal Firebase UID via signInAnonymously
Server-verifiable token for API callsNo token, requests are unauthenticatedFirebase ID token, sign_in_provider: anonymous
VM warmed before you typeCold start on first generationYes, /api/vm/prewarm fires on mount
Project survives a page refreshOften lost when browser memory clearsYes, owned by your anonymous UID in Firestore
Upgrade path to a real accountRe-import or start overlinkWithPopup, then batch migration as fallback
Code ownership of generated appOften vendor-locked outputReal HTML/CSS/JS or Vite + React project

What you can actually build without signing in

Habit tracker
Budget planner
Recipe scaler
Quiz app
Landing page
Tip calculator
Pomodoro timer
Markdown editor
Color palette generator
Random name picker
Mood journal
Meeting cost calculator

The honest trade-off

There is one cost to skipping the form. If you clear your browser storage, you lose the local mk0r_session_key, Firebase signs you out, and on the next paint we sign you back in as a brand new anonymous user with a fresh UID. Anything you built under the previous anonymous UID is still in Firestore but is no longer reachable from this browser, because no one is holding its credentials anymore.

That is the trade we explicitly made. Asking for an email at the front door would solve that one edge case at the cost of making every visitor type before they create. We chose the other side: the front door is empty, and if you want cross-device durability you sign in once, the migration runs, and from then on everything is permanent.

By the time you read this, it has happened 0+ times across mk0r. Most of those visitors never typed an email.

Frequently asked questions

If there is no signup, how does mk0r know it is me when I come back?

On first visit the client generates a UUID with crypto.randomUUID() and writes it to localStorage under the key mk0r_session_key. It also calls signInAnonymously(auth) against Firebase, which mints a real Firebase user with isAnonymous = true. Both identifiers persist across reloads, so when you come back tomorrow your sessions and projects load against the same anonymous UID without you ever filling in an email.

What happens to apps I built anonymously if I sign in later?

When you sign in with Google, the client tries to link the Google credential onto your existing anonymous user with linkWithPopup. That keeps the same UID, so nothing has to move. If linking fails because that Google account already has its own UID, the app falls back to /api/auth/migrate, which runs a single Firestore batch.commit() that updates userId on every doc in app_sessions and ownerUid on every doc in projects from the old anonymous UID to the new permanent UID. Your work is not orphaned.

Is the VM also created without signup?

Yes. When the landing page mounts it fires a POST to /api/vm/prewarm. That endpoint calls topupPool() in src/core/vm.ts, which spins up E2B sandboxes ahead of demand. By the time you finish reading the prompt placeholder, a VM is already warming for you. The route is gated behind POOL_ADMIN_TOKEN in production but happily runs anonymously when the env var is unset, which is exactly the home page case.

Do I need an email to download the code mk0r generates?

Quick mode streams full HTML, CSS, and JavaScript into the preview iframe and you can copy or download it directly. VM mode runs a real Vite + React + TypeScript project inside a cloud sandbox, and you can browse and copy any file in there. Neither flow asks for an email before generation. We do gate publishing to a custom subdomain behind sign-in, because that is the only place an account is genuinely required.

How is this different from tools that just have a free trial without a signup form?

Most tools that advertise no signup either pop a form the second you click Generate, or they store everything in browser-only memory so a refresh wipes your work. mk0r issues you a real Firebase identity from the start, which means the server can authenticate your requests, attach your sessions in Firestore, and rate-limit you the same way it does signed-in users. You get durability and real backend state without the form.

Does anonymous mode have the same model access as signed-in mode?

Anonymous and signed-in users hit the same Claude generation paths through src/app/api/chat/route.ts. The only difference handled in src/app/api/vm/ensure-session/route.ts is that signed-in users with a connected Claude OAuth token can route generation through their own subscription, while anonymous users use the shared key. Output quality and feature set are identical.

What happens if I clear my browser storage?

You lose the local mk0r_session_key and Firebase signs you out, then signs you in again as a brand new anonymous user with a fresh UID on next paint. Anything you generated under the old anonymous UID is still in Firestore but is no longer reachable from this browser, since you no longer hold its credentials. This is the only real cost of skipping signup, and it is the trade we explicitly chose so the front door has zero friction.

Open the home page. The auth provider runs, the VM warms, and a blank textarea waits. That is the entire onboarding.

Build without signing up
mk0r.AI app builder
© 2026 mk0r. All rights reserved.