Lovable app works in preview but API calls fail after publish
Everything works in the Lovable preview, but the published app fails: API calls return 401/403/500, third-party integrations are dead, or features behave as if their API keys vanished.
- Lovable
- Checkout & payments
- Auth & login
Root cause, in plain English
Lovable frontends are Vite builds: only variables prefixed VITE_ are baked into browser code, and they're baked at build time — a key added or changed after your last publish isn't in the published bundle until you publish again. Server-side secrets live separately (Lovable's secrets panel, delivered to Supabase Edge Functions), never reach frontend code, and occasionally need re-saving before a function picks them up.
How to fix it
Decide which side each value belongs on. Anything secret (Stripe secret key, service keys, API tokens with write access) must stay server-side in an Edge Function — a VITE_ variable is publicly readable by anyone who opens devtools.
For frontend config (publishable keys, project URLs): name it with the VITE_ prefix, then publish again. The published bundle only updates on publish.
For server secrets: add them in the secrets panel so they're injected into Edge Functions, and read them with Deno.env.get("NAME") — no prefix.
Check the Edge Function logs for the failing call. "NAME is not defined" or empty-string auth headers confirm the secret isn't reaching the function; deleting and re-adding the secret forces a clean reload.
Re-test the live published URL, not the preview — the two run different builds with different injection paths.
How Nightlamp detects this automatically
- API canary
- Browser journey
- Keyword check
An api_canary calls your published app's API endpoints on a schedule and alerts on the 401/500 burst that follows a publish with missing keys. A browser_journey exercises the real user flow against the published URL — not the preview — and an http_keyword check asserts that pages render fetched data instead of an error state.
Catch this before your customers do
Nightlamp runs these checks continuously against your live app and sends a plain-English diagnosis — not a wall of logs — the moment this pattern shows up.
Related patterns
Frequently asked questions
- Why did this work in preview but not after publishing?
- Preview and published are separate builds. The preview rebuilds constantly and picks up recent changes; the published bundle is frozen at publish time. Any VITE_ variable changed since your last publish exists in preview but not in production until you publish again.
- Is it safe to put my Stripe secret key in a VITE_ variable?
- No. Every VITE_ value is compiled into the JavaScript your visitors download — treat it as public. Secret keys belong in Edge Function secrets, with the frontend calling the function rather than Stripe directly.
- The secret is saved but the Edge Function still can't read it.
- Confirm the exact name matches what the code reads, then delete and re-add the secret and redeploy the function — a stale function environment that hasn't loaded a recently added secret is a known failure mode, and a forced re-save clears it.
Newsletter
Get new incident patterns as we publish them
One email when new failure patterns, fixes, and monitoring recipes for no-code and AI-built apps land. No fluff, unsubscribe any time.
Double opt-in. One-click unsubscribe. No spam, ever.