Nano GPT logo
NanoGPT

Private AI

Back to Blog

Browser-Encrypted Private Mode on NanoGPT

Jun 5, 2026
Browser-Encrypted Private Mode on NanoGPT

NanoGPT now supports Private Mode for a first set of TEE-backed text models.

This is different from ordinary TEE routing. In a normal hosted chat request, NanoGPT receives your chat body as regular JSON, then routes it to a model. With Private Mode, the request and response body are encrypted on your device before NanoGPT receives them.

That means NanoGPT can authenticate, route, and bill the request, but cannot read the prompt or completion body for supported Private Mode requests.

What Private Mode does

Private Mode creates a stricter privacy boundary for supported models:

your browser or local proxy -> encrypted request body -> NanoGPT -> verified TEE target
verified TEE target -> encrypted response body -> NanoGPT -> your browser or local proxy

The plaintext exists where it has to exist:

  • in your browser or local proxy
  • inside the verified TEE target that runs the model

NanoGPT sees routing and account metadata, but not the encrypted request or response body.

What NanoGPT can and cannot see

For supported Private Mode requests, the encrypted body includes:

  • messages
  • system and developer instructions
  • text conversation history sent to the model
  • supported model settings and reasoning controls
  • the model response body

NanoGPT can still see the parts needed to run the service:

  • your NanoGPT account or API key identity
  • the selected Private Mode model
  • request timing, sizes, status, and usage metadata
  • the selected TEE target metadata

The TEE target can see the plaintext prompt and completion because the model has to process them.

Using Private Mode in the web app

In the NanoGPT web app, choose an eligible TEE model and use the Private Mode control in the model picker.

If a model does not show the Private Mode control, that model is not currently supported through the browser-encrypted Private Mode path. This is so far only working with Tinfoil models - we're working with other providers to be able to do this for more models and providers.

The web app encrypts the chat-completions body in the browser with the Tinfoil client before NanoGPT receives it. NanoGPT forwards the encrypted body and returns the encrypted response. Your browser decrypts the response locally.

Private Mode in the web app is intentionally narrower than normal chat. It supports text chat, conversation history, model settings, streaming, and supported reasoning modes. Features that require NanoGPT to inspect or add plaintext before the request is encrypted are disabled for Private Mode turns.

Verification receipts

After a completed Private Mode response, NanoGPT shows a verification receipt.

The receipt includes:

  • whether browser-side verification succeeded
  • the TEE target and enclave host
  • verifier step statuses
  • expected and runtime measurement fingerprints
  • attestation bundle hash when available
  • verification document hash
  • request and response encryption flags
  • timestamp and model information

This receipt is meant to be copied, saved, and checked independently.

To verify a copied receipt locally:

npx @nanogpt/private-mode verify receipt.json

You can also pipe the receipt JSON on stdin:

cat receipt.json | npx @nanogpt/private-mode verify

The verifier fetches fresh attestation material for the receipt's TEE target, verifies it locally, and checks the measurements, release digest, and HPKE key against the copied receipt.

The right interpretation is specific: this individual Private Mode request used browser-side attestation verification and encrypted request/response bodies for a supported TEE target.

Using Private Mode through the API

For API clients, CLIs, agents, and OpenAI-compatible tools, use the local NanoGPT Private Mode proxy:

NANOGPT_API_KEY=sk-your-key npx @nanogpt/private-mode

It starts an OpenAI-compatible local server:

http://127.0.0.1:8787/v1

Then point your OpenAI-compatible client at that local base URL:

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "http://127.0.0.1:8787/v1",
  apiKey: "unused",
});

const response = await client.chat.completions.create({
  model: "private/kimi-k2-6",
  messages: [{ role: "user", content: "Hello" }],
});

The local proxy verifies Tinfoil attestation, encrypts request bodies, sends ciphertext through NanoGPT, decrypts encrypted responses locally, and returns normal OpenAI-compatible responses to your app.

You can inspect the local proxy status with:

GET http://127.0.0.1:8787/v1/models
GET http://127.0.0.1:8787/v1/private-mode/status
GET http://127.0.0.1:8787/v1/private-mode/attestation

The local proxy preserves normal OpenAI chat semantics. Omit stream for a single JSON response, or set stream: true for server-sent events.

Why the local proxy exists

Direct API calls to NanoGPT's normal /v1/chat/completions endpoint send ordinary JSON to NanoGPT. That is the right path for normal NanoGPT API usage, but it is not the Private Mode privacy boundary.

Private Mode needs encryption before the request body leaves your machine. The local proxy gives OpenAI-compatible apps that boundary without requiring every app to implement attestation verification and encrypted transport itself.

Current scope

Private Mode is currently available for supported Tinfoil-backed text models.

That first scope is deliberate. We only want to show the Private Mode label for models where the request body can be encrypted before NanoGPT receives it, the client can verify the TEE target, and NanoGPT can still settle usage without decrypting the prompt or completion.

We will expand this when we can make the same claim for more models and providers.

Milan de Reede

Milan de Reede

CEO & Co-Founder

milan@nano-gpt.com
Back to Blog