How to Connect Custom HTML Form to Odoo CRM — Step-by-Step Integration Guide | Medkon
Developer Guide

Connect Custom HTML Form
to Odoo CRM

Fix the CSRF “Session Expired” error for good. A complete step-by-step guide to connecting any custom-designed HTML form to Odoo CRM — so leads flow directly into the backend using a JavaScript bridge.

Platform: Odoo Website Builder
Skill Level: Beginner (basic HTML awareness)
Time Required: 20–30 minutes
Published: April 2025
01

Why Direct Form Submission Fails in Odoo

Understanding the CSRF protection that causes the “Bad Request — Session Expired” error.

The Root Cause

Odoo’s website forms have a security system called CSRF (Cross-Site Request Forgery protection). This means only forms that Odoo itself creates can send data to the CRM. If you try to send data from a custom HTML form directly, Odoo rejects it with a “Bad Request — Session Expired” error.

The solution: Keep Odoo’s native form on the page (hidden from users), and use JavaScript to copy data from your custom form into Odoo’s hidden form — then trigger Odoo’s own submit button. Odoo thinks it’s its own form submitting, so it accepts it perfectly.

💡
The simple mental model
Your custom form = the face customers see. Odoo’s native form = the engine running in the background. JavaScript = the bridge connecting both. This is the JavaScript bridge method.
02

Step 1 — Create the Odoo Native Form

Drag and drop the Odoo Form block into the page using the website editor.

1
Open the page in Odoo Website Editor

Go to your Odoo website. Navigate to the page where the custom form already exists. Click the Edit button (top right) to enter the website editor.

2
Find the “Form” block in the left panel

In the left sidebar, click BLOCKS. Scroll down until you see the “Form” block (it has a form icon). It is usually near “CTA Badge”, “Blockquote” and “Countdown”.

📌
The Form block is in the BLOCKS tab, not CUSTOMIZE or THEME.
3
Drag the Form block onto the page

Click and drag the Form block. Drop it anywhere on the page — it does not matter where because we will hide it with CSS later. Drop it just below the section that has the custom form.

⚠️
Do not drop it inside the custom HTML block
Drop it as a separate section outside the custom HTML block. Nesting will break things.
4
Change Action to “Create a Lead”

Click on the form you just dropped. In the right panel under CUSTOMIZE, find the Action dropdown. It will say “Send an E-mail” by default.

Click it and look for “Create a Lead” or type crm.lead in the search box. Select it.

Once selected, the form is now connected to Odoo CRM. Any submission will create a lead automatically.
03

Step 2 — Configure Fields & CRM Mapping

Set up which fields you need and map them to the correct CRM fields in Odoo.

1
Identify what fields your custom form has

Look at the custom HTML form on the page. Note down every field it has. For example:

  • Name input field
  • Phone number input
  • Dropdown (interest/event type)

The Odoo native form needs to have at least the same fields so data can be copied across using JavaScript.

2
Add / Remove fields in the Odoo form

Click on a field in the Odoo form to select it. In the right panel you will see its settings — Type, Label, Visibility.

To add a field, click the + Field button at the top of the right panel. A dropdown will appear showing all CRM fields available — scroll and select the one you need.

To delete a field you do not need, select it and press the trash icon in the panel.

Standard field mapping — custom form to Odoo CRM
Custom Form Field Odoo CRM Field to Map Technical Name Status
Name Subject / Lead Name name Required
Phone Phone Number phone Optional
Interest / Event Type Event Type (custom studio field) x_studio_event_type Optional
(not shown to user) Email email_from Hidden — set default
3
Hide required fields that the user should not fill

Some fields like Email are required by Odoo but we do not want to show them to users. To hide them:

  • Click the field (e.g. Email)
  • In the right panel, find Visibility and set it to “Hidden”
  • Then set a default value — e.g. noreply@medkon.in — so the field is not empty on submit
⚠️
Never delete a required field
If Odoo marks a field as required (shown with *), you cannot delete it. You must hide it and give it a default value instead.
4
Save the page before proceeding

Click Save in the top bar. This is important — the Odoo form field IDs are only stable after saving. If you skip this step, the IDs you collect in Step 3 may change.

04

Step 3 — Get Odoo Field IDs via Browser Console

We need the exact HTML IDs of each Odoo form field to target them with JavaScript.

1
Open the page in the browser (not editor mode)

Go to the live URL of the page. Make sure you are NOT in the website editor — click Preview or open the URL directly in a new tab.

2
Open browser Console and run the field discovery command

Press F12 (or right-click anywhere → Inspect). Click the Console tab. Paste this command and press Enter:

Console Command — works for all field types
document.querySelectorAll('form[action="/website/form/"] input, form[action="/website/form/"] select, form[action="/website/form/"] textarea').forEach(function(el) { console.log(el.name, '|', el.id, '|', el.type); })

You will see output like this:

Example Output
name                | owude1wmma9   | text
phone               | ovpkeyzraqc   | tel
x_studio_event_type | o8alwh71bxhb  | text
email_from          | o382en45sli4  | email
3
Copy and save the field name → ID mapping

Copy this output into a notepad. You will need the IDs (the middle column) in the next step to build the JavaScript bridge.

⚠️
Odoo generates random IDs — they change after re-saving
Odoo generates random IDs like owude1wmma9 for each form. If you edit and re-save the form in the editor, the IDs may change. Always re-run this command after any edits.
05

Step 4 — Write the Bridge JavaScript

This script reads data from the custom form and pushes it into Odoo’s hidden form, then clicks Odoo’s native submit button to bypass CSRF.

1
Open the custom HTML block in the editor

In Odoo website editor, click on the section that contains your custom HTML. Click Edit in HTML editor or the code icon (</>) to open the raw HTML.

2
Paste the Bridge JavaScript template

Find the <script> block in your custom HTML. Replace the existing submit handler with this template — filling in the IDs from Step 3:

Bridge JavaScript Template — fill in YOUR IDs
// ── Bridge: Custom Form → Odoo CRM ──
var form       = document.getElementById('YOUR_CUSTOM_FORM_ID');
var successBox = document.getElementById('YOUR_SUCCESS_DIV_ID');

if (form) {
  form.addEventListener('submit', function(e) {
    e.preventDefault();

    // 1. Read values from your custom form fields
    var name     = document.getElementById('YOUR_NAME_INPUT_ID').value.trim();
    var phone    = document.getElementById('YOUR_PHONE_INPUT_ID').value.trim();
    var interest = document.getElementById('YOUR_SELECT_ID').value;

    // 2. Basic validation
    if (!name || phone.length < 10 || !interest) {
      alert('Please fill all fields correctly.');
      return;
    }

    // 3. Copy values into Odoo's hidden native form
    //    Use the IDs from the browser console (Step 3)
    document.getElementById('ODOO_NAME_FIELD_ID').value     = name;
    document.getElementById('ODOO_PHONE_FIELD_ID').value    = phone;
    document.getElementById('ODOO_INTEREST_FIELD_ID').value = interest;

    // 4. Click Odoo's native submit button — handles CSRF automatically
    document.querySelector('.s_website_form_send').click();

    // 5. Show success message, hide custom form
    form.style.display = 'none';
    if (successBox) successBox.style.display = 'block';
  });
}
💡
Filled example
ODOO_NAME_FIELD_IDowude1wmma9
ODOO_PHONE_FIELD_IDovpkeyzraqc
ODOO_INTEREST_FIELD_IDo8alwh71bxhb
3
If there are multiple Odoo forms on the page

If the page has more than one Odoo native form, document.querySelector('.s_website_form_send') will click the first one it finds. To target the correct one, give the Odoo submit button a unique ID in the HTML editor and use document.getElementById('your-unique-id').click() instead.

06

Step 5 — Hide the Odoo Native Form with CSS

The Odoo form must exist in the DOM but should be invisible to users.

1
Add one line of CSS to hide the Odoo form section

In the Odoo website editor, go to Customize → Edit CSS. Add this single line:

CSS — paste in Odoo custom CSS
.s_website_form { display: none !important; }
Why this works
display: none hides the Odoo form visually but it still exists in the HTML. JavaScript can still find it, fill its fields, and click its submit button. The user never sees it.
🚫
Never delete the Odoo form section
If you delete it, the JavaScript bridge will have nothing to push data into, and form submission will break completely.
07

Step 6 — Test & Verify in CRM Backend

Always test with a dummy entry before going live or handing off.

1
Submit a test entry

On the live page, fill in your custom form with test data:

  • Name: Test Lead
  • Phone: 9999999999
  • Interest: Select any option

Click submit. The success message should appear and the form should hide.

2
Check Odoo CRM backend for the new lead

Go to CRM → Leads in the Odoo backend. The new lead should appear at the top with the name, phone, and event type you entered.

⚠️
If the lead does NOT appear
Open browser Console (F12) and check for JavaScript errors. Most common issues: wrong Odoo field ID, or the Odoo form section was accidentally deleted from the page.
3
Delete the test lead from CRM

After confirming everything works, go to CRM and delete the test lead so it does not pollute your real pipeline data.

08

Quick Reference — Odoo CRM Field Names

Common Odoo CRM field technical names you will encounter when adding fields to the native form.

Standard Odoo CRM field names (name= attribute in HTML)
What it stores Odoo field name (name= attribute) Notes
Lead title / Subject name Required by Odoo. Used as the lead title in CRM.
Contact name contact_name The person’s name shown in CRM lead card.
Phone number phone Standard phone field.
Email email_from Often hidden with a default value like noreply@yourdomain.com
Company name partner_name Used for B2B / corporate forms.
Description / Notes description Free text notes on the lead record.
Event Type (custom) x_studio_event_type Custom field created in Odoo Studio. All Studio fields are prefixed with x_studio_.
Follow Up Notes (custom) x_studio_notes_3 Custom studio field. Exact name varies per Odoo account.
💡
How to find your custom Odoo field names
In Odoo, go to Settings → Technical → Fields and search for your field. The “Field Name” column shows the exact technical name to use in your JavaScript bridge.
09

Use AI to Generate the Bridge JS for Complex Forms

When a form has more than 3 fields, use this AI prompt template instead of writing the JavaScript manually.

When to use this shortcut

Whenever a form has more than 3 fields, or the form is complex (dropdowns, checkboxes, multiple sections), writing the JS manually is error-prone. Give AI your custom form HTML and the Odoo field IDs — it will generate the correct bridge JS instantly.

1
Collect two things before prompting AI
  • Your custom form HTML — copy the entire <form>…</form> block from the HTML editor in Odoo
  • Odoo field IDs output — the console output from Step 3 (the name | id | type list)
2
Copy this prompt template and fill in the two parts

Open Claude (claude.ai) or any AI assistant. Paste this prompt — replacing the two sections marked with [ ]:

AI Prompt Template — copy and fill in your details
I have a custom HTML form on an Odoo website page. I also have an Odoo native
form hidden on the same page that connects to Odoo CRM.

My goal: When the user submits MY custom form, JavaScript should:
1. Read the values from my custom form fields
2. Copy those values into the matching Odoo native form fields
3. Click the Odoo native submit button (.s_website_form_send)
4. Hide my custom form and show a success message div

Here is my CUSTOM FORM HTML:
[PASTE YOUR CUSTOM FORM HTML HERE]

Here is the Odoo native form field list (from browser console):
[PASTE THE CONSOLE OUTPUT HERE — the name | id | type list]

Please write the complete bridge JavaScript for this.
Map each custom form field to its corresponding Odoo field by name.
Include basic validation (required fields must not be empty).
The success div ID is: [YOUR SUCCESS DIV ID]
3
What AI gives back — and what to do with it

AI will return a complete JavaScript block. Here is how to use it:

  • Copy the JS code AI gives you
  • In Odoo website editor, open the HTML block that has your custom form
  • Find the existing <script> tag with the old form submit handler
  • Replace the old handler with the new AI-generated code
  • Save the page and test
⚠️
Always test after pasting AI code
AI code is usually correct but always do a test submission and verify the lead appears in CRM before marking the task done.

Final Checklist Before Going Live

Go through each point before marking the task as done.

  • Odoo native form is on the page and connected to CRM (action = crm.lead)
  • All required fields in Odoo form are either visible or hidden with a default value
  • Field IDs collected from browser console and noted down
  • Bridge JavaScript correctly maps custom form IDs → Odoo field IDs
  • CSS hides the Odoo form section (display: none)
  • Test submission done — lead appeared in CRM backend
  • Test lead deleted from CRM after verification
  • Success message appears and form hides after submission
  • Page tested on mobile device
10

Frequently Asked Questions

Common questions about connecting custom HTML forms to Odoo CRM.

This error happens because Odoo uses CSRF (Cross-Site Request Forgery) protection on all its forms. If you try to submit a custom HTML form directly to Odoo’s backend endpoint, it rejects the request. The fix is the JavaScript bridge method — keep Odoo’s native form on the page (hidden with CSS), copy your form’s values into it via JavaScript, and trigger Odoo’s own submit button. This way Odoo sees its own form submitting and accepts it.
.s_website_form_send is the CSS class Odoo assigns to the native form’s submit button. In the JavaScript bridge, you call document.querySelector('.s_website_form_send').click() to programmatically submit the Odoo form. Because this is Odoo’s own button, the CSRF token is included automatically and the submission goes through without errors.
Odoo generates random IDs (like owude1wmma9) for each form field when you save the page in the website editor. Every time you save the page, these IDs can regenerate. This is why you must always re-run the browser console command after editing the Odoo native form — to get the latest IDs before updating your JavaScript bridge.
Yes. The bridge method works for any number of fields. For forms with many fields (5 or more), use the AI prompt template in Section 9 — give the AI your full form HTML and the console output, and it will generate the complete bridge JavaScript automatically. You don’t need to manually match each field.
The most common causes are: (1) Wrong Odoo field ID in the JavaScript — re-run the console command and check the IDs match exactly. (2) The Odoo native form section was accidentally deleted from the page — add it back and repeat the setup. (3) A required Odoo field is empty — make sure all required fields either have a value from your custom form or a default value set in the editor. Open F12 → Console to see any JavaScript errors.
No, Odoo Studio is not required for standard fields (name, phone, email, description). You only need Odoo Studio if you want to add custom fields that don’t exist in CRM by default — like an “Event Type” dropdown or “Budget Range” field. Standard fields work out of the box.
Published by Medkon · Odoo CRM Form Integration Guide
Last updated: April 2026
Scroll to Top