← All guides

Is your OpenAI API key exposed in your frontend? Check and fix it

Updated 23 October 2026 · 5 min read

Short answer: If your app calls OpenAI directly from the browser, your key is in the JavaScript every visitor downloads, and anyone can copy it and spend your credits. Check by searching your site's scripts for sk-. If it's there: revoke the key at OpenAI now, move the call into a server function, and put the new key in a server-only secret.

Why this happens in vibe-coded apps

AI builders often make the quickest version work first: the page calls api.openai.com directly, with the key stored in a variable like VITE_OPENAI_API_KEY or NEXT_PUBLIC_OPENAI_KEY. Those prefixes mean "include this in the browser bundle". Vite's own docs say variables prefixed with VITE_ are exposed to client code. (Vite docs)

The 2-minute check

  1. Open your live app in Chrome, right-click → Inspect → Sources (or Network → JS).
  2. Press Ctrl+Shift+F (Cmd+Option+F on Mac) to search all files, and search for sk- and api.openai.com.
  3. If you see a long string starting with sk- or sk-proj-, your key is public.

Or run a free Vibe Check: it searches your public scripts for OpenAI, Anthropic, Stripe, AWS, GitHub and Supabase secret keys automatically.

If it's exposed: do this now

  1. In the OpenAI dashboard, create a new key, then revoke the exposed one. Assume it's already been copied.
  2. Set a monthly budget limit in your OpenAI billing settings so a future leak can't drain your account.
  3. Check the usage page for spikes you don't recognise.

The fix prompt

My app calls OpenAI directly from the browser, which exposes my API key. Move every OpenAI call into a server-side function (a Supabase Edge Function, or an API route if this is Next.js). The function should read the key from a server-only secret named OPENAI_API_KEY, check that the user is signed in, limit how often each user can call it, and return only the result. Remove the key and any VITE_ / NEXT_PUBLIC_ OpenAI variable from the frontend completely. Tell me where to add the new secret in my hosting dashboard. Do not print the key.

Why "signed in" and "rate limit" matter

Moving the key to a server hides it, but if the function accepts calls from anyone, people can still use your credits through it. Requiring a login and a per-user limit closes that gap.

Check your app in about 60 seconds

The free Vibe Check reads only public pages and gives you a fix prompt for each issue.

Run free Vibe Check

FAQ

Is it OK if the key is in a .env file?

Only if the variable is not exposed to the browser. Anything prefixed VITE_, NEXT_PUBLIC_ or REACT_APP_ ends up in public code.

Can I just hide the key with obfuscation?

No. If the browser can use it, anyone can extract it. The only fix is to call OpenAI from a server.

What if I already revoked the key?

Good. Now move the call to a server function before adding a new key, or the new one will leak too.

Related guides