Integration BlueprintUse case: lead captureUpdated 2026-10-19

Integrating Typeform with HubSpot for Automated Lead Capture

Syncing Typeform conversational form entries directly into HubSpot's CRM v3 Contacts API automates inbound lead qualification. Instead of manual exports or third-party middleware bottlenecks, developers can parse Typeform's signed form_response webhooks and invoke HubSpot's batch create/update endpoints within 200 milliseconds of submission.

Explore: Forms ยท CRM

Comparison matrix

FeatureTypeformHubSpotEdge
Starting Price$25/month (Basic plan, 100 responses/mo)$20/seat/month (Starter plan, free tier available)HubSpot
API Rate Limits2 requests/second100โ€“190 requests/10 seconds per appHubSpot
Authentication MethodsBearer Token / OAuth 2.0Private App Access Token (Bearer) / OAuth 2.0Tie
Webhook Payload SigningSupported (HMAC-SHA256 via Typeform-Signature)Supported (v3 request signature validation)Tie
Ecosystem Integrations120+ prebuilt integrations1,600+ App Marketplace integrationsHubSpot
Data Volume RestrictionsTier-gated monthly response caps (overage charges apply)Up to 15,000,000 non-marketing contacts on free CRMHubSpot
Frontend Lead Conversion UXConversational single-question display with conditional logicStandard embedded iframe and traditional static form builderTypeform
Custom Data Schema StorageHidden fields and dynamic payload variables onlyCustom properties on standard objects (Custom Objects gated to Enterprise)HubSpot
Start freeTry Typeform โ†’Try HubSpot โ†’

ROI metrics

Hours saved / mo

38

Typeform / mo

$55

HubSpot / mo

$40

Break-even

1.4 wks

Annual savings

$21,780

Automating Typeform lead ingestion directly to HubSpot removes 1.5 hours of daily manual CRM imports across a 10-person team, offsetting the $95 combined monthly tool cost within 10 business days.

Step-by-step setup guide

  1. 1.Generate HubSpot Private App Token

    In HubSpot Settings, navigate to Integrations > Private Apps. Create an app named 'Typeform Lead Ingestion' and assign the 'crm.objects.contacts.write' and 'crm.objects.contacts.read' scopes. Copy the resulting Bearer token starting with 'pat-'.

    curl -X GET https://api.hubapi.com/crm/v3/properties/contacts -H "Authorization: Bearer pat-na1-xxxx-xxxx"
  2. 2.Configure Typeform Webhook Endpoint

    Use the Typeform Create Webhook API endpoint or the Typeform Connect UI to point submission events to your backend routing server. Define a secret token to verify payload authenticity.

    curl -X PUT https://api.typeform.com/forms/{form_id}/webhooks/hubspot-sync -H "Authorization: Bearer tfp_xxxx" -H "Content-Type: application/json" -d '{"url":"https://api.yourdomain.com/webhooks/typeform","enabled":true,"secret":"whsec_AlphaNumericSecretKey99"}'
  3. 3.Verify HMAC-SHA256 Webhook Signatures

    Compute the HMAC-SHA256 hash of the incoming request body using your Typeform secret key and compare it in constant time against the value found in the 'Typeform-Signature' HTTP request header.

    const crypto = require('crypto');
    const signature = req.headers['typeform-signature'];
    const hash = 'sha256=' + crypto.createHmac('sha256', process.env.TYPEFORM_SECRET).update(req.rawBody).digest('base64');
    const isValid = crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(hash));
  4. 4.Extract Form Fields and Build HubSpot Contact Payload

    Parse the 'form_response.answers' array. Match answers by 'field.ref' or 'field.id' to the target HubSpot contact properties ('email', 'firstname', 'lastname', 'company').

    const answers = req.body.form_response.answers;
    const email = answers.find(a => a.type === 'email')?.email;
    const firstname = answers.find(a => a.field.ref === 'first_name')?.text;
    const company = answers.find(a => a.field.ref === 'company_name')?.text;
  5. 5.Upsert Contact into HubSpot via CRM v3 API

    Send a POST request to HubSpot's contact creation endpoint. Set 'idProperty' to 'email' or handle HTTP 409 Conflict status codes to update existing lead records without overwriting lead creation dates.

    curl -X POST https://api.hubapi.com/crm/v3/objects/contacts -H "Authorization: Bearer pat-na1-xxxx-xxxx" -H "Content-Type: application/json" -d '{"properties":{"email":"jane.doe@enterprise.io","firstname":"Jane","company":"Acme Corp","leadsource":"Typeform Inbound"}}'

Webhook payload example

POST https://api.yourdomain.com/webhooks/typeform ยท event: form_response

{
  "event_id": "01HNY78QW45Z8M1ZXY019ABCDE",
  "event_type": "form_response",
  "form_response": {
    "form_id": "d7kM9Z8A",
    "token": "01HNY78QW45Z8M1ZXY019FGHIJ",
    "landed_at": "2024-10-24T14:15:22Z",
    "submitted_at": "2024-10-24T14:16:05Z",
    "definition": {
      "id": "d7kM9Z8A",
      "title": "Enterprise Inbound Request",
      "fields": [
        {"id": "em_1", "ref": "contact_email", "type": "email", "title": "What is your work email?"},
        {"id": "txt_1", "ref": "contact_name", "type": "short_text", "title": "What is your full name?"},
        {"id": "txt_2", "ref": "company_name", "type": "short_text", "title": "What company are you with?"}
      ]
    },
    "answers": [
      {"type": "email", "email": "jordan.smith@cloudscale.net", "field": {"id": "em_1", "type": "email", "ref": "contact_email"}},
      {"type": "text", "text": "Jordan Smith", "field": {"id": "txt_1", "type": "short_text", "ref": "contact_name"}},
      {"type": "text", "text": "CloudScale Net", "field": {"id": "txt_2", "type": "short_text", "ref": "company_name"}}
    ]
  }
}

Typeform: pros & cons

  • โœ… Conversational layout produces 20% to 40% higher form completion rates on mobile devices compared to static web forms.
  • โœ… Payload verification via HMAC-SHA256 headers guarantees request origin integrity before payload execution.
  • โœ… Built-in conditional logic jumps capture branching lead qualifications without bespoke front-end code.
  • โš ๏ธ Aggressive response caps on entry-level tiers ($25/mo caps at 100 responses, $0.40/response overage).
  • โš ๏ธ API rate limit constrained to 2 requests per second makes bulk retro-syncing slow.

HubSpot: pros & cons

  • โœ… Robust CRM v3 API allows up to 190 requests per 10-second window per private app.
  • โœ… Free tier hosts up to 15 million contacts and includes lead scoring and timeline tracking.
  • โœ… Private App access tokens bypass complex multi-tenant OAuth overhead for direct server-to-server pipelines.
  • โš ๏ธ Custom Objects schema configuration is restricted to Enterprise tier plans ($3,600+/month).
  • โš ๏ธ Contact update batch endpoints will fail the entire batch if an individual record contains a validation error.

FAQ

How does the pipeline handle existing contacts without duplicate record errors in HubSpot?

When sending a POST request to '/crm/v3/objects/contacts', HubSpot returns an HTTP 409 Conflict if the email already exists, along with the conflicting record ID. Your webhook handler must catch the 409 response, extract the existing record ID from the error message body, and execute a 'PATCH /crm/v3/objects/contacts/{contactId}' request to update fields.

What happens if Typeform webhook dispatch fails due to an endpoint timeout?

Typeform retries failed webhook deliveries using an exponential backoff schedule for up to 24 hours. Your receiver endpoint must return an HTTP 200 or 204 status within 10 seconds of initial receipt; execute contact upserts asynchronously via an internal job queue (e.g., Redis BullMQ or AWS SQS) to prevent timeouts.

Can I map Typeform Hidden Fields to HubSpot UTM tracking properties?

Yes. Typeform appends hidden URL query parameters to the root of the 'form_response.hidden' object. You can directly extract 'hidden.utm_source', 'hidden.utm_medium', and 'hidden.utm_campaign' and write them into the default HubSpot properties 'hs_analytics_source_data_1' and 'hs_analytics_source_data_2'.

How do Typeform API limits impact high-traffic product launches?

Typeform's 2 req/s REST API limit applies to inbound GET/POST requests directed at 'api.typeform.com' (such as manual polling or form configuration edits). Outbound webhooks pushed to your server are not throttled by this 2 req/s limit, allowing your application to handle sudden bursts of hundreds of concurrent submissions.

Related integrations & comparisons