Skip to main content
RapidDev - Software Development Agency
v0-integrationsNext.js API Route

How to Integrate HubSpot Marketing Hub with V0

To use HubSpot Marketing Hub with V0 by Vercel, generate your lead capture forms in V0, then create a Next.js API route using the @hubspot/api-client package to submit contacts. Store your HUBSPOT_ACCESS_TOKEN as a server-only Vercel environment variable. Optionally embed the HubSpot tracking script in your Next.js layout for automatic page view and event tracking.

What you'll learn

  • How to generate lead capture forms and landing pages in V0
  • How to create a Next.js API route that creates HubSpot contacts via the CRM API
  • How to securely store and use your HubSpot access token in Vercel
  • How to embed the HubSpot tracking script in a Next.js App Router layout
  • How to trigger HubSpot workflow events when users take actions on your site
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate13 min read20 minutesMarketingMarch 2026RapidDev Engineering Team
TL;DR

To use HubSpot Marketing Hub with V0 by Vercel, generate your lead capture forms in V0, then create a Next.js API route using the @hubspot/api-client package to submit contacts. Store your HUBSPOT_ACCESS_TOKEN as a server-only Vercel environment variable. Optionally embed the HubSpot tracking script in your Next.js layout for automatic page view and event tracking.

Connecting V0-Generated Forms to HubSpot Marketing Hub

HubSpot Marketing Hub is the most widely used marketing automation platform for growing businesses. If you're building a landing page, waitlist sign-up, or contact form with V0, connecting it to HubSpot means every submission automatically becomes a contact in your CRM — ready for email sequences, lead scoring, and sales follow-up.

V0 excels at generating beautiful marketing UI: hero sections with email capture, multi-step lead qualification forms, pricing pages with 'Get in touch' CTAs, and newsletter sign-ups. The challenge is that HubSpot's API requires authentication using an access token, which must never appear in client-side code. A Next.js API route solves this perfectly — the form submits to /api/hubspot, the API route calls HubSpot server-side with the secret token, and the browser never sees the credential.

Beyond contact creation, HubSpot's tracking script gives you free visitor analytics, form tracking, and live chat even on your custom V0-built pages. This tutorial covers both the API integration and the tracking script setup, giving you a complete marketing stack on your Vercel-deployed Next.js app.

Integration method

Next.js API Route

V0 generates polished lead capture and marketing form UIs. A Next.js API route uses the @hubspot/api-client package to securely submit contact data to HubSpot's CRM. The HubSpot tracking script can be embedded in the Next.js layout component for automatic visitor analytics.

Prerequisites

  • A V0 account at v0.dev with a Next.js project
  • A HubSpot account — the free CRM tier works for contact creation and basic tracking
  • A HubSpot Private App access token (Settings → Integrations → Private Apps → Create private app) with CRM contacts read/write scopes
  • A Vercel account for deployment and environment variable management
  • Your landing page or form design ready to generate in V0

Step-by-step guide

1

Generate the Marketing Form UI in V0

Open V0 and describe the marketing form or landing page component you need. Be specific about the form fields you want to collect — HubSpot has standard contact properties (email, firstname, lastname, company, phone) and you can also create custom properties. Describe how you want the form to behave: should it validate fields before submitting? Show a loading state while the API call is in progress? Display an inline success message or redirect to a thank-you page? V0 will generate a React component with the form markup, Tailwind styling, and state management. The generated component will likely use useState for form data and a handleSubmit function — this is exactly what you need to wire up to your HubSpot API route. After generating the initial component, use V0's chat to refine details: 'make the CTA button green with rounded corners', 'add a phone number field', or 'show red error messages below each invalid field'. Use Design Mode (Option+D) to fine-tune colors to match your brand. Once the visual design is right, open the Code panel to see the component code before moving on.

V0 Prompt

Create a lead capture landing page hero section with a headline 'Start Growing Your Business Today', a subheadline, and a form with fields for First Name, Last Name, Work Email, and Company Name. Add a large 'Get Started Free' button. Show a loading spinner on the button while submitting. On success, show 'Thanks! We'll be in touch shortly.' The form should call POST /api/hubspot/contact with the field values.

Paste this in V0 chat

Pro tip: Match your form field names in the component to HubSpot's standard contact property names (firstname, lastname, email, company, phone) to make the API route simpler.

Expected result: A polished marketing form component renders in the V0 preview with loading and success states. The component's handleSubmit is ready to be pointed at the HubSpot API route.

2

Create the HubSpot Contact API Route

Add the @hubspot/api-client package to your package.json. This is HubSpot's official Node.js SDK — it handles authentication and provides typed methods for every HubSpot API. Create a new file at app/api/hubspot/contact/route.ts. This API route will export a POST handler that receives the form submission, validates the required fields, creates or updates a HubSpot contact using the SDK, and returns a success or error response. The key HubSpot operation here is crm.contacts.basicApi.create(), which takes an object with properties matching HubSpot's contact property names. If the contact already exists (same email address), you'll get a CONFLICT error — handle this gracefully by updating the existing contact with crm.contacts.basicApi.update() instead. Always wrap the HubSpot API calls in a try/catch and return appropriate HTTP status codes: 200 for success, 400 for invalid input, 500 for HubSpot API errors. This prevents your form from silently failing when something goes wrong. The HUBSPOT_ACCESS_TOKEN environment variable is used to authenticate the SDK client — you'll set this in Vercel in the next step.

V0 Prompt

Create a Next.js API route at app/api/hubspot/contact/route.ts. It should import Client from '@hubspot/api-client', initialize it with process.env.HUBSPOT_ACCESS_TOKEN, and on POST requests create a HubSpot contact using the request body's firstname, lastname, email, and company fields. Return { success: true } on success or an error message with appropriate status codes.

Paste this in V0 chat

app/api/hubspot/contact/route.ts
1import { Client } from '@hubspot/api-client';
2import { NextRequest, NextResponse } from 'next/server';
3
4const hubspotClient = new Client({
5 accessToken: process.env.HUBSPOT_ACCESS_TOKEN,
6});
7
8export async function POST(req: NextRequest) {
9 try {
10 const body = await req.json();
11 const { email, firstname, lastname, company, phone } = body;
12
13 if (!email) {
14 return NextResponse.json(
15 { error: 'Email is required' },
16 { status: 400 }
17 );
18 }
19
20 const contactProperties = {
21 email,
22 firstname: firstname || '',
23 lastname: lastname || '',
24 company: company || '',
25 phone: phone || '',
26 };
27
28 try {
29 // Try to create a new contact
30 await hubspotClient.crm.contacts.basicApi.create({
31 properties: contactProperties,
32 associations: [],
33 });
34 } catch (createError: unknown) {
35 const err = createError as { code?: number };
36 // If contact already exists (409 Conflict), update instead
37 if (err?.code === 409) {
38 const existingContact = await hubspotClient.crm.contacts.basicApi.getById(
39 email,
40 undefined,
41 undefined,
42 undefined,
43 undefined,
44 'email'
45 );
46 await hubspotClient.crm.contacts.basicApi.update(
47 existingContact.id,
48 { properties: contactProperties }
49 );
50 } else {
51 throw createError;
52 }
53 }
54
55 return NextResponse.json({ success: true });
56 } catch (error) {
57 console.error('HubSpot API error:', error);
58 return NextResponse.json(
59 { error: 'Failed to create contact' },
60 { status: 500 }
61 );
62 }
63}

Pro tip: HubSpot's contact property names are lowercase with underscores (firstname, not firstName). Check your HubSpot portal's Contact Properties settings to find the exact names for custom properties.

Expected result: The API route at /api/hubspot/contact handles POST requests and creates HubSpot contacts. Duplicate emails trigger an update instead of an error.

3

Add Your HubSpot Access Token to Vercel

Your HubSpot access token grants full API access to your CRM — it must be treated like a password and kept server-side only. Never use the NEXT_PUBLIC_ prefix for it, and never include it in client-side React components. To create a Private App token in HubSpot, go to Settings (gear icon) → Integrations → Private Apps → Create a private app. Give it a name like 'V0 Website Integration', go to the Scopes tab, and enable crm.objects.contacts.read and crm.objects.contacts.write under CRM. Click Create app and copy the access token immediately — it's only shown once. In the Vercel Dashboard, open your project → Settings → Environment Variables. Add HUBSPOT_ACCESS_TOKEN with your token as the value. Leave the NEXT_PUBLIC_ prefix off — this keeps it server-side only. Check all three environments (Production, Preview, Development). Save and redeploy if you already have a deployment. Locally, add HUBSPOT_ACCESS_TOKEN to your .env.local file. Also add the line .env.local to your .gitignore if it isn't already there. For local testing, you can use your HubSpot sandbox account instead of your live CRM to avoid polluting production data with test contacts.

.env.local
1# .env.local never commit this file
2# HubSpot Private App token (server-only, no NEXT_PUBLIC_ prefix)
3HUBSPOT_ACCESS_TOKEN=pat-na1-your-private-app-token-here

Pro tip: Use a HubSpot sandbox account (Settings → Account Management → Sandboxes) for development and testing to keep test contacts separate from your real CRM data.

Expected result: HUBSPOT_ACCESS_TOKEN is set in Vercel Dashboard environment variables without the NEXT_PUBLIC_ prefix. The API route can authenticate with HubSpot when called from a deployed Vercel function.

4

Add the HubSpot Tracking Script to Your Layout

HubSpot's tracking script automatically tracks page views, form submissions, and other events on your website. When a visitor's email is known (they've filled in a form previously), HubSpot can identify them across sessions and tie their browsing behavior to their contact record. This gives you rich analytics about which pages leads visit before converting. To add the script in Next.js App Router, open your root layout file at app/layout.tsx. You'll use Next.js's built-in Script component from next/script to load the HubSpot tracking script. The script URL includes your HubSpot Hub ID, which you can find in HubSpot → Settings → Account Setup → Account Defaults → Account Information → Hub ID. Use the strategy='afterInteractive' prop so the tracking script loads after the page's interactive content, not blocking your page's first paint. For single-page app navigation tracking (ensuring HubSpot knows when users navigate between pages in your Next.js app), HubSpot's tracker automatically handles this via its JavaScript API — the _hsq.push(['trackPageView']) call can be made after each navigation event. For complex multi-page apps with deep analytics requirements, RapidDev can help you set up server-side event tracking and custom HubSpot workflow triggers.

V0 Prompt

Add the HubSpot tracking script to app/layout.tsx using the Next.js Script component from 'next/script'. The script src should be https://js.hs-scripts.com/{HUBSPOT_HUB_ID}.js where the Hub ID is read from process.env.NEXT_PUBLIC_HUBSPOT_HUB_ID. Use strategy='afterInteractive' to avoid blocking page load.

Paste this in V0 chat

app/layout.tsx
1import Script from 'next/script';
2
3export default function RootLayout({
4 children,
5}: {
6 children: React.ReactNode;
7}) {
8 return (
9 <html lang="en">
10 <body>
11 {children}
12 {/* HubSpot Tracking Script */}
13 {process.env.NEXT_PUBLIC_HUBSPOT_HUB_ID && (
14 <Script
15 id="hs-script"
16 src={`https://js.hs-scripts.com/${process.env.NEXT_PUBLIC_HUBSPOT_HUB_ID}.js`}
17 strategy="afterInteractive"
18 />
19 )}
20 </body>
21 </html>
22 );
23}

Pro tip: The Hub ID in your tracking script URL is public information — it's safe to use with the NEXT_PUBLIC_ prefix since it only identifies your HubSpot account for analytics, not for API access.

Expected result: The HubSpot tracking script loads on every page after the interactive content. In your HubSpot portal under Reports → Traffic Analytics, you'll see page view data from your deployed site within 24 hours.

5

Test the Full Lead Capture Flow

Deploy your app to Vercel and test the complete lead capture workflow end-to-end. Fill in your form with test data and submit it. Check the Vercel Dashboard → Functions logs to see the API route execution — look for your console.log statements or any error messages. In HubSpot, navigate to Contacts → Contacts and search for the email address you used in the test form. The contact should appear within a few seconds of submission, with all the properties you sent (name, company, etc.) populated correctly. If the contact doesn't appear, check the Vercel function logs for HubSpot API errors. Common issues include a missing or incorrect HUBSPOT_ACCESS_TOKEN, property name mismatches (HubSpot uses firstname not first_name), or missing required scopes on your Private App (ensure crm.objects.contacts.write is enabled). Once contacts are being created successfully, test your HubSpot workflows: create a simple automation in HubSpot → Automation → Workflows that sends an email when a contact is created via your form. This is the core value of the integration — automatic follow-up from the moment someone shows interest on your site.

Pro tip: Use HubSpot's Activity Feed in a contact record to see exactly when the contact was created and from which source — this helps verify your integration is working correctly.

Expected result: Form submissions from the deployed Vercel app create contacts in HubSpot CRM within seconds. The HubSpot tracking script reports page views in the Analytics dashboard. Automated workflows trigger based on the new contact data.

Common use cases

Landing Page Lead Capture

Build a product landing page with a hero email capture form. When visitors submit, their email, name, and any other fields are sent to HubSpot as a contact. They're automatically enrolled in a welcome email sequence, and your sales team sees them appear in the CRM immediately.

V0 Prompt

Create a SaaS landing page with a hero section featuring an email capture form with fields for first name, email, and company name. Include a 'Get Early Access' CTA button. The form should show a success message after submission and call POST /api/hubspot/contact with the form data.

Copy this prompt to try it in V0

Multi-Step Lead Qualification Form

Create a multi-step form that qualifies leads before they reach your sales team. Each step asks increasingly detailed questions. At the end, the form submits all answers to HubSpot as contact properties, triggering a workflow that routes the lead to the right salesperson based on their answers.

V0 Prompt

Build a 3-step lead qualification form. Step 1: company name and industry. Step 2: team size (dropdown) and current tools. Step 3: budget range and timeline. Show a progress bar at the top. On the final step, submit all data to POST /api/hubspot/contact and show a 'We'll be in touch' confirmation screen.

Copy this prompt to try it in V0

Newsletter Sign-Up with Double Opt-In

Add a newsletter sign-up to your blog or content site. Subscribers are created as HubSpot contacts and added to a specific list. HubSpot's double opt-in feature sends a confirmation email automatically, keeping your list clean and GDPR-compliant.

V0 Prompt

Create a sticky newsletter sign-up bar at the bottom of the page with an email input and 'Subscribe' button. On successful submission to POST /api/hubspot/subscribe, replace the form with a message saying 'Check your email for a confirmation link'. Include a privacy policy link below the form.

Copy this prompt to try it in V0

Troubleshooting

API route returns 401 Unauthorized or 'Missing or invalid authentication token' from HubSpot

Cause: The HUBSPOT_ACCESS_TOKEN environment variable is missing in Vercel, or the Private App token was revoked or has insufficient scopes.

Solution: In Vercel Dashboard → Settings → Environment Variables, verify HUBSPOT_ACCESS_TOKEN is set and not prefixed with NEXT_PUBLIC_. In HubSpot → Settings → Integrations → Private Apps, check that the app has the crm.objects.contacts.read and crm.objects.contacts.write scopes enabled.

Contact creation fails with 'PROPERTY_DOESNT_EXIST' error

Cause: You're trying to set a HubSpot contact property that doesn't exist in your portal, or the property name is misspelled.

Solution: In HubSpot, go to Settings → Properties → Contact Properties to see all available property names. Use the internal name (shown in the API Name column) not the display label. Custom properties need to be created in HubSpot before you can set them via the API.

typescript
1// Use HubSpot internal property names, not display labels
2const contactProperties = {
3 email, // not 'Email Address'
4 firstname, // not 'First Name'
5 lastname, // not 'Last Name'
6 company, // not 'Company Name'
7};

The HubSpot tracking script is not recording page views in the analytics dashboard

Cause: The script may not be loading (wrong Hub ID, blocked by ad blockers), or HubSpot's analytics dashboard has a reporting delay.

Solution: Open your deployed site, open browser DevTools → Network tab, and filter for 'hs-scripts'. Verify the script loads with a 200 status. Check that NEXT_PUBLIC_HUBSPOT_HUB_ID is set correctly in Vercel. Note that HubSpot analytics data can have a 24-hour delay before appearing in the dashboard.

Form submits successfully but creates duplicate contacts in HubSpot

Cause: The API route is calling create() for every submission without checking for existing contacts, and HubSpot may have duplicate detection disabled.

Solution: Ensure the API route handles the 409 CONFLICT error from HubSpot's create endpoint by catching it and calling update() on the existing contact instead, as shown in the Step 2 code example.

Best practices

  • Store HUBSPOT_ACCESS_TOKEN as a server-only environment variable — never use the NEXT_PUBLIC_ prefix, which would expose it in the browser bundle
  • Create a dedicated HubSpot Private App for each project with only the minimum required scopes rather than using a broad-access token
  • Handle the 409 CONFLICT response from HubSpot's contact creation endpoint by updating the existing contact — this prevents errors when visitors resubmit forms
  • Add form validation on the client side before calling your API route to reduce unnecessary API calls and improve the user experience
  • Use HubSpot's sandbox environment for development and testing to avoid populating your live CRM with test data
  • Include UTM parameters from the URL in the contact properties you send to HubSpot for accurate marketing attribution
  • Test your HubSpot workflows with a few real submissions before launching a marketing campaign to ensure the automation fires correctly

Alternatives

Frequently asked questions

Do I need a paid HubSpot plan to use the API with V0?

No. HubSpot's free CRM includes full API access for contact creation, updates, and basic list management. The API integrations in this tutorial work with HubSpot Free. Marketing Hub paid plans ($800/month+) add advanced features like custom reporting, smart content, and A/B testing, but these aren't required for basic lead capture.

What is a HubSpot Private App and how is it different from an API key?

HubSpot deprecated legacy API keys in 2022 and replaced them with Private Apps and OAuth. A Private App generates a scoped access token — you define exactly which parts of HubSpot it can access. This is more secure than a broad API key. Create your Private App at HubSpot Settings → Integrations → Private Apps.

Can I add contacts to a specific HubSpot list from my V0 app?

Yes. After creating a contact, you can add them to a static list using the hubspotClient.crm.lists API. However, for most use cases it's easier to use HubSpot Workflows: create a workflow triggered by 'Contact is created' that automatically adds contacts with specific properties to the right list.

How do I trigger a HubSpot workflow from my V0 app?

The most reliable way is to set specific contact properties when creating the contact — then build a HubSpot Workflow triggered by 'Contact property equals X'. For example, set a source property to 'landing-page-v2', and trigger a specific email sequence for contacts with that source value. This requires no additional API calls beyond the contact creation.

Is there a way to embed HubSpot's native forms in a V0 Next.js app?

Yes. You can embed HubSpot's native forms by loading the HubSpot Forms script and calling hbspt.forms.create() with your portal and form IDs. However, native HubSpot forms have limited customization options. The API approach in this tutorial gives you full control over form design while still sending data to HubSpot's CRM.

How do I track form conversions in Google Analytics alongside HubSpot?

Send a custom event from your form's success handler to both analytics platforms. For Google Analytics 4, call gtag('event', 'generate_lead'). HubSpot's tracking script automatically tracks form submissions when you use HubSpot's native forms. For custom forms via the API, HubSpot won't auto-track the submission, but you can fire a manual tracking event with _hsq.push(['trackEvent', { id: 'form-submitted' }]).

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.