> Lettrove docs 1.x · https://docs.lettrove.com/docs/get-started/sveltekit

# SvelteKit

The editor in a SvelteKit app: one server route mints tokens, one page opens the editor with
`createEditor` from `@lettrove/embed`. One process, four small files. Written for SvelteKit 3.

You need a project's two **test** keys from [lettrove.com](https://lettrove.com) → **Settings →
Embed** (step 1 of the [Quickstart](/docs/get-started/quickstart#1-create-a-project-and-copy-its-test-keys)),
and [Node.js](https://nodejs.org) 22.12 or newer (what SvelteKit asks for).

## 1. Create the app and install two packages

```bash
npx sv create lettrove-sveltekit --template minimal --types ts --no-add-ons --install npm
cd lettrove-sveltekit
npm install @lettrove/embed @lettrove/node
```

`@lettrove/embed` opens the editor, in the browser. `@lettrove/node` mints tokens with your secret
key, on the server only.

## 2. Your secret key

Create `.env` in the app's folder:

```bash title=".env"
LETTROVE_SECRET_KEY=lt_sk_test_paste_yours_here
```

SvelteKit reads only the variables you declare. Declare this one in `src/env.ts`; a variable not
marked `public` is handed to server code only, so the key never reaches a browser.

```ts title="src/env.ts"
import { defineEnvVars } from '@sveltejs/kit/env';

export const variables = defineEnvVars({
  LETTROVE_SECRET_KEY: {},
});
```

## 3. The token route

The editor opens with a short-lived **token**. Create `src/routes/lettrove-token/+server.ts`:

```ts title="src/routes/lettrove-token/+server.ts"
import { json } from '@sveltejs/kit';
import { Lettrove } from '@lettrove/node';
import { LETTROVE_SECRET_KEY } from '$app/env/private';
import type { RequestHandler } from './$types';

const lettrove = new Lettrove({ secretKey: LETTROVE_SECRET_KEY });

export const POST: RequestHandler = async ({ request }) => {
  // In your product: your own id for the signed-in person, from your session (locals).
  const userId = 'demo-user';
  const { token } = await lettrove.tokens.create({
    user: { id: userId },
    origin: request.headers.get('origin')!, // the page the editor opens on
  });
  return json({ token }, { headers: { 'Cache-Control': 'no-store' } });
};
```

## 4. The page

Replace `src/routes/+page.svelte`. Put your publishable key where it says so.

```svelte title="src/routes/+page.svelte"
<script lang="ts">
  import { onMount } from 'svelte';
  import { createEditor, type EditorHandle } from '@lettrove/embed';

  let container: HTMLDivElement;
  let editor: EditorHandle | null = null;

  async function getToken() {
    const response = await fetch('/lettrove-token', { method: 'POST' });
    return (await response.json()).token;
  }

  onMount(() => {
    createEditor({
      container,
      publishableKey: 'lt_pk_test_paste_yours_here',
      getToken,
      on: { 'design:saved': ({ designId }) => console.log('saved', designId) },
    }).then((opened) => (editor = opened));
    return () => editor?.destroy();
  });

  async function exportHtml() {
    const email = await editor?.exportHtml();
    console.log(email?.html);
  }
</script>

<div class="page">
  <button onclick={exportHtml}>Export HTML</button>
  <div bind:this={container} class="editor"></div>
</div>

<style>
  :global(body) { margin: 0; }
  .page { height: 100vh; display: flex; flex-direction: column; }
  .editor { flex: 1; }
</style>
```

## 5. Run it

```bash
npm run dev
```

Open the address it prints ([http://localhost:5173](http://localhost:5173)). Add a **Heading** from
the panel on the left; the browser's console prints `saved` and the design's id. Keep that id to
open the same design again: pass it as `designId`. Click **Export HTML** and the console prints the
whole email, compiled for every inbox.

## Next

- If the box shows a code instead of the editor: [the Quickstart's checklist](/docs/get-started/quickstart#if-something-is-not-right).
- [`@lettrove/embed`](/docs/api/embed): every option and method of `createEditor`, and the events.
- [Getting designs out](/docs/editor/exports) · [Theming](/docs/editor/theming) · [Test and live keys](/docs/going-live/test-and-live).
