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 with your form submission data. The API endpoint is:
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: '',
});
// Generate or retrieve session ID (store in localStorage)
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;
};
// Get URL parameters for attribution
const getUrlParam = (name: string) => {
const params = new URLSearchParams(window.location.search);
return params.get(name);
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
// Submit to your backend first
const response = await fetch('/api/contact', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData),
});
if (response.ok) {
// Track in FormTrackr after successful submission
try {
const attribution = {
landingPage: window.location.href,
referrer: document.referrer || null,
utms: {
source: getUrlParam('utm_source'),
medium: getUrlParam('utm_medium'),
campaign: getUrlParam('utm_campaign'),
term: getUrlParam('utm_term'),
content: getUrlParam('utm_content'),
},
gclid: getUrlParam('gclid'),
};
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: attribution,
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent,
}),
});
alert('Thank you for your message!');
setFormData({ name: '', email: '', message: '' });
} catch (error) {
console.error('FormTrackr tracking error:', error);
// Don't fail the form submission if tracking fails
}
}
};
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
Example using vanilla JavaScript:
// Session ID management
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;
}
// Get URL parameter
function getUrlParam(name) {
const params = new URLSearchParams(window.location.search);
return params.get(name);
}
// Track form submission
async function trackFormSubmission(formData) {
const attribution = {
landingPage: window.location.href,
referrer: document.referrer || null,
utms: {
source: getUrlParam('utm_source'),
medium: getUrlParam('utm_medium'),
campaign: getUrlParam('utm_campaign'),
term: getUrlParam('utm_term'),
content: getUrlParam('utm_content'),
},
gclid: getUrlParam('gclid'),
};
try {
const response = 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: attribution,
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent,
}),
});
if (response.ok) {
const data = await response.json();
console.log('Lead tracked:', data.leadId);
}
} catch (error) {
console.error('Tracking error:', error);
}
}
// Use in your form handler
document.getElementById('contact-form').addEventListener('submit', async (e) => {
e.preventDefault();
const formData = {
name: document.getElementById('name').value,
email: document.getElementById('email').value,
message: document.getElementById('message').value,
};
// Submit to your backend first
const response = await fetch('/api/contact', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData),
});
if (response.ok) {
// Track in FormTrackr after successful submission
trackFormSubmission(formData);
}
});Server-Side Example (Node.js)
Example of tracking from a Node.js server:
// Express.js example
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
// (e.g., save to database, send email, etc.)
// Track in FormTrackr
try {
const trackingResponse = 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-generated-session-id',
pageUrl: req.body.pageUrl || req.headers.referer || 'unknown',
formId: 'contact-form',
formName: 'Contact Form',
fields: [
{ name: 'name', value: name },
{ name: 'email', value: email },
{ name: 'message', value: message },
],
contact: {
name: name,
email: email,
},
attribution: req.body.attribution || {},
timestamp: new Date().toISOString(),
userAgent: req.headers['user-agent'],
}),
});
if (trackingResponse.ok) {
const trackingData = await trackingResponse.json();
console.log('Lead tracked:', trackingData.leadId);
}
} catch (error) {
console.error('FormTrackr tracking error:', error);
// Don't fail the request if tracking fails
}
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. This prevents spam submissions 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 deployed on platforms like Netlify or Vercel, we recommend using UseBasin as your primary form backend and spam filter, and then tracking only successful submissions in FormTrackr. This pattern gives you robust spam protection, email notifications, and a reliable delivery layer (UseBasin), while FormTrackr focuses on lead attribution and analytics.
The recommended flow looks like this:
- 1. Your frontend form submits to
https://usebasin.com/f/YOUR_FORM_ID(or a Netlify / Vercel serverless function that then posts to UseBasin). - 2. If UseBasin accepts the request (
response.okor asuccessflag in your API), you treat the submission as valid. - 3. Only then do you call
FormTrackr.track(...)(or/api/collect) with the same fields + attribution data.
This is the pattern used in our production template sites: UseBasin handles spam protection, validation, and delivery. FormTrackr receives only real, accepted submissions so your reporting stays clean.
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. This helps FormTrackr properly attribute multiple form submissions to the same user session.
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. This ensures proper attribution for Google Ads conversions.
4. Handle Errors Gracefully
FormTrackr tracking should never block your form submission. Wrap tracking calls in try-catch blocks and log errors without failing the user's form submission.
5. Include All Form Fields
Include all form fields in the fields array, not just contact information. This ensures complete data capture in your FormTrackr dashboard.
Rate Limiting
The API has rate limiting to prevent abuse:
- 100 requests per minute per project key and IP address combination
- If you exceed the rate limit, you'll receive a
429 Too Many Requestsresponse - Rate limits are 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.
For server-side requests, make sure to include the appropriate headers or configure your project to allow server-side API calls.
CORS (Cross-Origin Resource Sharing)
The API supports CORS and accepts requests from any origin. The API endpoint responds to OPTIONS preflight requests with appropriate CORS headers.
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.
Rate Limit Exceeded (429)
You're sending too many requests. Wait a minute before retrying, or implement request throttling in your application.
Leads Not Appearing in Dashboard
Check the API response for the leadId. If you receive a success response, the lead was created. If it's not appearing in your dashboard, check:
- You're viewing the correct project
- Your browser cache is cleared
- There are no filters applied in the leads view
Need Help?
If you need assistance with the API or have questions:
- Email: support@formtrackr.app
- Dashboard: Sign in to your account