How to Store Protoface API Keys Safely in Next.js and React Apps

Learn how to keep Protoface API keys server-side in Next.js and React, using safe env vars, route handlers, and backend proxies.
Introduction
If you’re wiring a realtime avatar service into a Next.js or React app, the security question is usually the same: where do API keys live, and what crosses the browser boundary?
The short answer is that Protoface API keys should stay server-side. Never ship a long-lived secret key into client JavaScript, never stash it in a public env var, and never assume “it’s only used for my own frontend” is a real security boundary. By the end of this post, you should be able to:
distinguish server-only secrets from browser-safe values,
structure a Next.js app so the client can request avatar/session actions without seeing your API key,
avoid common mistakes with React environment variables, and
choose the right Protoface integration surface for your app.
What should and should not be in the browser
API keys are credentials, not configuration. If a key lets someone create avatars, start realtime sessions, or consume paid usage, then exposing it in browser code is equivalent to handing that capability to every visitor.
In a Next.js app, the boundary is easy to blur because the same repository often contains:
client components rendered in the browser,
server components and route handlers running on the server,
build-time environment substitution, and
serverless or edge functions that can safely hold secrets.
The rule of thumb is simple:
Server-only: Protoface API keys, session creation, avatar management, signing any tokens or embed payloads, and anything that affects billing or access control.
Browser-safe: ephemeral identifiers, session IDs, non-sensitive display metadata, and URLs that are already public by design.
That means NEXT_PUBLIC_* is not for API keys. In React-only apps, the equivalent mistake is bundling the key into Vite/webpack/env config or hardcoding it in source. If the browser can see it, your users can see it.
Next.js: the safe pattern
The cleanest architecture is: browser calls your app backend; your backend calls Protoface. Keep the secret in a private environment variable, and expose only the minimum data the client needs.
In Next.js, put the key in a server-only env var such as PROTOFACE_API_KEY. Then create a route handler or server action that performs the API request. The frontend talks to that internal endpoint, not directly to Protoface.
Then from a client component:
This pattern gives you three important properties:
The secret never leaves the server.
You control authorization. Your app can decide who is allowed to start a session or use a given avatar.
You can enforce rate limits and logging. Useful when your product has multiple teams, tenants, or usage tiers.
React environment variables: the easy mistakes
A lot of leaks happen before a request is ever made. Here are the common ones I see in React and Next.js codebases.
Using a public env prefix for a secret
In Next.js, any variable prefixed with NEXT_PUBLIC_ is intended for browser exposure. Do not place an API key there. The build output will contain it.
Wrong:
Right:
Reading secrets in client components
Even if the variable name is private, importing it into a component that runs in the browser is still a leak if the build system inlines it or if you pass it through props/state. Keep secret usage inside server components, route handlers, server actions, or external backend code.
Assuming “localhost only” is safe
Teams often start by calling a third-party API directly from the frontend while developing locally. That habit usually survives into production. Treat “works in local dev” as irrelevant to security. If a secret is visible in browser devtools or source maps, it is already compromised.
Not separating read and write paths
Sometimes the browser only needs to fetch public avatar metadata, while session creation must be gated. Split those concerns. Keep public reads separate from privileged writes so you can expose only what’s necessary.
What to do in a frontend-only React app
If you truly have no backend, then you do not have a safe place to store a long-lived API key. The answer is not “hide it better”; the answer is to change the architecture.
Practical options:
Add a minimal backend. A small Next.js route handler, serverless function, or edge function can proxy the API call and hold the key.
Use a backend-issued ephemeral token if your provider supports it. That lets the browser hold a short-lived capability rather than a master secret.
Move the sensitive flow off the browser entirely. For example, create the session on the server and send the client only the session identifier or connection details.
The important part is that the browser should not be the authority for privileged operations. If the operation can be abused for billing, impersonation, or session creation, it belongs behind a server boundary.
Where Protoface fits cleanly
For many teams, the right integration is to use the REST API from server code or a small backend, and only pass the browser the session data it needs to render or connect. If you are building a voice agent with a synced avatar, the LiveKit plugin is the most natural place to keep the secret: your agent backend can hold the key, create the avatar session, and stream the synchronized video face without exposing credentials to the web client.
For example, a LiveKit agent process can use the Protoface plugin from server-side Python code. The browser joins LiveKit as usual; the agent process handles the avatar integration.
If you’re using the REST API directly, keep the same rule: make the call from a trusted server, not from a client bundle. The docs at docs.protoface.com cover the API surface and payload details; use those as the source of truth for request fields and session semantics.
And if you’re looking for the integration code itself, the plugin and examples live in the relevant GitHub repositories, which is usually the fastest way to see a real working pattern rather than a hand-wavy diagram.
Defensive practices that actually matter
Once the architecture is right, a few implementation details reduce risk further:
Rotate keys regularly. Treat old keys as dead, not “just in case.”
Use separate keys per environment. Development, staging, and production should not share credentials.
Scope access by app or tenant when possible. A leaked staging key should not unlock production usage.
Log server-side failures, not secrets. Never print the Authorization header or full request body if it may contain sensitive metadata.
Prefer short-lived sessions over long-lived credentials. If your workflow allows it, issue the browser only a bounded session token or connection payload.
Also be careful with source control. API keys often leak through accidentally committed .env files, CI logs, or copied examples. Add secret scanning and pre-commit checks if you handle multiple integrations.
Conclusion
Storing Protoface API keys safely in Next.js and React is mostly about respecting the browser/server boundary. Keep the master key on the server, proxy privileged requests through trusted code, and expose only the minimum session data to the frontend. In a Next.js app that usually means route handlers or server actions; in a voice-agent stack it often means the agent backend owns the integration entirely.
When you’re ready to wire this up, start with the docs at docs.protoface.com, then choose the integration surface that matches your architecture. If you want a concrete reference implementation, the quickstarts in the Protoface GitHub org are the fastest way to compare patterns and copy the one that fits your stack.
