Skip to content

How to Connect Typeform to Odoo: Form Submission Integration

DeployMonkey Team · March 23, 2026 9 min read

Why Connect Typeform to Odoo?

Typeform creates beautiful, conversational forms that achieve higher completion rates than traditional forms. Businesses use Typeform for lead capture, customer surveys, event registration, job applications, and feedback collection. Without integration, someone exports Typeform responses as CSV, imports them into Odoo, and maps fields manually. This delay means leads go cold, feedback gets lost, and data entry errors multiply.

Connecting Typeform to Odoo ensures every submission instantly creates the appropriate Odoo record — a CRM lead, a contact, a survey response, or a helpdesk ticket — with all form fields mapped to the right places.

Integration Methods

MethodDifficultySpeedCost
ZapierEasy1-15 min delay$20+/mo
Typeform WebhooksMediumInstantFree (Basic+ plan)
Make (Integromat)EasyInstant (webhook)$9+/mo
Custom Odoo ControllerMediumInstantDev time only

Step 1: Create Your Typeform

Design your form in Typeform with fields that map to your target Odoo model. For lead capture:

  • Name (Short Text) maps to contact_name
  • Email (Email) maps to email_from
  • Company (Short Text) maps to partner_name
  • Phone (Phone Number) maps to phone
  • Budget (Multiple Choice) maps to expected_revenue
  • Message (Long Text) maps to description

Step 2: Set Up Typeform Webhook

  1. Open your Typeform → Connect tab → Webhooks
  2. Add webhook URL: https://your-odoo.com/typeform/webhook
  3. Enable the webhook
  4. Note: Typeform signs webhooks with HMAC-SHA256 for verification

Step 3: Build Odoo Webhook Handler

from odoo import http
import json, hmac, hashlib

TYPEFORM_SECRET = 'your_webhook_secret'

class TypeformWebhook(http.Controller):
    @http.route('/typeform/webhook', type='http', auth='none',
                csrf=False, methods=['POST'])
    def handle(self, **kwargs):
        body = http.request.httprequest.data
        
        # Verify signature
        sig = http.request.httprequest.headers.get('Typeform-Signature', '')
        expected = 'sha256=' + hmac.new(
            TYPEFORM_SECRET.encode(), body, hashlib.sha256
        ).hexdigest()
        if not hmac.compare_digest(sig, expected):
            return http.request.make_response('Unauthorized', status=401)
        
        data = json.loads(body)
        answers = self._parse_answers(data)
        self._create_lead(answers)
        
        return http.request.make_response('OK')
    
    def _parse_answers(self, data):
        result = {}
        for answer in data.get('form_response', {}).get('answers', []):
            field_ref = answer['field']['ref']
            if answer['type'] == 'text':
                result[field_ref] = answer['text']
            elif answer['type'] == 'email':
                result[field_ref] = answer['email']
            elif answer['type'] == 'phone_number':
                result[field_ref] = answer['phone_number']
            elif answer['type'] == 'choice':
                result[field_ref] = answer['choice']['label']
            elif answer['type'] == 'number':
                result[field_ref] = answer['number']
        return result
    
    def _create_lead(self, answers):
        http.request.env['crm.lead'].sudo().create({
            'name': f"Typeform: {answers.get('name', 'New Lead')}",
            'contact_name': answers.get('name'),
            'email_from': answers.get('email'),
            'partner_name': answers.get('company'),
            'phone': answers.get('phone'),
            'description': answers.get('message'),
            'source_id': self._get_source('Typeform').id,
        })

Step 4: Map Multiple Forms to Different Models

Use the form ID from the webhook payload to route submissions to different Odoo models:

FORM_MAPPING = {
    'abc123': 'crm.lead',      # Contact form -> CRM lead
    'def456': 'hr.applicant',   # Job application -> HR applicant
    'ghi789': 'helpdesk.ticket', # Support form -> Helpdesk ticket
    'jkl012': 'event.registration', # Event signup -> Registration
}

def handle(self, **kwargs):
    data = json.loads(http.request.httprequest.data)
    form_id = data['form_response']['form_id']
    model = FORM_MAPPING.get(form_id, 'crm.lead')
    # Route to appropriate handler...

Advanced: Hidden Fields for Tracking

Typeform supports hidden fields that pass URL parameters into the form without the user seeing them. Use this for attribution tracking:

  • utm_source — maps to Odoo lead source
  • utm_medium — maps to Odoo lead medium
  • utm_campaign — maps to Odoo lead campaign
  • referrer — the page where the form was embedded
# Typeform embed with hidden fields
https://yourform.typeform.com/to/abc123#utm_source=google&utm_medium=cpc&utm_campaign=spring2026

Response Handling

For survey-type forms where you want to store all responses (not just create leads), create a custom Odoo model that stores the full Typeform response payload. This lets you analyze responses across form versions and build dashboards.

DeployMonkey + Typeform

DeployMonkey instances provide HTTPS endpoints for Typeform webhooks. Our AI agent can help configure form-to-model mapping, set up lead scoring based on form answers, and test the submission pipeline.