Add a ContactFire form to any site
Two ways to integrate. The JS snippet takes 30 seconds. The plain HTML form gives you full control over markup and styling.
Two integration approaches
Paste one <script> tag. ContactFire renders the full form for you, styled and ready. Best for most sites.
- No custom HTML needed
- Form updates without re-deploying your site
- Auto-handles spam protection
Write a standard <form> tag and point the action at ContactFire. Full control over markup and CSS.
- Use your own CSS
- Works with any backend or static site
- Needs a redirect URL for success handling
Get your embed token
Both approaches need an embed token. This is a public-safe credential — it is fine to ship it in client-side code.
- Log in to my.contactfire.com
- Go to Embed Tokens in the left sidebar
- Click Create token
- Give it a name (e.g., "My website") and optionally restrict it to your domain
- Copy the token — it starts with
cf_embed_
cf_embed_...) are safe in frontend code. API keys (cf_api_...) are for server-side use only. Learn the difference.Option 1: JS embed snippet
Add two lines of HTML anywhere on your page. ContactFire loads the form asynchronously and renders it inside the #cf-form div.
<!-- Place this where you want the form to appear -->
<div id="cf-form"></div>
<!-- Load the ContactFire embed script -->
<script
src="https://my.contactfire.com/api/embed-script"
data-token="cf_embed_your_token_here"
data-form-id="your_form_public_id"
async
></script>| Attribute | Required | Description |
|---|---|---|
| data-token | Yes | Your embed token (starts with cf_embed_) |
| data-form-id | Yes | 12-character public form ID from Form Studio |
| async | Recommended | Load without blocking page render |
abc123xyz789.Option 2: Plain HTML form
Point a standard HTML form at the ContactFire submission endpoint. Use your own markup and CSS. Works on any static site, WordPress, Webflow, or server-rendered app.
<form
action="https://my.contactfire.com/api/form/submit"
method="POST"
>
<!-- Required: your embed token -->
<input type="hidden" name="_token" value="cf_embed_your_token_here" />
<!-- Optional: redirect after successful submission -->
<input type="hidden" name="_redirect" value="https://yoursite.com/thank-you" />
<!-- Your form fields -->
<label for="name">Name</label>
<input type="text" id="name" name="name" required />
<label for="email">Email</label>
<input type="email" id="email" name="email" required />
<label for="message">Message</label>
<textarea id="message" name="message" rows="4" required></textarea>
<button type="submit">Send message</button>
</form>These names control ContactFire behaviour. Use any other name for your data fields.
| Field name | Purpose |
|---|---|
| _token | Your embed token — required |
| _redirect | URL to redirect to after a successful submission |
| _honeypot | Hidden spam trap — leave empty (ContactFire adds this automatically for embedded forms) |
Domain restrictions
Lock your embed token to specific domains so only your site can use it. This stops anyone else from submitting forms with your token.
- Go to Embed Tokens in your dashboard
- Edit your token
- Add your domain under Allowed domains (e.g.,
yoursite.com) - Save — submissions from other origins are now rejected
yoursite.com and www.yoursite.com if your site is accessible from both.Handle responses with JavaScript
Submit via fetch to show an inline success message instead of a page redirect.
document.querySelector('#contact-form').addEventListener('submit', async (e) => {
e.preventDefault();
const form = e.target;
const data = new FormData(form);
data.append('_token', 'cf_embed_your_token_here');
try {
const res = await fetch('https://my.contactfire.com/api/form/submit', {
method: 'POST',
body: data,
});
if (res.ok) {
// Show your success message
document.querySelector('#success').hidden = false;
form.reset();
} else {
const err = await res.json();
console.error('Submission failed:', err.message);
}
} catch (err) {
console.error('Network error:', err);
}
});{"status":"success","message":"Submission received","submissionId":"abc123"}{"status":"error","message":"Invalid token","code":"INVALID_TOKEN"}Redirect after submit
For plain HTML forms (without JavaScript), add a _redirect hidden field. ContactFire redirects to that URL after a successful submission.
<input type="hidden" name="_redirect" value="https://yoursite.com/thank-you" />If _redirect is not set and no JavaScript intercepts the submit, the browser stays on ContactFire's default confirmation page.
Custom fields
Every input name (except reserved names starting with _) becomes a field in the submission. Name your inputs to match how you want them to appear in the inbox.
<!-- These field names appear as-is in the ContactFire inbox -->
<input type="text" name="full_name" />
<input type="email" name="work_email" />
<input type="text" name="company" />
<select name="budget_range" />
<textarea name="project_brief" rows="5"></textarea>Framework examples
React
import { useState } from 'react';
export default function ContactForm() {
const [status, setStatus] = useState('idle');
async function handleSubmit(e) {
e.preventDefault();
setStatus('loading');
const data = new FormData(e.target);
data.append('_token', 'cf_embed_your_token_here');
const res = await fetch('https://my.contactfire.com/api/form/submit', {
method: 'POST',
body: data,
});
setStatus(res.ok ? 'success' : 'error');
}
if (status === 'success') return <p>Message sent!</p>;
return (
<form onSubmit={handleSubmit}>
<input name="name" type="text" required />
<input name="email" type="email" required />
<textarea name="message" required />
<button type="submit" disabled={status === 'loading'}>
{status === 'loading' ? 'Sending…' : 'Send'}
</button>
</form>
);
}Astro
Download the pre-built Astro component from your dashboard — it includes Live Draft Saving and resume support out of the box.
---
// ContactFireForm.astro — download from Dashboard > Embed Code > Astro tab
import ContactFireForm from './ContactFireForm.astro';
---
<ContactFireForm token="cf_embed_your_token_here" formId="your_form_id" />GET /api/embed-code/{tokenId}?format=astro