Send a Webflow Form to HubSpot

Build a Webflow Cloud route that sends form submissions directly to HubSpot.

Introduction

30 Second Summary

When someone fills in your website form, you expect their details to reach your team quickly. Extra handoffs can delay that journey. They can also leave the same data sitting in more places.

In this project, you will connect a website form directly to HubSpot through an API route you own. You will keep visitors on the page while a hidden honeypot filters bot submissions before they reach your CRM.

What You'll Build

When you demo the finished site, a form submission stays on the page while the matching contact lands in HubSpot through your route.

By the end of this project, you'll have:

  • A direct CRM route that maps submitted fields to HubSpot properties. A test request returns a 200 response with an ok body.
  • A page-friendly form experience that sends data to your own route without taking the visitor away from the page.
  • A spam trap that drops honeypot submissions before they create contacts in HubSpot.
  • An optional Secret Mission to push your direct CRM integration skills further.

Are there any prerequisites?

You need a HubSpot account with a form plus an existing Next.js app.

You also need Node.js installed plus a Webflow site ready for the live deployment.

Before We Start

Your future route crosses several systems before one contact appears. A missing login or test tool would stop that journey before your code can run.

In this step, you will prepare HubSpot, Webflow Cloud, curl, and Chrome DevTools. You will also confirm access to the website form that starts the workflow.

In this step, get ready to:
  • Create your HubSpot account.
  • Confirm access to your Webflow Cloud project and website form.
  • Verify your local request and browser inspection tools.
Create your HubSpot account

HubSpot holds the contact record created by each accepted submission. Your account gives you a destination for the route you build later.

This signup uses your login details. HubSpot handles those details inside its own account flow, so you never paste a password into this project.

  • Open the official HubSpot account creation page.
  • Enter your email address in the Email field.
  • Click Continue.
  • Complete the requested account details.
  • Finish any account verification that HubSpot sends you.

Your contact destination is ready. You should now be signed in to HubSpot with access to your account.

Having trouble creating your account?

  • Check that you entered an email address you can access.
  • Look for the verification message in your spam folder if it does not reach your inbox.
  • Ask for help with my HubSpot account setup.
Confirm Webflow Cloud and form access

Webflow Cloud hosts the route when you deploy it. Your website project contains the form that sends data to that route.

  • Open the official Webflow login page in Google Chrome.
  • Sign in with the account that has access to your website project.
  • Complete the visible account prompts if this is your first Webflow login.
  • Open the workspace that contains your website.
  • Open the settings for the site project that contains your form.
  • Select Webflow Cloud.
  • Open the Webflow Cloud project associated with this site.

You should see the Cloud project overview. This confirms that your account can reach the deployment target.

  • Return to the website project.
  • Open the page that contains the form you plan to connect.
  • Select the form in the site editor to confirm that its fields are editable.

Both ends of the workflow are now within reach. HubSpot can hold the contact record. Webflow gives you control of the form that creates it.

Cannot see the Webflow Cloud project?

  • Confirm that you signed in with the account invited to the correct workspace.
  • Ask the workspace owner to grant access to the website project if it is missing.
  • Ask for help with finding my Webflow Cloud project.
Verify curl and Chrome DevTools

The curl command sends HTTP requests from your terminal. Chrome DevTools records the requests made by your form page.

  • Press Cmd+Space on macOS or the Windows key on Windows to open system search.
  • Type Terminal on macOS or PowerShell on Windows.
  • Press Enter to open the terminal.

Before you run the check, do you expect your terminal to find curl immediately?

  • Check whether curl is available by running this command:
curl --version

What does this command check?

The curl command prints its version and build details when your shell can locate it. That output confirms your terminal is ready to send local test requests.

Your terminal now shows either curl version details or a message explaining that the command is unavailable.

✔️ I see version details

That check worked. Curl is ready to test your API route from the command line.

ⓧ I do not see version details

Your shell cannot locate curl yet. Install a build for your operating system before continuing.

  • Open the official curl download page.
  • Select the download entry that matches your operating system.
  • Follow the installation instructions supplied by the listed provider.
  • Return to your terminal after the installation finishes.
  • Verify the installation by running this command:
curl --version

What confirms the installation?

A version line confirms that your terminal can now locate curl. The remaining lines describe the protocols and features included in that build.

Still missing curl output?

  • Close your terminal after installation to clear its old command lookup state.
  • Open a fresh terminal through system search.
  • Ask for help with making curl available in my terminal.
  • Switch back to the website form in Google Chrome.
  • Press Cmd+Option+I on macOS or Ctrl+Shift+I on Windows to open Chrome DevTools.
  • Click Network in the action bar at the top.

Before you reload the page, do you expect the Network panel to stay empty or fill with requests?

  • Reload the website form using the browser reload button.

You should see rows appear in the Network panel as the page loads its document and other resources. This proves that Chrome DevTools is ready to capture the form request later.

DevTools not opening?

  • Click inside the browser page before trying the keyboard shortcut again.
  • Open the Chrome menu if the shortcut still does not work.
  • Select More Tools.
  • Select Developer Tools.
  • Ask for help with opening the Network panel in Chrome DevTools.

Your accounts and test tools are ready. Next up, you will create the HubSpot form that defines your route's field map.

Create Your HubSpot Form

Your website already collects visitor details. HubSpot still needs a form that defines which CRM properties can receive those details.

You will create the receiving form in HubSpot. Its submission endpoint plus property names become the contract for your local route.

In this step, get ready to:
  • Create a blank form in HubSpot.
  • Map every website field to a HubSpot property.
  • Publish the form and record its integration values.
Create the receiving form

HubSpot validates each API submission against the fields on its target form. Starting with a blank form gives you control over that receiving structure.

  • Return to the browser tab for your HubSpot account.
  • Sign in with the HubSpot account prepared for this project.
  • Click More in the top navigation if it appears.
  • Select Marketing from the navigation menu.
  • Select Forms.
  • Click Create form in the top right.
  • Select Form Editor.
  • Click Next.

The template screen controls the starting shape of your form. A blank template keeps the field list focused on your website submission.

  • Select Start from blank.
  • Click Use template.

You will see a new form in the form editor. The preview area is ready for the fields that receive your website data.

Can't access the form editor?

  • Confirm that you signed in to the HubSpot account prepared for this project.
  • Ask your HubSpot administrator to grant the Edit forms permission if the creation controls are missing.
  • Help me find the HubSpot form editor in my account.
Map the website fields

Each form field connects to a specific HubSpot property. Your route later sends the property's internal name with the visitor's value.

  • Switch back to the website form tab from earlier.
  • Read the label on the first visitor-facing field.
  • Return to the HubSpot form editor.
  • Click the add icon in the top left.
  • Drag the matching field type from the Fields panel onto the form preview.
  • Search for the matching property in the Edit field panel.
  • Select the matching property.
  • Repeat this mapping sequence for each remaining website field.

The form preview now shows one receiving field for every value collected by your website form.

Can't find a matching property?

  • Click Create new property in the Edit field panel.
  • Enter the website field's label in the Property label field.
  • Select a compatible option from the Field type menu.
  • Click Create property.
  • Help me choose a HubSpot property type for my website field.
  • Click the first field in the form preview.
  • Expand Field options in the left panel.
  • Set Required field to match the corresponding website field.
  • Repeat this requirement check for every remaining field.

Your HubSpot form now mirrors the fields that visitors complete on the website. Required fields also match across both forms.

Why internal names matter

A property label is the name displayed to people inside HubSpot. The internal name is the stable identifier used by integrations.

Your route uses these internal names when it builds a submission. A precise list prevents values from landing in the wrong properties.

Internal names sit in a different settings screen, so this part is easy to miss.

  • Click the settings icon in the top navigation bar.
  • Select Properties from the left sidebar.
  • Open the Select an object menu.
  • Select Contact properties.
  • Search for the first property connected to your form.
  • Click the property name.
  • Copy the Internal name.
  • Repeat this property check for every field on your form.

You now have one internal property name for every field that your route needs to send.

  • Record the internal names as a comma-separated list here: your comma-separated HubSpot property names.
Publish and record the endpoint

Publishing activates the form for submissions. The form GUID plus your Hub ID identify its unique submission endpoint.

  • Click More in the top navigation if it appears.
  • Select Marketing from the navigation menu.
  • Select Forms.
  • Hover over the form you created.
  • Click Edit.
  • Click your account name in the upper right.
  • Copy the numeric Hub ID shown under Account.

The Hub ID identifies the HubSpot account that owns your form.

  • Click Review and update in the top right.
  • Click Update at the bottom of the right panel.
  • Click Get embed code.
  • Find the data-form-id attribute in the embed code.
  • Copy the data-form-id attribute value.

Your form is now published. The copied data-form-id value is its unique GUID.

How the endpoint fits together

HubSpot's Forms API receives unauthenticated form posts at https://api.hsforms.com/submissions/v3/integration/submit/{portalId}/{formGuid}.

Your Hub ID replaces {portalId}. The data-form-id value replaces {formGuid}.

  • Store https://api.hsforms.com/submissions/v3/integration/submit/{portalId}/{formGuid} here: your HubSpot form submission endpoint.
  • Replace {portalId} inside the stored value with your Hub ID.
  • Replace {formGuid} inside the stored value with the copied data-form-id value.
  • Close the embed code dialog.

Does the endpoint look incomplete?

  • Reopen Get embed code if the form GUID is missing.
  • Copy the data-form-id value without its surrounding quotation marks.
  • Reopen the account menu if the Hub ID is missing.
  • Help me verify my HubSpot form submission endpoint.

Before you check, predict whether the form list shows Draft or Published.

  • Return to the Forms list.
  • Locate the form you created.
  • Inspect your HubSpot form submission endpoint.
  • Compare your comma-separated HubSpot property names with the fields in your screenshot.

You will see Published in the Publish Status column. Your saved endpoint begins with https://api.hsforms.com/submissions/v3/integration/submit/.

Your recorded property count matches the fields in the form editor. Each recorded value is an internal name from the property settings.

Your published HubSpot form now defines every value your website can send. Next up, you will build the local route and prove that it can return a successful response.

Build and Test the API Route

Your HubSpot form is ready to receive data. The missing link is a route you control between the website form and HubSpot.

A Next.js Route Handler can receive a form post at /api/hubspot-form. It reshapes each submitted field for HubSpot before returning a clear result to the caller.

In this step, get ready to:
  • Start the local development server.
  • Create the API route that forwards form submissions to HubSpot.
  • Send a test submission with curl.
Start the local server

The development server gives you a fast feedback loop while you build the route. It prints the local address that curl needs for the test request.

  • Return to the terminal in your local development environment.
  • Start the development server by running this command:
npm run dev

What does this command do?

The npm run dev command starts the development script configured by your project. Next.js then serves the app locally while watching for saved changes.

You should see the development server finish starting. The terminal also shows the local URL for your app.

  • Record the local URL here: http://localhost:3000.
  • Leave the development server running in this terminal.

Server not starting?

  • Confirm that the terminal is inside the Webflow Cloud project containing your existing Next.js app.
  • Check that the project dependencies from your local environment are still installed.
  • Share the terminal output with help me troubleshoot my local Next.js development server.
Build the forwarding route

The route receives browser-style form data through POST. Each incoming field becomes a HubSpot property object with a name and a value.

  • Switch back to your Webflow Cloud project in your code editor.
  • Use the editor's new-file control to create src/app/api/hubspot-form/route.ts.
  • Add the forwarding route by pasting this code into route.ts:
export async function POST(request: Request) {
  // Read the submitted website fields from the request.
  const formData = await request.formData()

  // Map each submitted entry to a HubSpot property.
  const fields = Array.from(formData.entries()).map(([name, value]) => ({
    name,
    value: String(value),
  }))

  // Forward the mapped properties to the saved HubSpot form endpoint.
  const hubspotResponse = await fetch(process.env.HUBSPOT_FORM_ENDPOINT!, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ fields }),
  })

  // Surface a rejected HubSpot submission to the original caller.
  if (!hubspotResponse.ok) {
    return Response.json({ ok: false }, { status: hubspotResponse.status })
  }

  // Confirm that HubSpot accepted the valid submission.
  return Response.json({ ok: true }, { status: 200 })
}

What does this code do?

  • The POST() handler makes /api/hubspot-form accept form submissions.
  • The request.formData() call reads the fields sent by the browser or curl.
  • The fields array converts every entry into the property shape expected by HubSpot.
  • The fetch() call sends those properties to the endpoint stored in HUBSPOT_FORM_ENDPOINT.
  • A rejected HubSpot request returns its failure status to the caller.
  • An accepted HubSpot request returns 200 with an ok body.
  • Save src/app/api/hubspot-form/route.ts.
  • Return to the terminal running the development server.

You should see the server finish compiling the saved route without a TypeScript error. That confirms the new endpoint is ready for a request.

Route not compiling?

  • Confirm that the file path ends with api/hubspot-form/route.ts.
  • Check that every opening brace in route.ts has a matching closing brace.
  • Compare the environment variable reference with the saved name HUBSPOT_FORM_ENDPOINT.
  • Share the compiler output with help me fix my HubSpot Route Handler.

✔️ Awesome, I've got everything!

Your local server has compiled the new HubSpot forwarding route.

ⓧ I'd like to double check the full code

Here is the complete code for src/app/api/hubspot-form/route.ts at this point.

export async function POST(request: Request) {
  // Read the submitted website fields from the request.
  const formData = await request.formData()

  // Map each submitted entry to a HubSpot property.
  const fields = Array.from(formData.entries()).map(([name, value]) => ({
    name,
    value: String(value),
  }))

  // Forward the mapped properties to the saved HubSpot form endpoint.
  const hubspotResponse = await fetch(process.env.HUBSPOT_FORM_ENDPOINT!, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ fields }),
  })

  // Surface a rejected HubSpot submission to the original caller.
  if (!hubspotResponse.ok) {
    return Response.json({ ok: false }, { status: hubspotResponse.status })
  }

  // Confirm that HubSpot accepted the valid submission.
  return Response.json({ ok: true }, { status: 200 })
}
Send a test submission

Your test body needs the HubSpot property names you recorded earlier. Including every required property gives HubSpot enough information to accept the submission.

  • Build a test body from the recorded HubSpot property names using safe test values.
  • Store the complete test body here: email=route-test@example.com&firstname=RouteTest.
  • Add every property marked as required on your HubSpot form to the test body.
  • Create a second terminal panel beside the running development server.

Before you run this, predict the status and body your route will return.

  • Send the test submission through your local route by running this command:
curl -i --request POST --data '[[TEST_FORM_BODY="email=route-test@example.com&firstname=RouteTest"]]' '[[LOCAL_APP_URL="http://localhost:3000"]]/api/hubspot-form'

What does this command do?

  • The -i option includes the response headers so you can inspect the status.
  • The --request POST option sends the request through the route's POST() handler.
  • The --data option supplies the test form fields as the request body.
  • The final URL targets /api/hubspot-form on your running local app.

You should see a response status containing 200. The response body should contain {"ok":true}.

You now have a working local bridge from a form post to HubSpot. The curl request reached your route before the route forwarded the mapped properties.

Not seeing a 200 response?

  • Confirm that the local URL matches the address printed by the running development server.
  • Check that the test body includes every required HubSpot form property.
  • Compare each test-body key with the recorded HubSpot internal property name.
  • Confirm that the saved HUBSPOT_FORM_ENDPOINT value is the complete form submission endpoint.
  • Share the response status with help me debug my local HubSpot form submission.

Your API route now accepts form posts and forwards them to HubSpot. Next, you will return to HubSpot to confirm that this curl submission created the expected contact.

Verify the HubSpot Contact

The 200 response with an ok body confirms that your API route at /api/hubspot-form handled the test submission.

The matching HubSpot contact confirms the full path into your CRM. In this step, you will locate that contact and compare its stored properties with the submitted values.

In this step, get ready to:
  • Locate the test contact in HubSpot Contacts.
  • Verify every mapped property against the valid curl submission.
Find the test contact

HubSpot stores each person as a contact record. The Contacts index has a focused Search field for matching the email address from your curl test.

Finding the right search box can be fiddly because HubSpot also has a global search. Use the field directly above the contacts table for this check.

  • Return to the signed-in HubSpot browser tab from earlier.
  • Click More in the top navigation if it appears.
  • Click CRM in the navigation menu.
  • Select Contacts.
  • Enter the email address from your valid curl submission in the Search field above the table.
  • Click the matching contact's name.

You should see the contact record created by your valid curl submission.

Can't Find the Contact?

  • Confirm that the Search field contains the same email address used in the valid curl submission.
  • Use the Search field directly above the contacts table.
  • Refresh the contacts list after a short wait.
  • Ask for help to trace the missing HubSpot test contact.
Verify the mapped properties

Contact creation proves that HubSpot accepted the submission. Matching property values proves that /api/hubspot-form forwarded the fields under the expected HubSpot property names.

  • Predict whether every mapped value matches the valid curl submission.
  • Click Actions in the contact record.
  • Select View all properties.
  • Locate each HubSpot property name recorded during the form setup.
  • Compare each displayed value with the data sent in the valid curl submission.

You should see every mapped property holding the same value as the valid curl submission.

What Does This Prove?

  • The valid form data reached /api/hubspot-form.
  • The route mapped the submitted fields to the recorded HubSpot property names.
  • HubSpot stored those values on the new contact record.

That closes the end-to-end loop. Your route has produced a CRM record with the expected data.

Seeing a Missing or Incorrect Value?

  • Open View all properties if a mapped property is absent from the contact summary.
  • Compare the missing property's internal name with the name recorded during the HubSpot form setup.
  • Repeat the valid curl test from earlier after resolving any mismatch.
  • Ask for help to trace the property mapping mismatch.

Your curl test now exists as a verified HubSpot contact. Next, you will connect the website form to /api/hubspot-form so a browser submission follows the same path.

Connect the Browser Form

Your API route already creates a contact in HubSpot from a direct request. The website form still follows the browser's default submission flow.

That default flow can take visitors away from the page. Browser-side JavaScript can capture the submission before navigation begins.

The handler posts the current fields to /api/hubspot-form. Your route remains the only path into the CRM.

In this step, get ready to:
  • Add a submit handler to the existing website form.
  • Stop the browser's default form navigation.
  • Confirm a POST request reaches your API route in the Network tab.
Add the browser submit handler

The submit event fires when a visitor sends the form. Calling event.preventDefault() stops the browser's native navigation.

  • Return to the code for the existing website form.
  • Add the browser handler immediately after the form markup by pasting this code:
<script>
  // Attach the handler to the existing website form
  const form = document.querySelector("form");

  form.addEventListener("submit", async (event) => {
    // Keep the visitor on the page while the route handles the submission
    event.preventDefault();

    // Preserve the website field names for the API route's existing mapping
    const formData = new FormData(form);

    // Send the submission to the route you own
    await fetch("/api/hubspot-form", {
      method: "POST",
      body: formData,
    });
  });
</script>

What does this script do?

  • The document.querySelector("form") line finds the existing website form.
  • The submit listener runs the handler whenever a visitor submits that form.
  • The event.preventDefault() call keeps the visitor on the current page.
  • The FormData object collects the current values using each field's existing name.
  • The fetch() call sends those fields to /api/hubspot-form in a POST request.
  • Save the file that contains the website form.
  • Reload the local form page in your browser.

You should see the existing form render with all of its fields. This confirms the new script has not blocked the page from loading.

Form page not loading?

  • Check that the opening <script> tag has a matching </script> tag.
  • Confirm the script sits after the form markup so document.querySelector("form") can find the form.
  • Compare each bracket in the submit handler with the reference below.
  • Help me debug why my website form page stopped loading after I added the submit handler.

✔️ Awesome, I've got everything!

Your saved browser script now intercepts the website form and sends its fields to your route.

ⓧ I'd like to double check the full code

The complete browser script is shown below for comparison.

<script>
  // Attach the handler to the existing website form
  const form = document.querySelector("form");

  form.addEventListener("submit", async (event) => {
    // Keep the visitor on the page while the route handles the submission
    event.preventDefault();

    // Preserve the website field names for the API route's existing mapping
    const formData = new FormData(form);

    // Send the submission to the route you own
    await fetch("/api/hubspot-form", {
      method: "POST",
      body: formData,
    });
  });
</script>
Capture the browser request

The browser's Network panel records every HTTP request made by the page. Its request entry proves that the website form called your API route.

  • Return to the local form page from the previous substep.
  • Open developer tools from your browser's menu.
  • Select the Network tab.
  • Reload the local form page to begin a clean request capture.
  • Complete each required form field with a distinctive test value.

Before you submit, do you expect the page to navigate away or remain on the form?

  • Submit the form using its existing button.

You should remain on the same page. You should also see /api/hubspot-form appear in the Network request list.

  • Select the /api/hubspot-form request in the Network panel.
  • Confirm that its request method is POST.
  • Confirm that its response status is 200.

You have closed the browser-to-route gap. A real visitor can now submit the form without leaving the page.

No request in Network?

  • If the page navigates away, confirm that event.preventDefault(); remains inside the submit handler.
  • If no request appears, confirm that the script sits after the existing form markup.
  • If the route returns a non-success status, compare each field's name with the website field names your route already maps.
  • Help me debug why my browser form is not posting successfully to my API route.

Your browser now sends form data through your own route while the page stays put. Next, you'll test whether the spam trap drops a bot-like submission before it reaches HubSpot.

Add and Test the Honeypot

Your local form now reaches your own route, so genuine submissions can land in HubSpot without sending visitors away. The public endpoint can also collect junk from bots.

This step adds a honeypot to the website form. Your route will drop any submission that fills the hidden field before HubSpot is contacted.

In this step, get ready to:
  • Add a hidden website field to the existing website form.
  • Check website before any HubSpot processing.
  • Prove a filled honeypot request creates no HubSpot contact.
Add the hidden honeypot field

The browser script already collects fields from the existing form. A named field inside that form joins the request payload automatically.

  • In the website form source from earlier, add one hidden field inside the existing form configured with the name website plus an empty value.
  • Save your website form.
  • Refresh the local form preview from earlier.
  • Use the DOM inspector in your browser developer tools to find the field named website.

You will find website inside the form. The field stays hidden from the visitor.

Cannot find the hidden field?

  • Confirm the hidden field sits inside the same form that the browser script serializes.
  • Check that its name is exactly website in lowercase.
  • Help me find why my hidden website field is missing from the form data.
Block filled honeypot requests

The check belongs immediately after the route reads the submitted form data. It must finish before the current mapping builds the HubSpot payload.

The guard reads website. A non-empty value returns the same 200 response with an ok body before mapping begins.

  • In the existing implementation of /api/hubspot-form, add the early guard immediately after the submitted form data is read.
  • Save the API route.

Why must the guard come first?

HubSpot should only receive data after the route classifies the submission as legitimate. Placing the guard first stops bot data before property mapping reaches the network.

Prove the spam request is dropped

A unique email makes the final check decisive. If HubSpot has no contact for that address, the request stopped inside your route.

  • Record a fresh address for this test: your unique honeypot test email.
  • Prepare the spam test in the terminal from earlier by editing your valid curl command to use your unique honeypot test email as the email value plus bot-value as the website value.

Before you send it, do you expect the filled website value to reach HubSpot?

  • Press Enter to send the edited curl request.

You should receive the route's 200 response with an ok body.

  • Switch back to HubSpot Contacts from earlier.
  • Search for your unique honeypot test email.

You should see no matching contact. That proves the route stopped the request before HubSpot.

That is the spam path contained. A filled honeypot now stops at your route.

Seeing a contact anyway?

  • Check that the honeypot guard appears before the HubSpot payload mapping.
  • Confirm the edited curl request uses the lowercase field name website with the non-empty value bot-value.
  • Help me find why my honeypot request still created a HubSpot contact.

✔️ Awesome, I've got everything!

Your form now sends an empty website field with legitimate submissions. Your route rejects non-empty values before HubSpot receives them.

ⓧ I'd like to double check the full code

The completed website form plus API route follow this order.

  • The website form contains a hidden field named website.
  • The existing browser script sends every form field to /api/hubspot-form.
  • That request includes an empty website value for legitimate submissions.
  • The API route reads website before mapping any HubSpot properties.
  • A non-empty website value returns before the HubSpot request.
  • An empty website value continues through the existing property mapping.
  • The valid payload reaches HUBSPOT_FORM_ENDPOINT.
  • The route keeps its 200 response with an ok body.

Your honeypot now stops filled spam submissions before HubSpot. Next up, deploy the protected route to Webflow Cloud for its live form test.

Deploy the Live Form

Your honeypot now drops bot traffic before it reaches HubSpot. The remaining challenge is making the protected form available to real visitors.

This step moves the working form plus its API route onto Webflow Cloud. You will trace one live submission from the browser into HubSpot Contacts.

In this step, get ready to:
  • Add the HubSpot form endpoint to the Webflow Cloud environment.
  • Deploy the website form with its API route.
  • Trace a live submission into HubSpot Contacts.
Configure the live environment

The deployed route needs the same HubSpot form endpoint that worked locally. Webflow Cloud stores this value in the environment used by the live app.

  • Switch back to your Webflow Cloud project from earlier.
  • Select the environment that serves the website form.
  • Open the Environment variables tab.
  • Click Add Variable.
  • Enter HUBSPOT_FORM_ENDPOINT in the variable name field.
  • Paste the copied HubSpot submission endpoint into the variable value field.
  • Click Add variable.

You should see HUBSPOT_FORM_ENDPOINT listed in the environment variables.

Good work. The deployed route now has the destination it needs for valid submissions.

Can't See the Endpoint?

  • Check that the variable name is exactly HUBSPOT_FORM_ENDPOINT.
  • Confirm that you added the variable to the environment used by the live form.
  • Return to the endpoint you copied earlier if the value field is empty.
  • Help me troubleshoot my Webflow Cloud environment variable.
Deploy the form and route

A Webflow Cloud deployment publishes the current app build to its environment. The build may take up to two minutes while Webflow Cloud prepares the app.

  • Return to the Environments Dashboard.
  • Click Deploy latest build.
  • Wait for the build process to finish.

The deployment status should confirm that the build succeeded.

  • Open the deployed app from the successful deployment screen.

You should see the website form at the live Webflow Cloud URL.

That closes the final hosting gap. Your form is now running from Webflow Cloud.

Deployment Not Succeeding?

  • Open the build logs from Environment Details to find the first failed build stage.
  • Confirm that HUBSPOT_FORM_ENDPOINT appears in the environment used by this deployment.
  • Check that the latest build contains the website form plus the /api/hubspot-form route.
  • Help me diagnose my failed Webflow Cloud deployment.
Verify the live submission in HubSpot

The final test follows one submission across every live layer. The browser request proves that your deployed route handled the form.

  • Use the developer tools control in your browser menu to open the panel.
  • Select the Network tab.
  • Clear the current Network log.
  • Enter email address for your live form test in the form's email field.
  • Complete every other required field with recognizable test data.

Before you submit, do you think the live request will reach your deployed route?

  • Click the form's submit button.

You should see a POST request to /api/hubspot-form in the Network log. Its response should show HTTP 200 with an ok body.

  • Select the POST request in the Network log.
  • Inspect the submitted form data in the request details.

The website field should be empty. That confirms the deployed browser script included the honeypot without blocking a real visitor.

Request Missing or Not Returning 200?

  • Confirm that the browser address shows the deployed Webflow Cloud form.
  • Check that the Network request targets /api/hubspot-form.
  • Confirm that HUBSPOT_FORM_ENDPOINT remains listed in the deployed environment.
  • Help me troubleshoot my live form request.

Before you return to HubSpot, do you expect the live test email to appear as a new contact?

  • Switch back to HubSpot Contacts from earlier.
  • Search for email address for your live form test.
  • Open the matching contact.

You should find the contact created by the deployed website form. Its recorded properties should match the values you submitted.

Contact Not Appearing?

  • Refresh HubSpot Contacts before searching again.
  • Confirm that the live request returned HTTP 200 with an ok body.
  • Check that the deployed route uses the recorded HubSpot property names.
  • Help me find why my live submission did not create a HubSpot contact.

You did it. A real submission now travels from your live form through your protected route into HubSpot Contacts.

Secret mission

Run a Production Regression Drill

Turn your finished integration into a repeatable release check. Prove that a valid submission reaches HubSpot while a fresh honeypot submission creates no contact.

Clean Up Your Resources

Clean Up Your Resources

Your deployed Webflow Cloud route can stay live. Your existing service plans still apply while it remains available.

Decide whether to keep the two HubSpot test contacts, leave them in place until later, or delete them now so they do not distort your first real CRM numbers.

The deployed website form plus its API route make up the finished project. The two HubSpot contacts are temporary test data.

Resources you used:

  • The HubSpot contact created by your valid curl submission.
  • The HubSpot contact created by your live Webflow Cloud form submission.

Keep everything running

No action is needed. Choose this if you want both contacts available as working examples while you continue testing the route.

  • Keep the contact created by your valid curl submission as an API test record.
  • Keep the contact created by your live website form submission as an end-to-end test record.

Pause - I'll come back to this later

Leave the test contacts in place while you take a break. The deployed form plus its route remain available when you return.

  • Stop sending test submissions until you resume the project.
  • Return to HubSpot Contacts when you are ready to review the two test records.

Delete - I don't want to use this again

Deleting CRM records can feel final. This cleanup removes only the two test contacts.

Your HubSpot form, deployed route, plus website form stay in place for real submissions.

  • Return to HubSpot Contacts.
  • Locate each test contact by matching the mapped values from your valid curl submission plus your live form submission.
  • Select the two matching contact records.
  • Use the contacts table action menu to choose the deletion option.
  • Confirm the removal when HubSpot prompts you.
  • Search HubSpot Contacts for the values from both test submissions.

You should find no matching records.

Good work. Those test submissions can no longer distort your first real CRM numbers.

Nice Work!

Nice Work!

You did it. Your deployed Webflow Cloud form now sends valid submissions through your own API route to HubSpot.

You've learned how to:

  • Built a direct form submission route at /api/hubspot-form. It maps website fields to the recorded HubSpot properties. Valid local posts return HTTP 200 with an ok body.
  • Connected the browser form flow to your own route. Visitors stay on the page during submission. Valid live submissions appear as contacts in HubSpot.
  • Protected the CRM workflow with a hidden website honeypot field. A filled trap creates no HubSpot contact.
  • Secret Mission: Completed an optional challenge to push your direct form-to-CRM skills further.

Ready to quiz yourself?