OpenAI API key in your React or Vite frontend: rotate it and move calls to a backend

Updated Oct 27, 2026 · Pewterkit Guides

If your OpenAI API key is in your app's browser code, anyone can copy it and send requests billed to your account. Rotate the key from the API Keys page now, then route every OpenAI call through your own server or serverless function that reads the key from a secret. OpenAI's own rule: "Never deploy your key in client-side environments like browsers or mobile apps."

Why hiding the key in the frontend doesn't work

Everything a browser runs is downloaded to the visitor's machine. Putting the key in an environment variable doesn't help if the build copies it into the bundle: Vite says "Variables prefixed with VITE_ will be exposed in client-side source code after Vite bundling," and Next.js says a NEXT_PUBLIC_ value "will be inlined into any JavaScript sent to the browser." Minifying or splitting the string makes it harder to spot, not hidden.

OpenAI's key-safety article gives the alternative: requests "should always be routed through your own backend server", which holds the key so the browser never sees it.

Fix it

  1. Rotate the key. OpenAI: "If you believe your key has been leaked, rotate your key immediately from the API Keys page." Delete the old key once the new one works.
  2. Add a small backend route. It receives the user's request from your frontend, adds the key on the server, calls OpenAI and returns the answer.
  3. Store the key as a server secret in your host's settings, under a name with no public prefix. OpenAI suggests the name OPENAI_API_KEY.
  4. Limit what the route accepts. Fix the model and maximum length on the server, require a signed-in user if your app has accounts, and rate-limit per user, so the route can't be used as a free proxy.
  5. Redeploy and search the bundle for sk- to confirm the key is gone.

A minimal server route (Node, OpenAI's library):

// api/chat.js  (server only)
import OpenAI from "openai";
const client = new OpenAI(); // reads process.env.OPENAI_API_KEY

export default async function handler(req, res) {
  const { message } = req.body;
  const r = await client.responses.create({
    model: "gpt-6-astra", // the model in OpenAI's quickstart; use the one your app needs
    input: String(message).slice(0, 2000),
  });
  res.status(200).json({ text: r.output_text });
}

The frontend then calls /api/chat with fetch, and never sees the key. Test this on a preview deployment before relying on it.

If your app has no server

Most hosts and app builders include one: Vercel and Netlify functions, Cloudflare Workers, Supabase Edge Functions, Firebase Cloud Functions, or your builder's backend actions. Ask your AI builder to "move the OpenAI call into a server function and read the key from a secret", then check the result with the steps above.

What Pewterkit Check looks at

The check reads your home page and the scripts it loads and looks for OpenAI keys that start with sk-proj-, along with other well-known secret formats (Stripe live secret keys, Anthropic, AWS, GitHub, Slack and SendGrid keys, Supabase service_role keys and private keys). It shows the key masked and names the file. It never uses a key it finds. Keys in older formats, or keys your app fetches at run time, may not show up, so search your code too.

FAQ

Can I keep the key in the frontend if I restrict it?

Keep it on the server. OpenAI's guidance is to never deploy the key in browsers or mobile apps, whatever settings it has.

Is a .env file enough?

Only for server code. A .env value that your build tool copies into client code (such as a VITE_ or NEXT_PUBLIC_ variable) ends up in the public bundle.

How do I know if someone used my leaked key?

Check the usage page in your OpenAI account for spikes you don't recognize. OpenAI also says you can contact it through help.openai.com for investigation.

Sources

  1. Best practices for API key safety (OpenAI Help Center) — read 27 Oct 2026
  2. Developer quickstart: Responses API example (OpenAI) — read 27 Oct 2026
  3. Env variables and modes (Vite) — read 27 Oct 2026
  4. How to use environment variables (Next.js) — read 27 Oct 2026

How this page was made: drafted with AI from the sources listed, reviewed by Pewterkit. Docs checked Oct 27, 2026. Spotted something out of date? Tell us.

Related guides