Connect a Website Form to Your CRM via Direct API Integration
Directly integrating a website form with a CRM API bypasses third-party integration platforms like Zapier. This approach eliminates monthly task limits, reduces point-to-point latency, and provides complete control over error handling and data transformation.
Architecture Overview and Security Requirements
Never submit form data directly from the client browser to a CRM API using front-end JavaScript. Exposing secret API keys or Bearer tokens in client-side code creates a severe security risk. Additionally, cross-origin resource sharing (CORS) policies on most CRM APIs block direct browser requests.
A secure direct integration uses a two-step architecture:
- Client Side: The HTML form captures user input and sends a JSON payload to your server or serverless function via `fetch()`.
- Server Side: Your server validates the input, formats the payload to match the CRM's requirements, injects authentication headers securely, and performs an HTTP POST request to the CRM API.
Step-by-Step Implementation
1. Client-Side Form and Script
Create the HTML form and intercept the submission event with JavaScript to POST the payload to your backend endpoint (`/api/submit-lead`).
<form id="lead-form">
<input type="text" id="firstName" name="firstName" placeholder="First Name" required />
<input type="email" id="email" name="email" placeholder="Email Address" required />
<button type="submit">Submit</button>
</form>
<script>
document.getElementById('lead-form').addEventListener('submit', async (e) => {
e.preventDefault();
const payload = {
firstName: document.getElementById('firstName').value,
email: document.getElementById('email').value
};
try {
const res = await fetch('/api/submit-lead', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (res.ok) {
alert('Form submitted successfully.');
} else {
alert('Submission failed. Please try again.');
}
} catch (err) {
console.error('Network error:', err);
}
});
</script>
2. Server-Side Handler (Node.js / Express Example)
Create an endpoint to receive the form data, map the fields to the CRM's expected JSON format, and make the authorized API call.
const express = require('express');
const app = express();
app.use(express.json());
app.post('/api/submit-lead', async (req, res) => {
const { firstName, email } = req.body;
if (!email || !firstName) {
return res.status(400).json({ error: 'Missing required fields' });
}
// Map incoming data to the CRM API schema (e.g., HubSpot / Salesforce REST API)
const crmPayload = {
properties: {
firstname: firstName,
email: email
}
};
try {
const crmResponse = await fetch('https://api.hubapi.com/crm/v3/objects/contacts', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.CRM_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(crmPayload)
});
if (!crmResponse.ok) {
const errorDetails = await crmResponse.json();
console.error('CRM API Error:', errorDetails);
return res.status(502).json({ error: 'Failed to push lead to CRM' });
}
const data = await crmResponse.json();
return res.status(200).json({ success: true, recordId: data.id });
} catch (error) {
console.error('Server error:', error);
return res.status(500).json({ error: 'Internal server error' });
}
});
app.listen(3000, () => console.log('Server running on port 3000'));
Key Technical Considerations
- Field Key Mapping: API property keys are case-sensitive and often differ from HTML input names. Verify your CRM's developer documentation for exact internal property names (e.g.,
firstnamevsfirst_name). - Duplicate Logic: Most CRMs reject duplicate primary keys (typically email addresses) with HTTP status `409 Conflict` or `400 Bad Request`. Decide whether your backend should treat duplicates as errors or catch them to perform an update (`PATCH`/`PUT`) call instead.
- Rate Limits: Enterprise CRM APIs impose rate limits (e.g., 100-150 requests per 10 seconds). For high-volume forms, implement a queuing system (like Redis/BullMQ) on your backend to throttle API requests.
- Environment Variables: Always store authentication tokens in environment variables (`process.env.CRM_API_KEY`) rather than hardcoding them inside script files.
Need this done fast? order an integration on FreelanceHunt.
I take on freelance fixes and builds in this area.