Quickstart
By the end of this page the Lettrove editor is open in a React app on your machine, a design is saved, and you have its HTML. Everything below runs exactly as written.
Not using React? There is a page each for Next.js, Vue, Angular, SvelteKit and plain HTML (a script tag, no build step). Each is complete on its own.
You need: a Lettrove account and Node.js 20.19 or newer (check with
node --version).
1. Create a project and copy its test keys
- Sign in at lettrove.com and open Settings → Embed.
- Type a name for your project (if you already have one, click New project first), and under What your users make choose Emails. Click Make project.
- You now see two test keys. Copy both somewhere safe, then click I have stored it safely:
- the secret key,
lt_sk_test_…. It is shown once. It belongs on your server only. - the publishable key,
lt_pk_test_…. It is public; it goes in your page.
- the secret key,
Test keys open the editor on localhost with no other setup, and they are never billed.
2. The token server
The editor opens with a short-lived token. Your server mints it with the secret key, so the secret key never reaches a browser. This is one small Express server; in your product it is one route in the server you already have.
mkdir -p lettrove-quickstart/server
cd lettrove-quickstart/server
npm init -y
npm install express @lettrove/node
Create a file called .env with your secret key in it:
LETTROVE_SECRET_KEY=lt_sk_test_paste_yours_here
Then the server itself:
import express from 'express';
import { Lettrove } from '@lettrove/node';
const lettrove = new Lettrove({ secretKey: process.env.LETTROVE_SECRET_KEY });
const app = express();
// The page asks this route for a token whenever the editor needs one.
app.post('/lettrove-token', async (req, res) => {
// In your product: your own id for the signed-in person, from your session.
const userId = 'demo-user';
try {
const { token } = await lettrove.tokens.create({
user: { id: userId },
origin: req.get('origin'), // the page the editor opens on
});
res.set('Cache-Control', 'no-store').json({ token });
} catch (error) {
console.error(error);
res.status(500).json({ error: error.message, code: error.code });
}
});
app.listen(3000, () => console.log('Token server on http://localhost:3000'));
Start it, and leave it running:
node --env-file=.env server.mjs
3. The React app
In a second terminal, from the lettrove-quickstart folder:
npm create vite@latest app -- --template react-ts
cd app
npm install
npm install @lettrove/react
Send the app's /lettrove-token requests to the token server:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
server: { proxy: { '/lettrove-token': 'http://localhost:3000' } },
});
Replace src/index.css so the editor can fill the window:
html, body, #root { margin: 0; height: 100%; }
And replace src/App.tsx. Put your publishable key where it says so.
import { useRef } from 'react';
import { LettroveEditor, type EditorHandle } from '@lettrove/react';
async function getToken() {
const response = await fetch('/lettrove-token', { method: 'POST' });
return (await response.json()).token;
}
export default function App() {
const editor = useRef<EditorHandle | null>(null);
async function exportHtml() {
const email = await editor.current?.exportHtml();
console.log(email?.html);
}
return (
<div style={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
<button onClick={exportHtml}>Export HTML</button>
<LettroveEditor
ref={editor}
publishableKey="lt_pk_test_paste_yours_here"
getToken={getToken}
onDesignSaved={({ designId }) => console.log('saved', designId)}
style={{ flex: 1 }}
/>
</div>
);
}
4. Run it
npm run dev
Open the address it prints (http://localhost:5173). The editor loads in the page.
-
In the panel on the left, click Heading (or drag it onto the email). A heading appears; click it to type your own words.
-
Open your browser's console (in Chrome: View → Developer → JavaScript Console). Within a moment of your edit it shows:
saved 01J9ZQ3W8D2K7M5T1V4XG6HB0R
That id is the design. Lettrove saves as your user works; in your product you store the id with your
own record (an email campaign, say) and pass it back as designId to open the same design again.
5. Get the email out
Click Export HTML. The console prints the whole email as HTML, compiled for Gmail, Outlook and
Apple Mail, ready to send with any email provider. The same call gives you email.subject, the
plain-text version in email.text, and email.mergeTags: tags such as {{unsubscribe_url}} for
you to fill before sending (Merge tags).
Your server can get the same email later, with the editor closed:
const email = await lettrove.designs.export(designId, { user: { id: 'demo-user' } });
You are done. Everything from here is making it yours.
If something is not right
The editor never shows an empty box: if it cannot open, the box says why, with a code. When the
box says token_invalid, your token route failed — the terminal running the token server prints
the real reason. The usual first-day causes:
| Where | Code | Why | Fix |
|---|---|---|---|
| Terminal | key_invalid | The secret key in .env is wrong, has a space or quote around it, or was revoked | Copy it again, or make a new one in Settings → Embed |
| Terminal | origin_not_allowed | A live secret key on localhost | Use the test keys while you build |
| Terminal | Error: `secretKey` is required | .env was not read | Start the server with node --env-file=.env server.mjs, from the server folder |
| Terminal | `secretKey` is not a Lettrove secret key | A cut-off copy, or a space inside the key | Copy the whole key again |
| Editor box | token_invalid | Your token route did not answer with a token | Read the terminal: one of the lines above. If the terminal is quiet, the app is not reaching the server: check the proxy in vite.config.ts and that the server is running |
| Editor box | frame_blocked | The publishable key is wrong, or your page's Content-Security-Policy blocks the editor | Check the key; then Allowed sites and CSP |
Every code is explained in Troubleshooting.
Where next
- How it fits together: projects, keys, tokens, sites and end users.
@lettrove/react: every prop, and the editor handle.- Getting designs out: HTML, plain text, PNG, PDF and ZIP.
- Options and Theming: make it look like your product.
- Test and live keys: before your users see it.