> ## Documentation Index
> Fetch the complete documentation index at: https://docs.heretic.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# SvelteKit

> Verify a widget form in a SvelteKit server route.

This `/check` route serves the widget form and saves one receipt after server verification. The complete example uses Node 24+ with adapter-node and persistent SQLite storage.

## Install the example

[Download the server examples](https://heretic.tech/downloads/heretic-server-examples.zip). Put the extracted directory at `src/lib/server/server-examples`, then add `src/routes/check/+server.js`:

```js theme={"dark"}
import { env } from '$env/dynamic/private';
import { fromEnvironment } from '$lib/server/server-examples/examples/lib/form-flow.mjs';

export const prerender = false;
let flow;
const handle = ({ request }) => (flow ??= fromEnvironment(env)).handle(request);
export const GET = handle;
export const POST = handle;
```

The [SvelteKit server route](https://svelte.dev/docs/kit/routing#server) returns a plain HTML form on GET and checks its POST. The code and secret stay in server-only modules.

Copy the archive's `.env.example` into your app's private environment. Set `APP_ORIGIN=http://localhost:5173` for Vite's default development port. Run your app and open `/check`. The supplied test keys save a receipt without running measurements or a phone ceremony.

For production, use [your verified site's keys](/integration/plain-html#2-use-your-keys), set `HERETIC_ALLOW_TEST=false`, and set `APP_ORIGIN` to the exact HTTPS origin. With adapter-node, configure SvelteKit's `ORIGIN` to the same value when serving behind your reverse proxy.

## Keep the backend check

The shared handler checks Origin and the HttpOnly browser-session cookie, then verifies the token against the saved attempt ID, action, site and hostname. It chooses `policy: "uncontradicted"` on the server. The widget attributes control presentation; the backend chooses [what proof authorizes the write](/api/siteverify-endpoint#request).

Failures return an error page. A network timeout leaves the action pending, and the same submission can be retried. A completed attempt returns its existing receipt. Test proofs are rejected outside explicit local test mode.

Replace the receipt write in `examples/lib/form-flow.mjs` with your business write in the same transaction. Save the authenticated account and operation data with the attempt when your action needs them.

## Use your deployment's database

The bundled store needs persistent local storage. A Cloudflare or other serverless adapter needs your shared database's transaction and unique constraint in place of SQLite. The [Node API client](/integration/server-clients) uses fetch and can run separately from the Node-specific example store.

The example returns `Cache-Control: no-store` and a CSP that permits Heretic scripts and frames. Merge those sources into your existing page policy when moving the form into a Svelte component. For explicit widget rendering during client navigation, remove the widget when the component unmounts using [`heretic.remove()`](/integration/challenge-widget#script-api).


## Related topics

- [Node, Python and PHP](/integration/server-clients.md)
- [Quickstart](/quickstart.md)
- [Signal reference](/reference/signals.md)
