Integration guide
Keep the FormDex API key server-side, validate incoming data, forward trusted fields, and preserve upstream status codes.
Step by step
Put the visually hidden honeypot text input in the client form using the exact FormDex setting name.
Read the endpoint and API key from environment variables. Never send the FormDex key to the browser or include it in logs.
If req.body.company contains any value, return a generic success response or a controlled rejection according to your abuse policy; do not call FormDex.
Construct a new payload from approved keys instead of spreading req.body. Include the honeypot key as an empty string after it passes your local check.
Return FormDex’s status and safe response body so the frontend can distinguish validation, authentication, credit, and rate-limit failures.
Use a request timeout, avoid blind retries, and never record secrets or full message bodies in logs.
Honeypot in this integration
For a browser → Node.js → FormDex flow, the browser must render the honeypot and Node.js must reject any non-empty value before forwarding. After that local check, forward the same key as an empty string so the FormDex contract remains explicit. A server-only job does not benefit from a visual honeypot.
Read the honeypot fundamentals →Working example
<!-- Browser: the honeypot must exist where bots can discover it. -->
<form method="POST" action="/contact">
<div aria-hidden="true" style="position:absolute;left:-10000px;width:1px;height:1px;overflow:hidden;">
<label>Leave this field empty
<input type="text" name="company" tabindex="-1" autocomplete="off" />
</label>
</div>
<input type="email" name="email" required />
<textarea name="message" required></textarea>
<button type="submit">Send enquiry</button>
</form>
// Server: parse URL-encoded form bodies before this route.
app.post("/contact", async (req, res) => {
// HONEYPOT: reject locally; never forward a bot submission.
if (String(req.body.company || "").trim()) {
return res.status(400).json({ error: "Spam detected." });
}
const payload = {
email: String(req.body.email || ""),
message: String(req.body.message || ""),
company: "" // Must match the FormDex honeypot field name.
};
try {
const response = await fetch(process.env.FORMDEX_ENDPOINT, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": process.env.FORMDEX_API_KEY,
"Origin": process.env.FORMDEX_ALLOWED_ORIGIN
},
body: JSON.stringify(payload),
signal: AbortSignal.timeout(10_000)
});
const result = await response.json();
return res.status(response.status).json(result);
} catch {
return res.status(502).json({ error: "Form service temporarily unavailable." });
}
});Troubleshooting
401 Invalid API key
Verify the environment variable on the running server and restart safely after changing it.
Timeout or 502
Use a bounded timeout and show a retry option without discarding the visitor’s input.
Unknown fields
Forward only schema keys or enable Dynamic fields intentionally.
Duplicate notifications
Do not retry accepted requests and avoid sending both directly from the browser and through the server.