Live form monitoring
See what visitors are typing — before they hit submit. Live Draft Saving captures partial responses so you can follow up on abandoned forms and help visitors complete them.
What is Live Draft Saving
When Live Draft Saving (LDS) is enabled on a form, ContactFire saves the visitor's answers to the server as they type. If the visitor closes the tab or navigates away without submitting, you still receive their partial data.
Watch drafts appear in real-time in your Live inbox tab.
Get notified after 10 minutes of visitor inactivity on a draft.
Visitors can resume where they left off on any device.
Enable live draft saving
LDS is controlled per-form in Form Studio:
- Open your form in Form Studio
- Click Settings
- Toggle Live Draft Saving on
- Click Save
LDS is off by default. Enable it only for forms where the drop-off data is valuable, since it does store partial visitor data on the server.
How it works
Live tab in your inbox
Your dashboard inbox has a Live tab that shows all partial submissions for forms with LDS enabled. Each entry shows:
- Fields filled in so far
- Last activity timestamp
- Whether the draft was eventually submitted or abandoned
Submitted drafts move from the Live tab to your main inbox automatically.
Draft resume flow
When a visitor returns to the same form on the same browser, the embed script:
- Reads the stored
sessionIdfrom localStorage - Calls
GET /api/public/forms/{formId}/partial?sessionId=... - Pre-fills all previously saved fields
- Picks up from where the visitor left off
The sessionId is per-form and per-browser. A visitor on a different device starts a fresh session.
sessionId is the resume token — pass it on every subsequent save and the final submit. submissionPublicId is a public identifier for the draft record, not a continuation token.Partial submission API
Use the API directly if you are building a custom frontend:
// Save a partial (first save — no sessionId yet)
const res = await fetch(
'https://my.contactfire.com/api/public/forms/YOUR_FORM_ID/partial',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-embed-token': 'cf_embed_your_token',
},
body: JSON.stringify({
data: { name: 'Alice', email: '[email protected]' },
}),
}
);
const { sessionId } = await res.json();
localStorage.setItem('cf_session_YOUR_FORM_ID', sessionId);// Update an existing draft (subsequent saves — pass sessionId)
const sessionId = localStorage.getItem('cf_session_YOUR_FORM_ID');
await fetch(
'https://my.contactfire.com/api/public/forms/YOUR_FORM_ID/partial',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-embed-token': 'cf_embed_your_token',
},
body: JSON.stringify({
sessionId,
data: { name: 'Alice', email: '[email protected]', message: 'Hello' },
}),
}
);// Resume a draft — pre-fill the form on page load
const sessionId = localStorage.getItem('cf_session_YOUR_FORM_ID');
if (sessionId) {
const res = await fetch(
`https://my.contactfire.com/api/public/forms/YOUR_FORM_ID/partial?sessionId=${sessionId}`,
{
headers: { 'x-embed-token': 'cf_embed_your_token' },
}
);
if (res.ok) {
const { data } = await res.json();
// data = { name: 'Alice', email: '[email protected]', ... }
// pre-fill your form fields from `data`
}
}Idle notifications
When a draft has not been updated for 10 minutes, ContactFire sends an email notification so you can follow up. The notification includes the full partial data saved so far.
- Form name
- All fields saved before the visitor went idle
- Timestamp of last activity
- Link to the full draft in your dashboard
Common mistakes
These mistakes show up in almost every custom LDS integration. Check each one before shipping.