Google AI Studio export / Vite / React

Your AI Studio app export ships your Gemini key

Quick answer

If your app was exported from Google AI Studio's Build mode, its vite.config.ts may copy GEMINI_API_KEY into the browser bundle at build time, so anyone can read it. Search your built dist/ folder for "AIza". If it's there, rotate the key now, then call Gemini from a server function or through a capped KeyVault Edge token, and set a monthly spend cap on the AI Studio project.

AI Studio's Build mode exports a Vite + React app. If its config defines process.env.GEMINI_API_KEY, the production build contains the key as plain text that any visitor, or any bot scanning public sites for AIza keys, can copy. The bill lands on the project that owns the key.

The Problem

This is the pattern to look for in an exported app. loadEnv with an empty prefix reads every variable in your environment, and the define block pastes GEMINI_API_KEY into the JavaScript that ships to the browser. Deploy it to Vercel, Netlify or Firebase Hosting and the key is public.

TypeScript
// vite.config.ts in an exported AI Studio app (look for this pattern)
import { defineConfig, loadEnv } from "vite";

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, ".", ""); // empty prefix: loads EVERY variable
  return {
    define: {
      // Replaced with the key's literal value in the browser bundle
      "process.env.GEMINI_API_KEY": JSON.stringify(env.GEMINI_API_KEY),
    },
  };
});

// Then check the build:
//   npm run build && grep -r "AIza" dist/

The Fix

Send the request to the KeyVault Edge proxy at https://proxy.keyvaultedge.com with the provider's usual path, your kvt_ token in X-KV-Token and the provider's base URL in X-KV-Target. The proxy refuses requests whose Origin isn't on the token's allowed hosts, then injects your real GEMINI_API_KEY, so it never sits in your app's environment.

TypeScript
// Browser code, no backend: only a host-locked, capped kvt_ token ships
const res = await fetch(
  "https://proxy.keyvaultedge.com/v1beta/models/gemini-3.5-flash:generateContent",
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-KV-Token": import.meta.env.VITE_KVE_TOKEN, // kvt_..., not your AIza key
      "X-KV-Target": "https://generativelanguage.googleapis.com",
      // The browser sends Origin itself; it must be one of the token's allowed hosts
    },
    body: JSON.stringify({ contents: [{ parts: [{ text: prompt }] }] }),
  }
);
const data = await res.json();
const text = data.candidates?.[0]?.content?.parts?.[0]?.text ?? "";

Setup in 5 steps

1

Rotate the key now

If grep finds AIza in dist/ or on your live site, assume the key has been copied. In AI Studio, delete that key and create a new one before changing any code, then check the project's usage for the period the site was live. The leaked-key checklist at keyvaultedge.com/leaked-api-key covers the evidence to gather for a billing dispute.

2

Remove the define block

Delete the process.env.GEMINI_API_KEY (and process.env.API_KEY, if present) entries from define in vite.config.ts, and remove the client code that reads them. Rebuild and run grep -r "AIza" dist/ again: it must return nothing.

3

Option A: call Gemini from a server function

Put the call in a function that runs on your host, with the key in a server-only environment variable (no VITE_ prefix), and have the browser call your function instead. This example is a Vercel function in a Vite project; Netlify functions and Cloud Run handlers can use the same Request and Response objects. Add your own rate limiting or auth, since anyone can call the function.

TypeScript
// api/gemini.ts (Vercel). Set GEMINI_API_KEY in the project's env, no VITE_ prefix.
export async function POST(request: Request) {
  const { prompt } = await request.json();
  const upstream = await fetch(
    "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.5-flash:generateContent",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "x-goog-api-key": process.env.GEMINI_API_KEY!,
      },
      body: JSON.stringify({ contents: [{ parts: [{ text: prompt }] }] }),
    }
  );
  return new Response(upstream.body, {
    status: upstream.status,
    headers: { "Content-Type": "application/json" },
  });
}

// Browser:
// await fetch("/api/gemini", { method: "POST", body: JSON.stringify({ prompt }) });
4

Option B: no backend, use a KeyVault Edge token

Store the new AIza key in KeyVault Edge and create a token with your site's domain as the allowed host, the generateContent endpoint as the only allowed endpoint, a requests-per-minute limit and a monthly cost cap. Put the kvt_ token in VITE_KVE_TOKEN and call the proxy as shown above. The token is visible in your bundle by design; the real key never is, browsers on other sites are refused, and if the token is abused you revoke it in one click without rotating the Gemini key. You can try it first with the free sandbox key, no real key needed.

5

Set a Monthly spend cap and restrict the key

In AI Studio, open the project's Spend tab and set a Monthly spend cap (project owners can set this). Google says caps have about a 10-minute delay, so it bounds the damage rather than preventing it. Also restrict the key to the Generative Language API on Google Cloud's Credentials page so it can't be used for other APIs on the project.

What this protects, and what it doesn't

  • Your real GEMINI_API_KEY stays at the edge, so it can't leak from your repo, logs, bundle or server environment.
  • The kvt_ token is still a credential. A copied token can be replayed by anyone who can send the right headers, including a fake Origin from a server. The protection is that each token has its own rate limits, monthly cost cap and endpoint scope, and you can revoke it in one click without rotating the provider key.
  • The cost cap is estimated from the usage the provider reports, so a request already in flight can overshoot it slightly.

Already leaked a Gemini key? Read what to do in the first hour. Plans and limits are on the pricing page.

Frequently asked questions

How do I check if my AI Studio app leaks the Gemini key?

Run npm run build, then search the output: grep -r "AIza" dist/. You can also open your live site, look through the JavaScript files in DevTools (Sources tab) for AIza, or watch the Network tab for requests to generativelanguage.googleapis.com that carry your key. Any match means every visitor can copy it.

Why does the key end up in the bundle without a VITE_ prefix?

Vite only exposes VITE_ variables to client code by default, but a define block bypasses that. When vite.config.ts loads every variable with loadEnv(mode, '.', '') (an empty prefix) and maps process.env.GEMINI_API_KEY in define, Vite replaces that expression with the key's literal value in the client code.

Does a Monthly spend cap in AI Studio stop the bill?

It limits it. Google lets project owners set a Monthly spend cap on the project's Spend tab in AI Studio, and says caps have about a 10-minute delay, with overages in that window still billed. Treat it as a ceiling, not a substitute for keeping the key out of the browser.

Is restricting the key to my website's domain enough?

No. A referrer restriction only checks a header that any script outside a browser can set, so a copied key still works from a server. Restrict the key to the Generative Language API too, but don't rely on restrictions alone.

What happens if a KeyVault Edge token for Google AI leaks?

The real GEMINI_API_KEY stays at the edge, so it isn't exposed. The leaked token is still a credential, but it is limited by its own rate limits, monthly cost cap and allowed endpoints, browsers on hosts outside its allowlist are refused, and you can revoke it in one click without rotating your Google AI key.

Do I have to rewrite my AI Studio (Vite) code?

No. Keep the same Google AI API paths and send the request to https://proxy.keyvaultedge.com with your token in the X-KV-Token header and https://generativelanguage.googleapis.com in X-KV-Target.

Start protecting your keys

Your Google AI key is one leaked .env file away from being exploited. With KeyVault Edge the real key stays at the edge, and the token that replaces it is capped, scoped and revocable in one click.