A clean, ready-to-deploy chat UI for the Claude API. Auth and per-user data sync are built in. Follow the 5-step setup (including a one-toggle Supabase lockdown) and your deployment is private to you — strangers who find your URL can't spend your Anthropic credits.
First time deploying anything? Read
docs/SETUP.md— a step-by-step guide with no shortcuts and no assumed knowledge. The only fiddly part is a 5-minute one-time Supabase setup;docs/SUPABASE_SETUP.mdwalks through that.
- Sign-in required — Supabase magic-link auth. Each user gets their own private space.
- Cross-device sync — sign in on your phone, see your laptop's conversations. All data lives in your Supabase project.
- Projects in the sidebar, each holding multiple conversations (just like Claude.ai).
- Model switcher — Opus, Sonnet, and Haiku across the 4.x line. Add or remove models with one line of code.
- Web search — toggle it on per project; Claude searches the web when it needs to.
- Extended thinking — toggle it on for complex reasoning. Thinking is shown collapsed above the response.
- File library — upload PDFs, images, or text/code files and attach them to your messages.
- Streaming responses — text appears as Claude writes it.
- Prompt caching — system prompts and conversation history are auto-cached so follow-up turns cost ~10% of the input price.
- Token + cost counters — per message and cumulative for the conversation.
- Message actions — copy, regenerate, delete on hover.
- Export & import conversations as Markdown or JSON.
The whole thing is ~1,500 lines of code across a handful of files. Read it. Change it. Make it yours.
You'll need accounts on GitHub (free), Vercel (free), Supabase (free), and Anthropic (~$5 minimum).
- Fork this repo.
- Set up a Supabase project (detailed walkthrough). Run the schema, copy 3 values.
- Click the Vercel Deploy button above. Paste in the 3 Supabase values + your Anthropic API key as environment variables. Hit Deploy.
- Tell Supabase about your URL so magic-link emails know where to send people back. (Auth → URL Configuration in Supabase.)
- Open the URL, sign in with your email, chat.
Full step-by-step in docs/SETUP.md.
beginner-api-interface/
├── api/
│ ├── chat.py ← Serverless endpoint. Verifies auth via Supabase, then proxies to Anthropic & streams back.
│ ├── config.py ← Returns Supabase URL+anon key from env vars to the frontend.
│ └── requirements.txt ← Python deps: just `anthropic` (auth uses stdlib urllib).
├── public/
│ ├── index.html ← Page skeleton: sign-in screen + main shell + dialogs.
│ ├── styles.css ← All styling. Theme via CSS variables at the top.
│ └── app.js ← All client logic (auth, projects, conversations, files, streaming).
├── docs/
│ ├── SETUP.md ← Beginner walkthrough (this is what you'd send a friend).
│ ├── SUPABASE_SETUP.md ← The Supabase-specific bit, broken out for clarity.
│ ├── supabase-schema.sql ← Tables + row-level security. Paste-and-run in Supabase SQL Editor.
│ └── screenshot.png ← README image.
├── vercel.json ← Tells Vercel how to route requests.
├── LICENSE ← MIT.
└── README.md ← You are here.
There's no build step, no framework, no bundler.
api/chat.py is a Python serverless function. It:
- Verifies the request's auth token by asking Supabase's
/auth/v1/userendpoint whether the token is valid. Anything missing or invalid → 401. This is what stops a stranger from calling/api/chatdirectly with curl. - Builds an Anthropic message stream with caching, optional web search, optional extended thinking.
- Forwards events back over Server-Sent Events: text deltas, thinking deltas, tool-use notifications, final usage.
api/config.py is a tiny endpoint the frontend calls on load to get the Supabase URL and anon key — that way the keys live in one place (Vercel env vars) instead of being baked into the HTML.
- Calls
/api/config, initializes the Supabase JS client. - If no session, shows the sign-in screen.
- If signed in, loads all your projects/conversations/files from Supabase and renders the app.
- Every database write goes back to Supabase. The frontend keeps an in-memory copy for fast rendering, but the source of truth is the database.
- When you hit Send, it builds an Anthropic-style messages array (with
image,document,textcontent blocks for any attached files) and POSTs to/api/chatwith your Supabase access token in the Authorization header.
Anthropic's prompt caching lets you mark parts of a request as cacheable. This app marks the system prompt and the full conversation prefix on every turn, so on follow-up messages the cached portion is billed at ~10% of normal input price. Only newly-added tokens (your latest message + the model's reply) pay full rate.
The cost number shown in the conversation header reflects this — it's lower than a naive tokens × price estimate.
Two things invalidate the cache:
- Switching the model mid-conversation. Caches are scoped per-model.
- Changing the system prompt. It's part of the cached prefix, so editing it busts the cache.
Caches expire after ~5 minutes of inactivity. Always-on, no toggle — short prefixes silently aren't cached, everything else just gets cheaper.
Dollar amounts shown next to each message are estimates based on Anthropic's published per-million-token pricing at the time this code was written. They give you a sense of "is this expensive?" but they are not a substitute for real billing data. Anthropic occasionally updates pricing.
The single source of truth is your Anthropic Console → Plans & Billing.
To update prices in the UI: edit MODELS in public/app.js. Set both pricePerMillion values to 0 to show tokens without dollar estimates.
You don't need to read every line of this codebase to change it.
- Clone your fork to your computer.
- Open it in Claude Code —
cdinto the folder and runclaude. - Tell Claude what you want. Examples:
- "Anthropic released Sonnet 4.7 — add it to the model list, make it default, remove Sonnet 4."
- "Change the color scheme to match my brand: primary color #6366f1."
- "Add a system-prompt template picker."
- "Render markdown in assistant responses."
- Claude reads the relevant files, proposes the change, edits the code. Review the diff, push to GitHub, Vercel auto-deploys in 30 seconds.
This README and most of this app were built that way.
- Safe out of the box without locking down signups.
⚠️ The auth wall doesn't help you if anyone can sign up — they'd just enter their email, get a magic link, and start spending your Anthropic credits. You must disable signups in Supabase after creating your own account (see docs/SETUP.md Step 6). This is one toggle and it's the difference between "private to you" and "open bar." Don't share your URL until you've done it. - Foolproof. Auth is only as strong as Supabase's user verification. The repo's
.gitignorecovers.env, so secrets don't get committed; if you ever leak credentials, rotate them in Supabase Settings → API and redeploy. - Free of Anthropic charges for your own usage. The auth wall stops other people from costing you money. Your own chats still hit your bill. Set a monthly spending cap at console.anthropic.com → Plans & Billing for peace of mind.
- Without rate limits. Nothing in this code stops a signed-in user (you, by default, after lockdown) from hammering
/api/chat. Add rate-limiting at the Vercel edge or in the function if you need it. - A finished product. It's a learning reference designed to be modified. Markdown rendering, real-time multi-user sync, file storage, batch API — all good extensions.
MIT. Take it, fork it, ship it.
