API Documentation
Track form submissions programmatically using FormTrackr's API. Perfect for React, Vue, Angular, and other custom implementations.
Overview
FormTrackr's API allows you to track form submissions directly from your application without using the default JavaScript snippet. This is ideal for:
- React, Vue, Angular, and other JavaScript frameworks
- Single-page applications (SPAs) with programmatic form handling
- Multi-step forms that don't trigger native submit events
- Server-side form processing
- Custom form validation and submission logic
Note: If you're using standard HTML forms, you can use our default tracking snippet which automatically captures form submissions. This API documentation is for custom implementations.
Getting Started
Step 1: Get Your Project Key
Log in to your FormTrackr dashboard and navigate to your project. Your Project Key is displayed in the project settings. This unique identifier is required for all API requests.
Step 2: Make API Requests
Send POST requests to the FormTrackr API endpoint:
https://formtrackr.app/api/collectAPI Endpoint
/api/collectRequest Headers
Content-Type: application/json
Request Body
{
"projectKey": "string (required)",
"sessionId": "string (required)",
"pageUrl": "string (required, valid URL)",
"formId": "string (optional)",
"formName": "string (optional)",
"fields": [{ "name": "string", "value": "string" }],
"contact": {
"name": "string (optional)",
"email": "string (optional, valid email)",
"phone": "string (optional)"
},
"attribution": {
"landingPage": "string (optional)",
"referrer": "string (optional)",
"utms": {
"source": "string (optional)",
"medium": "string (optional)",
"campaign": "string (optional)",
"term": "string (optional)",
"content": "string (optional)"
},
"gclid": "string (optional)"
},
"timestamp": "string (optional, ISO 8601)",
"userAgent": "string (optional)"
}Response
Success response (200):
{ "success": true, "leadId": "string", "requestId": "string" }Error responses:
- 400 Bad Request: Invalid request data or missing required fields
- 403 Forbidden: Domain not allowed (if domain allowlist is configured)
- 429 Too Many Requests: Rate limit exceeded
- 500 Internal Server Error: Server error
React Example
Here's a complete example of tracking a form submission in a React component:
import React, { useState } from 'react';
const ContactForm = () => {
const [formData, setFormData] = useState({ name: '', email: '', message: '' });
const getSessionId = () => {
let sessionId = localStorage.getItem('formtrackr_session_id');
if (!sessionId) {
sessionId = Math.random().toString(36).substring(2) + Date.now().toString(36);
localStorage.setItem('formtrackr_session_id', sessionId);
}
return sessionId;
};
const getUrlParam = (name) => new URLSearchParams(window.location.search).get(name);
const handleSubmit = async (e) => {
e.preventDefault();
const response = await fetch('/api/contact', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData),
});
if (response.ok) {
try {
await fetch('https://formtrackr.app/api/collect', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
projectKey: 'YOUR_PROJECT_KEY',
sessionId: getSessionId(),
pageUrl: window.location.href,
formId: 'contact-form',
formName: 'Contact Form',
fields: [
{ name: 'name', value: formData.name },
{ name: 'email', value: formData.email },
{ name: 'message', value: formData.message },
],
contact: { name: formData.name, email: formData.email },
attribution: {
landingPage: window.location.href,
referrer: document.referrer || null,
utms: {
source: getUrlParam('utm_source'),
medium: getUrlParam('utm_medium'),
campaign: getUrlParam('utm_campaign'),
},
gclid: getUrlParam('gclid'),
},
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent,
}),
});
} catch (error) {
console.error('FormTrackr tracking error:', error);
}
}
};
return (
<form onSubmit={handleSubmit}>
<input type="text" value={formData.name} onChange={(e) => setFormData({...formData, name: e.target.value})} placeholder="Name" required />
<input type="email" value={formData.email} onChange={(e) => setFormData({...formData, email: e.target.value})} placeholder="Email" required />
<textarea value={formData.message} onChange={(e) => setFormData({...formData, message: e.target.value})} placeholder="Message" required />
<button type="submit">Submit</button>
</form>
);
};
export default ContactForm;Plain JavaScript Example
function getSessionId() {
let sessionId = localStorage.getItem('formtrackr_session_id');
if (!sessionId) {
sessionId = Math.random().toString(36).substring(2) + Date.now().toString(36);
localStorage.setItem('formtrackr_session_id', sessionId);
}
return sessionId;
}
async function trackFormSubmission(formData) {
try {
await fetch('https://formtrackr.app/api/collect', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
projectKey: 'YOUR_PROJECT_KEY',
sessionId: getSessionId(),
pageUrl: window.location.href,
fields: [
{ name: 'name', value: formData.name },
{ name: 'email', value: formData.email },
],
contact: { name: formData.name, email: formData.email },
attribution: {
gclid: new URLSearchParams(window.location.search).get('gclid'),
utms: {
source: new URLSearchParams(window.location.search).get('utm_source'),
medium: new URLSearchParams(window.location.search).get('utm_medium'),
campaign: new URLSearchParams(window.location.search).get('utm_campaign'),
},
},
timestamp: new Date().toISOString(),
}),
});
} catch (error) {
console.error('Tracking error:', error);
}
}
document.getElementById('contact-form').addEventListener('submit', async (e) => {
e.preventDefault();
const formData = {
name: document.getElementById('name').value,
email: document.getElementById('email').value,
};
const response = await fetch('/api/contact', {
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(formData),
});
if (response.ok) trackFormSubmission(formData);
});Server-Side Example (Node.js)
const express = require('express');
const fetch = require('node-fetch');
const app = express();
app.use(express.json());
app.post('/api/contact', async (req, res) => {
const { name, email, message } = req.body;
// Process your form submission here...
try {
await fetch('https://formtrackr.app/api/collect', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
projectKey: process.env.FORMTRACKR_PROJECT_KEY,
sessionId: req.body.sessionId || 'server-session',
pageUrl: req.headers.referer || 'unknown',
fields: [
{ name: 'name', value: name },
{ name: 'email', value: email },
{ name: 'message', value: message },
],
contact: { name, email },
attribution: req.body.attribution || {},
timestamp: new Date().toISOString(),
userAgent: req.headers['user-agent'],
}),
});
} catch (error) {
console.error('FormTrackr tracking error:', error);
}
res.json({ success: true });
});
app.listen(3000);Best Practices
1. Track After Successful Submission
Always track form submissions after your form has been successfully processed to prevent spam from being tracked.
❌ Don't: Track before validation or submission
✅ Do: Track only after successful backend submission
1.1 Recommended: UseBasin + FormTrackr (Static Sites)
For static sites on Netlify or Vercel, use UseBasin as your primary form backend and spam filter. Track only successful submissions in FormTrackr. UseBasin handles spam protection and delivery; FormTrackr focuses on lead attribution and analytics.
2. Session ID Management
Generate a unique session ID when a user first visits your site and store it in localStorage. Reuse the same session ID for all form submissions during that session to ensure proper attribution.
3. Capture Attribution Data
Capture UTM parameters and GCLID from the URL when the user first lands on your site. Store this data and include it in all form submission tracking requests.
4. Handle Errors Gracefully
FormTrackr tracking should never block your form submission. Wrap tracking calls in try-catch blocks.
Rate Limiting
- 100 requests per minute per project key and IP address combination
- Exceeding the rate limit returns a
429 Too Many Requestsresponse - Rate limits reset after the time window expires
Domain Allowlist
If you've configured a domain allowlist in your project settings, API requests must originate from an allowed domain. The API checks the Origin or Referer header to validate the request source.
Field Reference
Required Fields
projectKey— Your project's unique identifiersessionId— Unique session identifier (generate and store in localStorage)pageUrl— Valid URL of the page where the form was submitted
Optional Fields
formId— HTML form element IDformName— HTML form element name attributefields— Array of form field name/value pairscontact— Object with name, email, and/or phoneattribution— UTM parameters, GCLID, referrer, etc.timestamp— ISO 8601 timestamp (defaults to current time)userAgent— User agent string (defaults to request header)
Troubleshooting
Invalid Project Key (400)
Make sure you're using the correct project key from your FormTrackr dashboard. Project keys are case-sensitive.
Domain Not Allowed (403)
If you've configured a domain allowlist, ensure your request originates from an allowed domain. Check the Origin or Referer header.
Leads Not Appearing in Dashboard
- You're viewing the correct project
- Your browser cache is cleared
- There are no filters applied in the leads view
Need Help?
- Email: support@formtrackr.app
- Dashboard: Sign in to your account