Every workflow needs input. Forms are how you get it without building a website. The Form node in n8n lets you create professional, multi-step forms that feed directly into your automations. No coding. No external form builders. No complicated integrations.
Need to collect leads? Gather customer feedback? Build an intake process for client requests? Run surveys? The Form node handles it all while giving you complete control over what happens after someone hits submit.
The Form Building Challenge
Most automation platforms force you to use external form tools like Typeform or Google Forms, then connect them via webhooks or Zapier. That means managing multiple services, dealing with API limits, and losing data fidelity during transfers.
n8n’s Form node eliminates this complexity. The form lives inside your workflow. Data flows directly into your automation logic. No middleware. No conversion issues. No subscription costs for yet another tool.
What You’ll Learn
- The difference between Form Trigger and Form nodes (and when to use each)
- How to configure all 12 form field types for any use case
- Building multi-step forms with logic between pages
- Conditional branching for dynamic form experiences
- Custom CSS styling to match your brand
- Pre-filling fields via URL parameters
- Handling file uploads properly
- Debugging the most common form issues
When to Use the Form Node
Before diving into configuration, understand when the Form node is the right choice versus other input methods.
| Scenario | Best Option | Why |
|---|---|---|
| Collect data from humans via web form | Form Node | Purpose-built for user input |
| Receive data from external services | Webhook Node | APIs send JSON, not form submissions |
| Fetch data from APIs | HTTP Request Node | Pull data rather than receive it |
| Process incoming emails | Email Trigger | Dedicated email handling |
| Manual workflow testing | Manual Trigger | Quick testing without form setup |
| Scheduled data processing | Schedule Trigger | No human input needed |
Rule of thumb: If a human needs to enter data through a browser, use the Form node. If a system sends data programmatically, use the Webhook node.
Understanding the Two Form Nodes
n8n provides two nodes for forms, and understanding the difference is critical.
Form Trigger Node
The Form Trigger starts your workflow. It generates a public URL where users access your form, displays the first page of fields, and waits for submissions. Every form workflow begins with a Form Trigger.
What it provides:
- A unique test URL for development
- A production URL for live use
- Form title and description
- The first page of form fields
- Custom CSS styling options
Form Node
The Form node adds additional pages to your form. It creates multi-step experiences where users progress through several screens. You can add processing logic between Form nodes to validate data, fetch related information, or make routing decisions.
What it provides:
- Additional form pages after the trigger
- Form Ending options (completion screen, redirect, custom HTML)
- The same field types as Form Trigger
- Ability to display processed data back to users
How They Work Together
Form Trigger → [Process] → Form → [Process] → Form → Form Ending
↓ ↓ ↓ ↓ ↓
Page 1 Validate Page 2 Route Page 3
The Form Trigger always comes first. Form nodes chain after it. Between each Form node, you can insert any processing logic: validation, database lookups, conditional routing, API calls, or data transformation.
Test URL vs Production URL
Like the Webhook node, Form nodes provide two URLs:
| Aspect | Test URL | Production URL |
|---|---|---|
| URL path | /form-test/... | /form/... |
| When active | Only while testing in editor | Only when workflow is active |
| Purpose | Development and debugging | Live form collection |
| Data visibility | Shows in editor immediately | Visible in execution log |
Critical: Test URLs stop working when you close the editor. Production URLs only work when the workflow is activated. Using the wrong URL is the most common form debugging issue.
Your First Form
Let’s build a working form from scratch.
Step 1: Add the Form Trigger Node
- Create a new workflow in n8n
- Click + to add a node
- Search for “Form Trigger”
- Click to add it as your starting node
Step 2: Configure Basic Settings
With the Form Trigger selected:
- Form Title: Enter “Contact Request”
- Form Description: Enter “Tell us how we can help”
- Form Fields: Add the following fields:
- Name (Text, required)
- Email (Email, required)
- Message (Textarea)
Step 3: Test Your Form
- Click “Test step” to open the form
- A new browser tab opens with your form
- Fill out the fields and submit
- Return to n8n to see the submitted data
Step 4: View the Response Data
After submission, the Form Trigger outputs data like:
{
"submittedAt": "2025-03-15T10:30:00.000Z",
"formMode": "test",
"Name": "Jane Smith",
"Email": "[email protected]",
"Message": "I'd like to discuss a project"
}
Access this data in subsequent nodes:
{{ $json.Name }}returns “Jane Smith”{{ $json.Email }}returns “[email protected]”{{ $json.Message }}returns the message text
For complex expressions, use our expression validator tool to test before running.
Step 5: Activate for Production
- Connect additional nodes to process submissions (send email, add to CRM, etc.)
- Save the workflow
- Toggle the workflow to “Active”
- Copy the production URL and share it
Form Field Types
The Form node supports 12 field types covering virtually any data collection need.
Field Types Overview
| Field Type | Input Format | Best For |
|---|---|---|
| Text | Single line | Names, short answers |
| Textarea | Multi-line | Long responses, descriptions |
| Email format | Contact emails (with validation) | |
| Number | Numeric only | Quantities, ages, amounts |
| Password | Hidden input | Sensitive data collection |
| Date | Date picker | Appointments, deadlines |
| Dropdown | Select menu | Single choice from options |
| Checkbox | Multiple selection | Multi-select options |
| Radio | Single selection | Exclusive choices |
| File | File upload | Documents, images |
| Hidden | Invisible | Tracking data, metadata |
| Custom HTML | Rendered HTML | Instructions, images, videos |
Configuring Each Field Type
Text and Textarea
Basic text input for short or long responses:
{
"fieldLabel": "Full Name",
"fieldType": "text",
"placeholder": "Enter your name",
"requiredField": true
}
{
"fieldLabel": "Project Description",
"fieldType": "textarea",
"placeholder": "Describe your project in detail",
"defaultValue": ""
}
Validates email format automatically:
{
"fieldLabel": "Email Address",
"fieldType": "email",
"placeholder": "[email protected]",
"requiredField": true
}
Number
Accepts only numeric input:
{
"fieldLabel": "Budget",
"fieldType": "number",
"placeholder": "5000"
}
Date
Provides a date picker with format options:
{
"fieldLabel": "Preferred Date",
"fieldType": "date",
"formatDate": "mm/dd/yyyy",
"requiredField": true
}
Available formats: mm/dd/yyyy, dd/mm/yyyy, yyyy-mm-dd
Dropdown (Single Select)
Single choice from predefined options:
{
"fieldLabel": "Department",
"fieldType": "dropdown",
"fieldOptions": {
"values": [
{ "option": "Sales" },
{ "option": "Support" },
{ "option": "Engineering" }
]
},
"defaultValue": "Sales",
"requiredField": true
}
Dropdown (Multi-Select)
Multiple selections allowed:
{
"fieldLabel": "Interests",
"fieldType": "dropdown",
"multiselect": true,
"fieldOptions": {
"values": [
{ "option": "Product Updates" },
{ "option": "Company News" },
{ "option": "Technical Tips" }
]
}
}
Checkboxes
Multiple independent options:
{
"fieldLabel": "Services Needed",
"fieldType": "checkbox",
"fieldOptions": {
"values": [
{ "option": "Consulting" },
{ "option": "Development" },
{ "option": "Training" }
]
},
"defaultValue": ["Consulting"]
}
Radio Buttons
Mutually exclusive choices:
{
"fieldLabel": "Priority",
"fieldType": "radio",
"fieldOptions": {
"values": [
{ "option": "Low" },
{ "option": "Medium" },
{ "option": "High" }
]
}
}
File Upload
Accept file submissions:
{
"fieldLabel": "Resume",
"fieldType": "file",
"multipleFiles": false,
"acceptFileTypes": ".pdf, .doc, .docx"
}
File data becomes available as binary data for processing with nodes like Google Drive, S3, or Email.
Hidden Fields
Pass data through the form without displaying it:
{
"fieldLabel": "Campaign Source",
"fieldType": "hiddenField",
"fieldValue": "google-ads-spring"
}
Hidden fields are useful for tracking form sources, passing context between pages, or including metadata in submissions.
Custom HTML
Display rich content within your form:
{
"fieldType": "html",
"elementName": "instructions",
"html": "<div style='padding: 10px; background: #f0f0f0;'><strong>Important:</strong> Please complete all sections.</div>"
}
Custom HTML renders in the normal form flow. Note that <script>, <style>, and <input> elements are not supported for security reasons.
Multi-Step Forms
Single-page forms work for simple cases, but complex data collection benefits from multiple steps. Multi-step forms reduce cognitive load, improve completion rates, and allow processing between pages.
Building a Multi-Step Form
- Start with a Form Trigger (Page 1)
- Add processing nodes if needed
- Add a Form node (Page 2)
- Repeat for additional pages
- End with a Form node using Form Ending
Example: Lead Qualification Wizard
Form Trigger → Edit Fields → Form → Switch → Form → Send Email
(Contact) (Validate) (Company) (Route) (Thanks)
Data Persistence Across Steps
All data from previous pages remains accessible throughout the workflow. In page 3, you can still access page 1 data:
{{ $('Form Trigger').item.json.Email }}
{{ $('Form').item.json.CompanySize }}
Processing Between Pages
Between Form nodes, you can:
- Validate data with an IF node
- Look up existing records in your database
- Calculate values based on inputs
- Fetch related data from APIs
- Route users down different paths
Example: Lookup existing customer
Form Trigger → HTTP Request → IF → Form (existing) / Form (new)
(Email) (CRM lookup) (exists?)
Form Ending Options
Every form workflow needs an ending. The final Form node provides three options:
Show Completion Screen
Displays a confirmation message to the user:
Page Type: Form Ending
Form Ending: Show Completion Screen
Title: "Thank you!"
Message: "We've received your request and will respond within 24 hours."
Redirect to URL
Sends users to another page after submission:
Page Type: Form Ending
Form Ending: Redirect to URL
URL: "https://yoursite.com/thank-you"
Show Custom HTML/Text
Display fully customized content:
Page Type: Form Ending
Form Ending: Show Text
Text: "<h2>All Done!</h2><p>Your reference number is: {{ $json.referenceId }}</p>"
You can include n8n expressions in custom text to show personalized confirmations.
Branching Logic and Conditional Forms
Dynamic forms adapt based on user responses. n8n supports this through branching workflows.
Mutually Exclusive Branches
When only one path executes based on a condition:
Form Trigger → Switch → Form (Path A) / Form (Path B)
The Switch node evaluates the condition and routes to one branch. Only that branch’s Form Ending displays.
Example: Support Ticket Routing
// Switch node routing logic
if ({{ $json.IssueType }} === "Billing") {
// Route to billing form
} else if ({{ $json.IssueType }} === "Technical") {
// Route to technical form
}
Each path collects different follow-up information relevant to the issue type.
Parallel Branches
When multiple branches receive data, n8n executes them sequentially. The last branch’s Form Ending displays.
Important: For forms, mutually exclusive branches (using Switch or IF) provide cleaner user experiences. Parallel execution is better suited for processing workflows, not form display.
Conditional Field Display
Within a single form page, you cannot conditionally show/hide fields based on other answers. This requires multiple pages:
- Page 1: Ask the qualifying question
- Switch node: Evaluate the answer
- Page 2A or 2B: Show relevant follow-up fields
Custom Form Styling
Default n8n forms are functional but generic. Custom CSS lets you match your brand.
Accessing Custom Styling
- Select your Form Trigger node
- Expand Options
- Find Custom Form Styling
The field pre-populates with default CSS. Modify only what you need.
CSS Override Examples
Change primary colors:
:root {
--color-primary: #6136ff;
--color-primary-hover: #4d2bcc;
}
Update button styling:
.n8n-form-button {
background-color: #6136ff;
border-radius: 8px;
font-weight: 600;
}
Customize form container:
.n8n-form-container {
max-width: 600px;
font-family: 'Inter', sans-serif;
}
Branding Considerations
Keep forms consistent with your website:
- Use your brand colors for buttons and accents
- Match font families when possible
- Maintain consistent border-radius values
- Test on mobile devices (forms are responsive by default)
For CSS fundamentals, see MDN’s CSS basics guide.
Pre-filling Forms with Query Parameters
Pre-populate fields by adding parameters to your form URL. This is useful for personalized links, tracking campaigns, or reducing friction for known users.
URL Parameter Format
Append parameters to the production URL:
https://your-n8n.com/form/my-form?email=jane%40example.com&name=Jane%20Doe
Important: Query parameters only work with production URLs, not test URLs.
URL Encoding
Special characters must be percent-encoded:
| Character | Encoded |
|---|---|
| @ | %40 |
| space | %20 |
| & | %26 |
| = | %3D |
| + | %2B |
Dynamic URL Generation
Generate pre-filled URLs dynamically in your workflows:
// In a Code node or expression
const baseUrl = "https://your-n8n.com/form/feedback";
const email = encodeURIComponent($json.customerEmail);
const name = encodeURIComponent($json.customerName);
const formUrl = `${baseUrl}?email=${email}&name=${name}`;
Use Cases
- Email campaigns: Pre-fill subscriber email from your mailing list
- UTM tracking: Pass
utm_source,utm_medium,utm_campaignvia hidden fields - CRM integration: Include customer ID for automatic record linking
- Referral tracking: Pass referrer information through the form
Protecting Forms with Authentication
By default, n8n forms are publicly accessible. Anyone with the URL can submit data. For internal forms or sensitive data collection, add authentication.
Enabling Basic Authentication
- Select your Form Trigger node
- Set Authentication to “Basic Auth”
- Create credentials with username and password
Users must enter credentials before seeing the form. A browser login prompt appears when they access the URL.
When to Use Form Authentication
| Scenario | Authentication? | Why |
|---|---|---|
| Public contact form | No | You want anyone to reach you |
| Customer feedback | No | Reduce friction for responses |
| Internal request form | Yes | Restrict to employees |
| Sensitive data intake | Yes | Protect confidential submissions |
| Client portal forms | Yes | Verify identity before access |
Authentication Limitations
Basic Auth only: n8n forms support basic authentication, not OAuth or API keys. For advanced access control, consider:
- Embedding forms behind your own authenticated application
- Using a Webhook node with custom authentication instead
- Adding a password field as the first form question (less secure, but no browser prompt)
No per-user tracking: Basic auth validates access but does not identify individual users. If you need to know who submitted the form, add a name or email field.
Self-Hosted URL Configuration
For self-hosted n8n, forms require proper URL configuration to work externally. Set these environment variables:
WEBHOOK_URL=https://your-domain.com
N8N_HOST=your-domain.com
N8N_PROTOCOL=https
Without correct URL configuration, form links may point to localhost or internal addresses that external users cannot access.
Handling File Uploads
File uploads add complexity but open powerful use cases: document collection, image submissions, application attachments.
Configuring File Fields
{
"fieldLabel": "Upload Documents",
"fieldType": "file",
"multipleFiles": true,
"acceptFileTypes": ".pdf, .doc, .docx, .jpg, .png"
}
Options:
multipleFiles: Allow multiple file selectionacceptFileTypes: Comma-separated list of allowed extensions
Accessing Uploaded Files
Uploaded files become binary data items. Access them in subsequent nodes:
// Reference binary data
{{ $binary.data }}
// Get file name
{{ $binary.data.fileName }}
// Get MIME type
{{ $binary.data.mimeType }}
Processing Uploaded Files
Common patterns for file handling:
Save to Google Drive:
- Add Google Drive node after form
- Select “Upload” operation
- Map binary data to file input
Attach to Email:
- Add Send Email node
- Enable attachments
- Select binary data from form
Store in Database:
- Convert binary to Base64 if needed
- Store in blob column or reference external storage
File Size Considerations
n8n has payload limits (default 16MB). For large files:
- Increase
N8N_PAYLOAD_SIZE_MAXon self-hosted instances - Consider external upload services (S3 presigned URLs) for very large files
- Compress files before upload when possible
Common Issues and Solutions
Based on n8n community discussions, these are the problems that trip up most users.
Issue 1: Form Not Appearing
Symptom: Sharing the URL shows an error or blank page.
Causes and fixes:
- Using test URL: Switch to the production URL (without
-testin the path) - Workflow not active: Toggle the workflow to Active in the top right
- URL typo: Copy the exact URL from the node, paths are case-sensitive
Issue 2: Fields Not Pre-filling
Symptom: Query parameters in URL, but fields remain empty.
Causes and fixes:
- Using test URL: Query parameters only work on production URLs
- Encoding issues: Special characters like @ must be percent-encoded (%40)
- Field name mismatch: Parameter names must match field names exactly
Issue 3: Multi-Step Data Missing
Symptom: Can’t access data from previous pages.
Causes and fixes:
- Wrong node reference: Use
$('Form Trigger')or$('Form')to reference specific nodes - Execution path: Ensure data flows through connected nodes, not parallel paths
Issue 4: Custom Styling Not Applying
Symptom: CSS changes don’t appear on the form.
Causes and fixes:
- Cache: Hard refresh the form page (Ctrl+Shift+R)
- Specificity: Add more specific selectors if defaults override yours
- Syntax errors: Validate CSS syntax before saving
Issue 5: File Uploads Failing
Symptom: Form submits but files are missing.
Causes and fixes:
- Size limit: Check payload size limits (16MB default)
- Type restriction: Ensure file extension matches
acceptFileTypes - Binary handling: Verify subsequent nodes properly handle binary data
For systematic debugging, try our workflow debugger tool.
Real-World Examples
Example 1: Contact Form with Email Notification
Scenario: Collect inquiries and notify your team instantly.
Form Trigger → Send Email → Respond with Confirmation
Form Trigger Configuration:
- Title: “Contact Us”
- Fields: Name (text), Email (email), Subject (dropdown), Message (textarea)
Email Node Configuration:
To: [email protected]
Subject: New Contact: {{ $json.Subject }}
Body:
Name: {{ $json.Name }}
Email: {{ $json.Email }}
Message: {{ $json.Message }}
Example 2: Multi-Step Onboarding Wizard
Scenario: Collect client information across multiple focused pages.
Form Trigger → Form → Form → Google Sheets → Form Ending
(Contact) (Company) (Project) (Save) (Thanks)
Page 1 (Form Trigger):
- Name, Email, Phone
Page 2 (Form):
- Company Name, Industry (dropdown), Company Size (radio)
Page 3 (Form):
- Project Description (textarea), Budget (dropdown), Timeline (date)
Google Sheets Node:
- Append row with all collected data
Example 3: Feedback Form with Conditional Questions
Scenario: Show different follow-up questions based on initial rating.
Form Trigger → Switch → Form (Low Rating) / Form (High Rating) → Save
(Rating) (Evaluate)
Form Trigger:
- “How would you rate your experience?” (radio: 1-5)
Switch Logic:
- If rating is 2 or below: Route to “What can we improve?” form
- If rating is 4 or above: Route to “What did you love?” form
Example 4: File Request with Google Drive Upload
Scenario: Collect documents and store them automatically.
Form Trigger → Google Drive Upload → Send Confirmation Email
(File upload)
Form Trigger Configuration:
{
"fieldLabel": "Document",
"fieldType": "file",
"acceptFileTypes": ".pdf, .doc, .docx",
"multipleFiles": false
}
Google Drive Node:
- Folder:
Submissions/{{ $now.format('yyyy-MM') }} - File Name:
{{ $json.Name }}_{{ $json.DocumentType }}.pdf
Pro Tips and Best Practices
1. Keep Forms Simple
Every additional field reduces completion rates. Ask only what you need. If you need extensive information, break it into logical multi-step sections.
2. Use Hidden Fields for Tracking
Pass UTM parameters, referral sources, or campaign IDs through hidden fields:
{
"fieldType": "hiddenField",
"fieldLabel": "source",
"fieldValue": "{{ $json.query.utm_source || 'direct' }}"
}
3. Test on Mobile Devices
n8n forms are responsive, but always verify your custom styling works on phones and tablets. Many users complete forms on mobile.
4. Log Submissions During Development
Add a Set node to log raw submissions during testing:
{
"timestamp": "{{ $now }}",
"formData": {{ JSON.stringify($json) }},
"source": "{{ $json.headers?.referer || 'direct' }}"
}
Send to Google Sheets or a database for debugging.
5. Validate Early
Add validation logic immediately after form submission. Catch bad data before it enters your systems:
// Check email domain
if (!$json.Email.includes('@company.com')) {
throw new Error('Please use your company email');
}
6. Design for Errors
What happens when your form workflow fails? Use the Error Trigger node to catch failures and notify your team. Never leave users hanging.
For comprehensive guidance, see our n8n workflow best practices guide.
When to Get Help
The Form node handles most data collection needs. Some scenarios benefit from expert assistance:
- Complex conditional logic with many branching paths
- Integration with legacy systems requiring custom data transformation
- High-volume forms needing performance optimization
- Enterprise compliance requirements for data handling
Our workflow development services can build production-ready form systems. For strategic guidance on form automation architecture, explore our consulting packages.
Frequently Asked Questions
What is the difference between Form Trigger and Form node?
Form Trigger:
- Starts your workflow
- Displays the first page of fields
- Provides the URL users visit
- Required for any form-based workflow
Form Node:
- Adds additional pages after the trigger
- Creates multi-step form experiences
- Provides Form Ending options (completion screen, redirect, custom HTML)
You can have one Form Trigger followed by multiple Form nodes.
How do I create a multi-step form in n8n?
- Add a Form Trigger node with your first page of fields
- Add a Form node for the second page
- Optionally add processing nodes between them (validation, lookups)
- Repeat for additional pages
- On the final Form node, set Page Type to “Form Ending”
Data access: All pages remain accessible using expressions like $('Form Trigger').item.json.fieldName.
Can I style n8n forms to match my brand?
Yes. In the Form Trigger node:
- Expand Options
- Find Custom Form Styling
- Add CSS to override defaults
Common customizations:
- Button colors and styling
- Font families
- Spacing and container width
- Border radius
Tip: Use a hard refresh (Ctrl+Shift+R) to bypass cache when testing style changes.
How do I handle file uploads in forms?
Setup:
- Add a field with type “file”
- Set
acceptFileTypes(e.g., “.pdf, .doc, .jpg”) - Enable
multipleFilesif needed
Processing:
- Files become binary data after submission
- Use Google Drive, S3, or Email nodes to handle them
Limits: Default payload is 16MB. Increase N8N_PAYLOAD_SIZE_MAX on self-hosted instances for larger files.
Why is my form not showing when I share the URL?
Check these in order:
- URL type: Test URLs (
/form-test/) only work with editor open. Use production URL (/form/). - Workflow status: Toggle must be set to Active (top right).
- URL accuracy: Paths are case-sensitive. Copy directly from the node.
- Execution log: Check for errors preventing the form from rendering.