For years, embedding a Google API key in client-side JavaScript was fine. Not a security hole, not a code smell, just how you did it. Google Maps keys, Firebase config keys, YouTube Data API keys: all of them designed to be public. Google’s model was restriction by referrer and app, not by secrecy. You locked a key to a domain, and even if someone copied it, they couldn’t do much with it.
This was a deliberate design, and it worked reasonably well. It solved a real problem: browser-based apps have no safe place to store secrets, so making the key non-secret was the pragmatic answer. Developers internalized this. “Google API key” became associated with something you could safely commit, paste into a frontend bundle, or document in a README.
Then Gemini came along.
The Gemini API uses keys that behave like traditional API secrets. They carry billing access. They can make arbitrary requests. Exposing one is a real problem. Simon Willison wrote about this in February, pointing out the mismatch between the old mental model and the new reality. The product is called a “Google API key,” it comes from a Google console, and it looks identical to the keys developers have been treating as public for a decade. But it is not the same thing.
This kind of silent convention change is particularly dangerous because it doesn’t announce itself. There’s no compiler warning, no deprecation notice, no error when you do the wrong thing. You commit a Gemini key to a public repo the same way you would have committed a Maps key two years ago, and then you get a bill.
Why This Happens
Google grew their API surface through several different teams and product lines with different threat models. The Maps team designed for browser usage. Firebase was built to live in client apps. Those conventions made sense in context. The Gemini team then inherited a key format and distribution system shaped by those decisions, and the result is a credential type that looks familiar but carries completely different risk.
For developers who’ve worked with Google APIs for a while, the mental model is: these keys are restricted, not secret. That model was accurate for long enough that it’s now load-bearing assumption in a lot of codebases and tutorials.
What to Actually Do
Treat any key that touches Gemini, Vertex AI, or any generative AI billing surface as a traditional API secret:
- Store it in environment variables, not in source
- Add
*.envand.env.localto your.gitignorebefore you write the first line of code - Use secret scanning in your repo if the platform offers it
- Audit any existing projects where you might have followed the old Google key convention
If you’re building a Discord bot or any server-side app with Gemini, this is straightforward: the key lives in your environment, never in the repo. The complication is browser-based apps, where you genuinely cannot hide the key. For those, you need a backend proxy that holds the credential and makes requests on behalf of the client.
The underlying lesson is not unique to Google. API conventions drift, product lines merge, and what was safe in one era is a liability in the next. Reading the docs for each specific credential, rather than assuming category-level behavior, is the only reliable approach.