Embed tokens and API keys
ContactFire uses two token types so you never have to expose a secret in frontend code. The right token depends on where your submission code runs.
Two token types
cf_embed_...- Public-safe: ship in HTML and JavaScript
- Locked to allowed domains
- Used by the JS embed snippet
- Used by the Astro component
- Used by plain HTML forms
cf_api_...- Server-only: never put in frontend code
- Used in
x-api-keyheader - For server-to-server submissions
- No domain restriction (server already trusted)
Which one to use
| Your scenario | Use |
|---|---|
| Plain HTML form on a static site | Embed token |
| JS embed snippet on any page | Embed token |
| Astro component | Embed token |
| React / Vue / Svelte frontend | Embed token |
| WordPress, Webflow, Squarespace | Embed token |
| Next.js / Nuxt / Remix server action | API key |
| Node.js or Python backend script | API key |
| Server-to-server form submission | API key |
Embed tokens
Create an embed token
- In your dashboard, click Embed Tokens
- Click Create token
- Name it (e.g., "Main website" or "Contact page")
- Optionally set allowed domains
- Click Create
- Copy the full token starting with
cf_embed_
Use an embed token
In the JS embed script attribute (recommended: the script handles submission automatically):
<script
src="https://my.contactfire.com/api/embed-script"
data-token="cf_embed_your_token_here"
data-form-id="your_form_id"
async
></script>In a plain HTML form (add data-contactfire-token; embed script intercepts the submit):
<script src="https://my.contactfire.com/api/embed-script" async></script>
<form data-contactfire-token="cf_embed_your_token_here">
<input type="text" name="name" />
<input type="email" name="email" />
<button type="submit">Send</button>
</form>In a fetch request (send as JSON with X-Embed-Token header):
await fetch('https://my.contactfire.com/api/form/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Embed-Token': 'cf_embed_your_token_here',
},
body: JSON.stringify({
formData: {
name: 'Alice',
email: 'alice@example.com',
},
}),
});API keys
Create an API key
- In your dashboard, click API Keys
- Click Create key
- Name it (e.g., "Backend integration")
- Click Create
- Copy the full key: it is only shown once
Use an API key
Send the key in the x-api-key header:
// Node.js example
const res = await fetch('https://my.contactfire.com/api/form/submit', {
method: 'POST',
headers: {
'x-api-key': process.env.CONTACTFIRE_API_KEY, // cf_api_...
'Content-Type': 'application/json',
},
body: JSON.stringify({
formData: {
name: 'Alice',
email: 'alice@example.com',
message: 'Hello from the backend',
},
}),
});
const result = await res.json();
// { message: 'Form submission received successfully', submissionId: 'abc123xyz', status: 'accepted', usage: {...} }Domain restrictions (embed tokens)
Restrict an embed token to specific domains. Submissions from unlisted origins are rejected with a 403 response.
- One domain per line:
yoursite.com - Include www separately if needed:
www.yoursite.com - Wildcard subdomains supported:
*.yoursite.com - Leave blank to allow all origins (not recommended for production)
Recipient overrides
Both token types support custom notification recipients. Useful when different tokens are used for different departments or clients.
- Per-form notification recipients (Form Studio โ Settings)
- Embed token recipient override
- API key recipient override
- Account notification email (Settings โ Notifications)
- Account email
Rotating and revoking
Create a new token, update your site, then delete the old token. No downtime: both tokens are valid until the old one is deleted.
Delete a token from the dashboard to revoke it instantly. Submissions using that token are rejected immediately.