Announcing dynamic API keys for Appwrite Sites_
Appwrite Sites now mints a scoped, short-lived API key for every build and SSR request, so server-rendered sites call your project without storing a key.

Server-rendered sites regularly need to call Appwrite with more access than a visitor's session grants. Sending an email OTP, creating a team when a customer signs up, or accepting a form submission from an anonymous respondent all need an API key. Until now that meant creating a key in the Console, pasting it into a site environment variable, and remembering to rotate it. The key lived forever, applied to every deployment, and one leaked variable exposed the whole project.
Today we are announcing dynamic API keys for Appwrite Sites. Appwrite now generates a scoped, short-lived key for every site build and every server-side rendering (SSR) request, so your site can call your project without storing a key anywhere.
What dynamic API keys give you
- A key with every request. Appwrite mints a new key for each SSR request and delivers it on the
x-appwrite-keyheader. Build commands get one too, as theAPPWRITE_SITE_API_KEYenvironment variable. - Scopes on the site, not on a key. You grant scopes to the site itself. Every key Appwrite mints carries exactly those scopes and nothing more.
- Expiry for free. A runtime key expires shortly after the site's request timeout. There is nothing to rotate and nothing left behind in a variable list.
- The same model as Functions. If you have used dynamic API keys in Appwrite Functions, the header name, the scope model, and the security rules are identical.
Grant scopes to your site
A site starts with no scopes, so its dynamic key can call nothing until you grant some.
- In the Appwrite Console, navigate to Sites and open the site.
- Under the Settings tab, navigate to the Build section.
- In the Scopes card, select the scopes your server code needs and click Update.
Grant only what the code uses. A key with users.write but not documents.write fails loudly on the first write, which is far easier to notice than a key that can do everything. The scopes parameter on the create site and update site endpoints sets the same list from a Server SDK or the Appwrite CLI.
Read the key in your SSR code
Read the x-appwrite-key header on the server and pass it to setKey. Create the client per request instead of sharing one, because each key belongs to the request that carried it. The endpoint and project ID are already available as APPWRITE_SITE_API_ENDPOINT and APPWRITE_SITE_PROJECT_ID, which Appwrite injects at run time, so nothing needs configuring.
// src/lib/server/appwrite.ts (SvelteKit)
import { env } from '$env/dynamic/private';
import { Client, Users } from 'node-appwrite';
export function createAdminClient(request: Request) {
const client = new Client()
.setEndpoint(env.APPWRITE_SITE_API_ENDPOINT)
.setProject(env.APPWRITE_SITE_PROJECT_ID)
.setKey(request.headers.get('x-appwrite-key')!);
return { users: new Users(client) };
}
The Sites docs show the same pattern for Next.js, Nuxt, and Astro.
When to reach for the dynamic key
The dynamic key acts without a session and bypasses permissions, so it belongs in the small set of places where Appwrite cannot act on the visitor's behalf: sending one-time codes, provisioning resources on sign-up, accepting anonymous submissions, or adding a member by email. Everything a signed-in visitor does should still go through a client bound to their session, as described in Server-side rendering with Appwrite Auth. Appwrite's permission engine then decides what that visitor may read or change, and the key never enters the picture.
If your site already stores an APPWRITE_API_KEY variable, the migration is two steps. Deploy the code that reads the header first, then delete the variable once that deployment is live.
Get started with dynamic API keys in Sites
Dynamic API keys are available today on Appwrite Cloud and in self-hosted Appwrite for every server-rendered site. Grant scopes on the site, read the header, and delete the stored key.





