How do you connect forms on a Next.js marketing site?
You connect forms on a Next.js marketing site by posting them to your own server code, a server action or a route handler, which validates the data and then sends it on to your CRM, your inbox and your analytics. The browser never talks to the CRM directly, so API keys stay private and every lead passes the same checks.
This is one of the practical advantages of a coded site over a builder, and it's a big part of why teams pick Next.js for a marketing website in the first place. The trade-off is that someone has to build what a builder gives you for free: validation, spam protection, notifications and retries. This guide covers all of it in one flow, because those pieces fail together when they're built separately.
Should you embed the CRM form or build a custom one?
Build a custom form that submits through the CRM's API if design, speed and data control matter to you. Use the CRM's embed only when you need its built-in features, like progressive profiling, and accept the extra script weight.
Approach | Design control | Page weight | Spam control | Best for |
|---|---|---|---|---|
CRM embed script | Limited, styled with overrides | Heavy third-party script | The CRM's own | Teams that rely on CRM form features |
Custom form + CRM API | Full | Minimal | Yours, layered | Most marketing sites |
Custom form + form service | Full | Minimal | The service's plus yours | Small sites without a CRM |
Custom form + automation tool | Full | Minimal | Yours | Routing leads to several tools |
Third-party form embeds are also a common source of slow interactions, which our guide to Core Web Vitals on Framer, Webflow and Next.js covers. If you're moving off a builder's native forms, see what replaces Webflow forms in Next.js.
What are the steps for a Next.js forms integration?
The reliable pattern has seven steps, and the order matters: validate and save before you send anything anywhere else.
Build the form as a progressive enhancement
Use a normal form element that posts to a server action, so it still submits if JavaScript is slow. Add client-side validation only as a convenience.
Validate on the server
Check every field with a schema library such as Zod. Reject unexpected fields, enforce lengths and normalize emails before anything else runs.
Run spam checks
Check the honeypot field, verify the challenge token with the provider, and apply a per-IP rate limit. Fail quietly for bots and clearly for humans.
Save the submission
Write the lead to a store you own, such as your CMS, a database table or a log, with a status field. This is your safety net.
Send it to the CRM
Call the CRM's API with the mapped fields plus context like page URL and UTM parameters. Mark the saved record as synced or failed.
Notify the team
Send an internal email or chat message through a transactional email service with proper domain authentication.
Confirm and track
Return success to the browser, show a clear confirmation, and only then push the conversion event.
How do you stop form spam without hurting real users?
Stop form spam with layers, because each layer catches a different kind of bot. A honeypot, a low-friction challenge and rate limiting together block most automated spam without making humans solve puzzles.
- Honeypot field. A hidden input that humans never fill. Any submission with a value is dropped. It costs nothing and catches simple bots.
- Invisible or managed challenge. Cloudflare Turnstile or reCAPTCHA issues a token in the browser that your server verifies. Load the script only on pages with forms.
- Rate limiting. Limit submissions per IP and per email over a short window, at the edge or in your server code.
- Content checks. Reject links in name fields, disposable email domains if you sell to businesses, and messages that are only URLs.
- Time check. Forms submitted within a second or two of page load are almost always automated.
Never rely on client-side checks alone. Bots post straight to your endpoint, so every rule has to run on the server.
How do you sync leads to HubSpot or another CRM?
Sync leads by mapping your form fields to the CRM's fields and calling its submission or contacts API from the server. Include the page URL, page title, UTM parameters and, for HubSpot, the tracking cookie value, so attribution survives even though you're not using the embed.
Two details save a lot of pain. First, keep the field mapping in one config file so marketing can add a field without hunting through code. Second, decide what happens when the CRM is down: retry with a queue, or mark the saved record as failed and alert someone. If HubSpot also runs your content, our guide to HubSpot CMS to Next.js explains how the custom front end and HubSpot back office fit together.
Hypothetical example: a demo request flow with routing
For example, suppose a B2B startup has one demo form with company size as a field. The server action validates the form, checks Turnstile and saves the lead. It then creates or updates the contact in the CRM, sets the lifecycle stage and owner based on company size, and posts a message to the sales channel with the lead's details.
If the CRM call fails, the lead stays in the saved log with a failed status, a scheduled job retries it, and the team is alerted after a second failure. The visitor sees the same confirmation either way, because their request was received.
How do you track form conversions accurately?
Track form conversions by pushing one well-named event, such as generate_lead, to the data layer after the server confirms success, with the form name and page as parameters. Tag managers and ad platforms then read that single event.
Respect consent: the event fires either way, but your consent setup decides what each tag may store. For high-value forms, send the conversion server-side as well, so ad blockers don't hide it. Our guide to conversion tracking for lead-gen websites covers naming, deduplication and reporting in detail.
Why are form notification emails not arriving?
Form notification emails usually fail because the sending domain isn't authenticated, so inbox providers treat them as spoofed. Send through a transactional email service and set up SPF, DKIM and DMARC for the domain you send from.
Also avoid sending from the visitor's address, which fails authentication by design; put it in the reply-to header instead. Our guide to email deliverability for website forms walks through each record. Finally, host the endpoint somewhere predictable: our notes on hosting Next.js on Cloudflare Workers cover environment secrets and runtime limits that affect form handlers.
