To integrate HubSpot Marketing Hub with Lovable, create a HubSpot Private App with marketing scopes, store the access token in Cloud → Secrets, then build Edge Functions that call the HubSpot Marketing API for email events, forms, workflows, and marketing performance data. This is distinct from the HubSpot CRM integration — Marketing Hub covers email campaigns, landing pages, and automation, not just contacts and deals.
Connect Lovable to HubSpot Marketing Hub for campaign tracking and marketing automation
HubSpot Marketing Hub is a distinct product layer on top of HubSpot CRM — while HubSpot CRM manages contacts, companies, and deals as a database, Marketing Hub is the activation layer that runs email campaigns, tracks engagement, manages lead capture forms, and orchestrates marketing workflows. For founders building Lovable apps for marketing teams or wanting to embed marketing performance data in their product, the Marketing Hub APIs provide access to campaign metrics, form submissions, and email engagement data.
The key architectural distinction: HubSpot CRM contacts are the shared data layer, but email sends, opens, and clicks are Marketing Hub data. A Lovable integration that needs email engagement data (did this contact open the last campaign? how many leads came from the pricing page form?) requires Marketing Hub API scopes beyond what the basic CRM integration provides. Marketing Hub requires at least a Marketing Hub Starter plan ($800/month for 1,000 contacts) for email marketing features, though the Marketing Hub Free includes forms and basic email tracking.
Authentication is identical to the CRM integration: HubSpot Private Apps with scoped access tokens. But the scopes differ — Marketing Hub operations require scopes like marketing-email, forms, automation, and marketing-analytics. The access token format is the same ('pat-' prefix), and the API base URL is the same (api.hubapi.com), but the endpoint paths differ.
The most common Lovable + Marketing Hub integration patterns are: submitting Lovable forms to HubSpot forms to trigger email workflows, displaying email campaign performance dashboards, tracking which contacts have engaged with specific campaigns, and pulling lead source analytics to understand which marketing channels drive the most conversions.
Integration method
HubSpot Marketing Hub has no native Lovable connector. Marketing operations are proxied through Lovable Edge Functions using the HubSpot Marketing APIs (Email Events, Forms, Workflows, and Marketing Analytics). The Private App access token is stored in Cloud → Secrets and accessed via Deno.env.get(), keeping credentials server-side and preventing CORS issues from direct browser API calls.
Prerequisites
- A Lovable project with Lovable Cloud enabled (Edge Functions require a deployed app)
- A HubSpot account with Marketing Hub access (Free tier includes forms and basic email; Starter plan required for full email marketing)
- Admin or Super Admin access to your HubSpot portal to create Private Apps
- Your HubSpot Portal ID (the number in your HubSpot URL: app.hubspot.com/contacts/12345678 — use the 8-digit number)
Step-by-step guide
Create a HubSpot Private App with Marketing Hub scopes
Create a HubSpot Private App with Marketing Hub scopes
HubSpot Private Apps are the recommended authentication method for server-to-server integrations. For Marketing Hub operations, you need specific scopes beyond the basic CRM scopes. In HubSpot, go to Settings (gear icon) → Integrations → Private Apps. Click 'Create a private app'. Name it 'Lovable Marketing Hub Integration'. In the Scopes tab, select the Marketing Hub-specific scopes you need: - For email campaign data: marketing-email (read email send/engagement data) - For form submissions: forms (submit data to HubSpot forms, read form definitions) - For workflow enrollment: automation (read/write workflow enrollments) - For analytics data: marketing-analytics (access campaign analytics and reports) - Also include CRM scopes if you need contact data alongside marketing data: crm.objects.contacts.read Note: Marketing Hub scopes are separate from CRM scopes. A token with only CRM scopes cannot access email campaign data, and vice versa. If you already have a CRM Private App, either add marketing scopes to the existing app or create a second app dedicated to marketing operations. After selecting scopes, click 'Create app'. Copy the access token (starts with 'pat-'). Also note your Portal ID — found in your HubSpot URL when logged in (the 8-digit number in app.hubspot.com/contacts/XXXXXXXX). Different Marketing Hub features require different plan levels. The Forms API works on free accounts. Email campaign analytics require at least Marketing Hub Starter. Marketing automation workflows with email sends require Marketing Hub Professional ($800/month) or higher.
Pro tip: HubSpot Marketing Hub API scopes are not included in 'all scopes' unless you explicitly select them. When creating or editing your Private App, scroll through the full scope list and check the 'Marketing' section — CRM scopes and Marketing scopes are listed in separate sections.
Expected result: A HubSpot Private App with marketing-email, forms, and marketing-analytics scopes is created. The access token (pat-na1-... or pat-eu1-...) is copied. The HubSpot Portal ID is noted.
Store credentials in Cloud Secrets and identify your HubSpot form IDs
Store credentials in Cloud Secrets and identify your HubSpot form IDs
Add HubSpot Marketing credentials to Lovable Cloud Secrets. In Lovable, click '+' → Cloud panel → Secrets. Add: - HUBSPOT_ACCESS_TOKEN — the Private App access token from the previous step (this can be shared with the CRM integration token if you added marketing scopes to the same app) - HUBSPOT_PORTAL_ID — your 8-digit HubSpot Portal ID For form submission integration, you also need your HubSpot form GUID. HubSpot Forms are identified by a GUID (a UUID like 'a1b2c3d4-5678-...'). To find it: 1. In HubSpot, go to Marketing → Lead Capture → Forms 2. Click on the form you want to submit to 3. In the form editor, click 'Actions' → 'Embed' or look at the form URL in your browser — the GUID is in the URL 4. Alternatively, use the HubSpot Forms API: GET https://api.hubapi.com/marketing/v3/forms will list all forms with their GUIDs Store frequently-used form GUIDs as secrets (HUBSPOT_FORM_GUID_LEAD_MAGNET, HUBSPOT_FORM_GUID_DEMO_REQUEST) for easy reference in Edge Functions. Note: The HubSpot Forms submission API v3 uses a different endpoint structure than the legacy v2 API. Use the v3 endpoint: POST https://api.hubspot.com/marketing/v3/forms/{formId}/submissions.
Pro tip: The HubSpot Form GUID format changed between API v2 and v3. If you have existing HubSpot forms, the GUID for v3 submissions is the same UUID shown in the form URL — but the submission endpoint URL path is different from what you may see in older documentation.
Expected result: HUBSPOT_ACCESS_TOKEN, HUBSPOT_PORTAL_ID, and any form GUIDs appear in Cloud → Secrets. You have identified the form GUID(s) for the HubSpot forms you will submit to from Lovable.
Create the HubSpot Marketing Hub API proxy Edge Function
Create the HubSpot Marketing Hub API proxy Edge Function
Build the Edge Function that handles Marketing Hub operations: form submissions, email campaign stats, and contact marketing properties. The Edge Function uses the same Authentication pattern as the CRM integration (Bearer token with the Private App access token) but calls different API endpoints. HubSpot Marketing Hub key API endpoints: - Forms submission: POST https://api.hubspot.com/marketing/v3/forms/{formId}/submissions - List forms: GET https://api.hubapi.com/marketing/v3/forms - Email campaign list: GET https://api.hubapi.com/marketing-emails/v1/emails - Email campaign statistics: GET https://api.hubapi.com/marketing-emails/v1/emails/{emailId}/statistics - Marketing analytics: GET https://api.hubapi.com/analytics/v2/reports/{reportId} For form submissions, the v3 API accepts a 'fields' array of { name, value } objects. The field names must match the HubSpot form field internal names (not display labels). Use GET /marketing/v3/forms/{formId} to retrieve the form definition and check field names before building the submission payload. For email campaign statistics, the v1 email statistics endpoint returns per-campaign metrics: sentAt, counters.sent, counters.open, counters.click, ratios.open (as decimal), ratios.click. Note these are returned as decimals (0.24 for 24% open rate), not percentages. For tracking utm parameters and lead sources from Lovable form submissions, include the pageUri and pageName in the form submission context object — HubSpot uses these for source attribution.
Create an Edge Function called hubspot-marketing at supabase/functions/hubspot-marketing/index.ts. Accept POST with { action, params }. Support actions: submit_form, list_campaigns, get_campaign_stats. Use HUBSPOT_ACCESS_TOKEN and HUBSPOT_PORTAL_ID from secrets. Return the HubSpot API response. Include CORS headers.
Paste this in Lovable chat
1import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'23const corsHeaders = {4 'Access-Control-Allow-Origin': '*',5 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',6}78const HS_BASE = 'https://api.hubapi.com'910async function hsFetch(path: string, method = 'GET', body?: unknown) {11 const token = Deno.env.get('HUBSPOT_ACCESS_TOKEN')12 if (!token) throw new Error('HUBSPOT_ACCESS_TOKEN not configured')13 const resp = await fetch(`${HS_BASE}${path}`, {14 method,15 headers: {16 Authorization: `Bearer ${token}`,17 'Content-Type': 'application/json',18 },19 body: body ? JSON.stringify(body) : undefined,20 })21 return resp.json()22}2324serve(async (req) => {25 if (req.method === 'OPTIONS') return new Response('ok', { headers: corsHeaders })2627 try {28 const { action, params = {} } = await req.json()29 const portalId = Deno.env.get('HUBSPOT_PORTAL_ID')30 let result3132 switch (action) {33 case 'submit_form':34 // HubSpot Forms API v335 result = await hsFetch(`/marketing/v3/forms/${params.formId}/submissions`, 'POST', {36 portalId: parseInt(portalId || '0'),37 fields: params.fields, // [{ name: 'email', value: '...' }, ...]38 context: {39 pageUri: params.pageUri || '',40 pageName: params.pageName || '',41 hutk: params.hutk || '',42 },43 })44 break4546 case 'list_campaigns':47 result = await hsFetch(`/marketing-emails/v1/emails?limit=${params.limit || 20}&offset=${params.offset || 0}&orderBy=-stats.counters.sent`)48 break4950 case 'get_campaign_stats':51 result = await hsFetch(`/marketing-emails/v1/emails/${params.emailId}/statistics`)52 break5354 case 'get_contact_marketing_props':55 result = await hsFetch(`/crm/v3/objects/contacts/${params.contactId}?properties=email,hs_email_last_open_date,hs_email_last_click_date,lifecyclestage,hs_analytics_source`)56 break5758 default:59 return new Response(JSON.stringify({ error: 'Unknown action' }), {60 status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' },61 })62 }6364 return new Response(JSON.stringify(result), {65 headers: { ...corsHeaders, 'Content-Type': 'application/json' },66 })67 } catch (error) {68 return new Response(JSON.stringify({ error: error.message }), {69 status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' },70 })71 }72})Pro tip: When submitting to HubSpot forms, include the HubSpot tracking cookie (hutk) if available from the user's browser. This links the form submission to the contact's existing analytics history in HubSpot, giving you complete attribution from first visit through form submission.
Expected result: The hubspot-marketing Edge Function deploys in Cloud → Edge Functions. Test with action 'list_campaigns' — recent email campaigns from your HubSpot Marketing Hub should appear in the response.
Build the marketing dashboard and connect form submissions
Build the marketing dashboard and connect form submissions
With the Edge Function deployed, build the marketing performance dashboard and wire form submissions to trigger HubSpot workflows. For the marketing dashboard, call list_campaigns on mount to get recent email sends, then display campaigns in a table with performance metrics. Convert HubSpot's decimal open/click rates to percentages (multiply by 100) before displaying. Add trend indicators comparing the last 5 campaigns' performance. For connecting Lovable forms to HubSpot workflows, use the submit_form action after any form submission where you want a HubSpot workflow to trigger. The form submission not only captures data in HubSpot but also enrolls the contact in associated email sequences. Pass the field values as an array: [{ name: 'email', value: form.email }, { name: 'firstname', value: form.firstName }]. Field names must match the HubSpot form field internal names — check these in HubSpot → Marketing → Forms → edit form → field settings. For lead magnet forms, also pass the pageUri and pageName context fields so HubSpot correctly attributes the submission to the right page in your analytics. This data appears in the contact's 'First page seen' and 'Last page seen' properties. For complex marketing automation scenarios such as triggering HubSpot workflows directly via the Workflow Enrollments API or building multi-step nurture sequences, RapidDev's team can help design the correct API architecture.
Build a marketing performance page using the hubspot-marketing Edge Function. Fetch recent campaigns (action: list_campaigns) on mount. Show a table with columns: Campaign Name, Sent Date, Sent Count, Open Rate (as %), Click Rate (as %), Unsubscribes. Add click-through to show individual campaign stats (action: get_campaign_stats). Show a summary row with averages at the bottom.
Paste this in Lovable chat
Pro tip: HubSpot's Marketing Email statistics are cached and may lag 15-30 minutes behind real-time sends. For very recent campaigns, the statistics endpoint may return zeros — add a 'last updated' timestamp to your dashboard so users know the data freshness.
Expected result: The marketing performance dashboard displays your HubSpot email campaigns with open and click rate metrics. Form submissions from Lovable appear in HubSpot → Marketing → Forms → Submissions and trigger any associated workflows.
Common use cases
Submit Lovable forms to HubSpot Marketing Hub to trigger email sequences
When a visitor submits a lead magnet or content download form in your Lovable app, submit the form data to the corresponding HubSpot form via the Forms API. This triggers any HubSpot workflows associated with that form — typically an automated email sequence delivering the lead magnet content and nurturing the lead. Unlike the CRM contact API, form submissions properly trigger workflow enrollments and email sends.
Create an Edge Function called hubspot-form-submit that accepts { formId, email, firstName, lastName, company, downloadedContent } and submits the data to a HubSpot form via the Forms API using HUBSPOT_ACCESS_TOKEN and HUBSPOT_PORTAL_ID from secrets. Include the hutk cookie value if available for tracking. Return success or error. Call this from my lead magnet download form on the pricing page.
Copy this prompt to try it in Lovable
Marketing performance dashboard showing campaign metrics
Build an internal marketing dashboard in your Lovable app that fetches HubSpot email campaign performance data: sent count, open rate, click-through rate, unsubscribe rate, and conversion count. The dashboard helps marketing teams monitor campaigns without logging into HubSpot, and can be embedded in a custom operations portal alongside other business metrics from Supabase.
Create an Edge Function called hubspot-marketing-stats that fetches email campaign performance from the HubSpot Marketing Email API using HUBSPOT_ACCESS_TOKEN from secrets. Return recent campaigns with sent, opens, clicks, open_rate, click_rate, and unsubscribes. Build a marketing dashboard in Lovable showing campaigns in a table with performance metrics and trend arrows. Add date range filtering.
Copy this prompt to try it in Lovable
Lead source attribution showing which marketing channels drive signups
Track which HubSpot marketing sources (email, organic search, social media, paid ads) are driving user registrations in your Lovable app by reading the original_source and latest_source fields from HubSpot contact records at the time of signup. Display an attribution dashboard showing signup volume by source, enabling data-driven marketing budget allocation.
Create an Edge Function that looks up a HubSpot contact by email and returns their original_source, original_source_data_1, and original_source_data_2 fields after a user signs up. Store the source data in my Supabase users table. Build a simple attribution chart showing how many users came from each marketing source (Organic Search, Direct, Social, Email Marketing, Paid Search).
Copy this prompt to try it in Lovable
Troubleshooting
HubSpot API returns 403 with 'Missing required scope: marketing-email'
Cause: The Private App access token does not have the marketing-email scope enabled. Marketing Hub scopes are separate from CRM scopes and must be explicitly added.
Solution: In HubSpot → Settings → Private Apps → your app → Scopes tab, scroll to the Marketing section and enable the required scopes (marketing-email, forms, marketing-analytics). After updating scopes, regenerate the access token — scope changes require a new token. Update the HUBSPOT_ACCESS_TOKEN secret with the new token value.
Form submission returns 400 with 'INVALID_FORM_GUID' error
Cause: The form GUID in the API call does not exist in your HubSpot portal, or the form belongs to a different portal.
Solution: Verify the form GUID by fetching your forms list: call the list_forms action or GET /marketing/v3/forms in your Edge Function. The GUID must match a form that exists in the portal associated with your HUBSPOT_PORTAL_ID. Forms created in a connected Sandbox account have different GUIDs than production forms.
Form submission succeeds (200) but no contact is created in HubSpot CRM
Cause: The form submission does not include a valid email field, or the email field name does not match the HubSpot form field's internal name.
Solution: Every HubSpot form submission must include the 'email' field by its internal name. Retrieve the form definition (GET /marketing/v3/forms/{formId}) to see each field's 'name' property — use these exact values in the fields array. The 'email' field is named 'email' by default but may have been renamed in custom forms.
Marketing email statistics endpoint returns all zeros for a recently sent campaign
Cause: HubSpot Marketing Hub statistics are not real-time — they are aggregated and cached, typically with a 15-30 minute lag after sends.
Solution: Add a 'data freshness' indicator to your dashboard showing when statistics were last updated. For campaigns sent in the last hour, display a notice that statistics may not yet reflect all recipient activity. Poll statistics no more frequently than once every 15 minutes to avoid hitting API rate limits.
Best practices
- Create a dedicated Private App for Marketing Hub with only the marketing-related scopes — separate from your CRM Private App — to maintain clear permission boundaries.
- Always include the hutk tracking cookie in form submissions when available — this links form submissions to existing contact analytics and improves attribution accuracy.
- Use HubSpot form field internal names (not display labels) in submission payloads — retrieve them via the Forms API before building submission code.
- Display marketing statistics with a data freshness indicator since HubSpot caches statistics with a 15-30 minute lag — set user expectations about near-real-time data.
- Track the form submission response for ALREADY_IN_LIST type errors — they indicate the contact is already enrolled in the associated workflow, which is useful context for your UX.
- For multi-step marketing attribution, capture UTM parameters from the page URL and pass them as hidden fields in HubSpot form submissions — HubSpot stores these as contact properties.
- When building marketing dashboards for stakeholders, cache campaign statistics in Supabase rather than fetching from HubSpot on every page load — marketing dashboards rarely need sub-minute freshness.
Alternatives
Choose the main HubSpot CRM integration if your primary need is contact and deal management — Marketing Hub features are an extension on top of the CRM for email automation and campaign analytics.
Choose Mailchimp if you need only email list management and campaigns without the full CRM layer — Mailchimp is more affordable and simpler for pure email marketing use cases.
Choose Klaviyo if your app is e-commerce focused and you need behavior-triggered email flows based on purchase history and product interactions.
Frequently asked questions
What is the difference between HubSpot CRM and HubSpot Marketing Hub?
HubSpot CRM is the free-forever database layer that manages contacts, companies, deals, and activities. Marketing Hub is a paid product built on top of CRM that adds email marketing, landing pages, lead capture forms, automation workflows, and campaign analytics. From an API perspective, they share the same contact database but have separate API endpoints and require different Private App scopes. Most Lovable integrations start with the CRM API and add Marketing Hub features as the need arises.
Do I need Marketing Hub Professional to use the Marketing API?
The Marketing Hub API is tiered by plan. The Forms API (submitting form data) works on the Free plan. Email campaign statistics require at least Marketing Hub Starter ($800/month). Advanced features like workflow enrollment via API and marketing analytics reports require Marketing Hub Professional ($3,600/month). For most Lovable integrations starting with form submissions and basic email tracking, the Starter plan is sufficient.
Can I trigger HubSpot email workflows from my Lovable app?
Yes, in two ways. The simplest method is submitting a HubSpot form via the Forms API — any workflow triggered by that form submission will enroll the contact automatically. The more direct method is using the HubSpot Workflow Enrollments API to enroll specific contacts in specific workflows by ID. The form submission method is recommended for most use cases as it does not require knowing workflow IDs in advance.
How do I get HubSpot form field names for my Edge Function?
Fetch the form definition via GET /marketing/v3/forms/{formId} using your access token. The response includes a 'fieldGroups' array containing each field's 'name' property — this is the internal name to use in API submissions. Common default names are 'email', 'firstname', 'lastname', 'company', 'phone'. Custom fields have internal names set at creation time, usually a lowercase snake_case version of the field label.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation