GUARDLABS
GuardLabs ยท Technical note

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., firstname vs first_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.

Published 2026-07-30 3 min read All articles
Need help with this?

I take on freelance fixes and builds in this area.