Fixing AI-built apps
Your AI-built app works in the preview but breaks when it's live. Here's why.
By Alexa · 8 November 2026 · 8 minute read
It worked perfectly in Lovable, Bolt, Replit or v0. Then you published it, or moved it to Vercel or Netlify, and now people can't log in, pages are empty or a refresh shows "Page not found". The good news: almost every case comes down to the same seven causes, and most take minutes to fix once you know which one it is.
The preview runs inside the builder, with the builder's address, its settings and you as the only user. Going live changes all three at once: a new address, new settings and real people. Each cause below is one of those changes.
First, look at the error. Open the live app, press F12 (or right-click and choose Inspect), and open the Console tab. Then do the thing that breaks. The red line that appears usually names the cause, and you can paste it to your AI tool word for word.
1. Settings that didn't come along
What you see: a blank page, errors mentioning undefined, "Failed to fetch", or features that need a key (maps, payments, AI) doing nothing.
Why: the app's keys, like the Supabase address and public key or the Stripe publishable key, are stored as environment variables. The builder sets them for the preview, but your hosting doesn't have them. On top of that, the browser only gets variables with the right prefix: VITE_ in Vite apps (what Lovable and Bolt usually make), NEXT_PUBLIC_ in Next.js apps.
Fix: copy every variable from the builder's settings into your host's environment variables, with exactly the same names, then deploy again. They're read when the app is built, so changing them without a new deploy does nothing.
2. Login sends people back to the preview
What you see: the sign-up or password reset email links to localhost or the preview address, or Google sign-in fails with redirect_uri_mismatch.
Why: your login provider still thinks the app lives at the preview address.
Fix: in Supabase, open Authentication → URL Configuration, set the Site URL to your live address and add it to the Redirect URLs. If you use Google sign-in, also add the live address to your OAuth client in Google Cloud. In Firebase, add your domain under Authentication → Settings → Authorized domains.
3. Data shows for you, but not for anyone else
What you see: new users get empty pages, or saving fails with "new row violates row-level security policy". Or the opposite, and worse: users can see each other's data.
Why: Supabase protects data with Row Level Security (RLS), rules that say who can read and change each row. While you test, you're usually the only user, or the rules were switched off to make things work.
Fix: turn RLS on for every table that holds user data, and add policies such as "users can read rows where user_id matches their own id". Then test with a second account in a private window. Don't skip this one: a table without RLS can be read by anyone who has your app's public key, and that key is visible in the browser.
4. Refreshing a page gives "Page not found"
What you see: the home page works, but refreshing /dashboard, or opening a link someone shared, shows a 404.
Why: apps built with React and Vite are single-page apps. There's one real file, index.html, and the app draws every other page itself. When someone asks the host for /dashboard directly, the host looks for that file and finds nothing.
Fix: tell the host to answer every unknown address with index.html. On Netlify, add a _redirects file with /* /index.html 200. On Vercel, add a rewrite to /index.html in vercel.json. On Cloudflare, turn on single-page application handling.
5. Payments go through, but nothing unlocks
What you see: Stripe shows the payment, but the order isn't created or the account isn't upgraded.
Why: your app finds out about payments from a Stripe webhook, a message Stripe sends to your app. That webhook still points to the preview, or the app is using test-mode keys while Stripe is in live mode. Test and live mode each have their own keys and their own webhook secret.
Fix: in the Stripe Dashboard, add a webhook endpoint for your live address, in live mode, and put its signing secret in your host's settings. The webhook's list of recent deliveries shows each failed attempt and why.
6. Emails never arrive
What you see: sign-up confirmations and password resets arrive for the first few people, then stop, or land in spam.
Why: Supabase's built-in email sender is meant for testing and has a very low hourly limit. Contact forms need a real sending service too.
Fix: connect your own sender under Authentication → Emails → SMTP Settings in Supabase, using a service like Resend, Brevo or Postmark, and verify your domain with it so emails don't go to spam. The full walkthrough: Supabase emails not arriving.
7. A secret key ended up in the browser
What you see: it worked in the preview, then your OpenAI or Stripe key was revoked, the bill jumped, or the host blocked the call.
Why: a secret key (OpenAI, the Stripe secret key, Supabase's service role key) placed in front-end code is visible to anyone who opens the browser's developer tools.
Fix: move that call into a server function, like a Supabase Edge Function or a Vercel or Netlify function, keep the key in the host's secret settings, and create a new key to replace the exposed one.
Before you share the link
- Every environment variable is copied to the host, and the app was deployed again.
- The live address is set as the Site URL and redirect URL for login.
- Row Level Security is on for every table with user data, tested with a second account.
- Refreshing any page works.
- A live-mode Stripe webhook points to the live address.
- Emails go through your own sender and your domain is verified.
- No secret keys in front-end code.
Still stuck?
When asking your AI tool for help, give it one problem at a time with the exact error from the console. Asking it to "fix login" while three things are broken is how one fix turns into two new problems.
If you've been going in circles, I fix this kind of problem for a fixed price, from $170, and you pay only once it works. See how it works.