Features

Forms — Lead Capture Engine

Build data collection forms, publish them publicly, and have every submission automatically create a CRM lead. The direct pipeline from marketing into the CRM — no manual data entry, no spreadsheet handoffs.

  • Free: 3 forms, 100 submissions, builder + public forms (forms:builder, forms:public)
  • Sales: 20 forms, 5,000 submissions, + lead capture (forms:lead-capture) and form duplication (forms:duplicate)
  • Caps scale up the plate ladder — Growth 50 / Full Loop 100 / Agency 250 forms.

Planned: AI form builder (forms:ai-form-builder) is a reserved key (Studio + ai-pack add-on) — no generate-form action or UI ships yet.

Forms management

Forms list (/forms): Table with name, status (Draft/Published/Closed), submission count, last updated, actions. Row actions: Edit, View (preview + share link), View submissions, Publish/Unpublish, Duplicate (Sales), Delete.

Duplicate (Sales): Creates a full copy of the form as a Draft. Requires forms:duplicate feature flag.

Form builder

The full-page form builder (/forms/new or /forms/[formId]) has two panels: the field editor on the left and a live preview on the right.

Field types

TypeInputWhen to use
TextSingle-line inputName, company, short answers
EmailEmail inputContact email (required for lead capture)
NumberNumber inputBudget, team size
Long TextTextareaProject description, questions
DropdownSelectIndustry, product interest
CheckboxCheckboxMulti-select options, consent
RadioRadio groupSingle-select from options
DateDate pickerPreferred meeting date
Deprecated — File Upload. The file field type is no longer selectable in the builder (parity TASK-CUT-01). Existing forms with file fields keep rendering for backwards compatibility, but new fields cannot be created with this type — public-form uploads open a storage/security surface not justified at this stage.

Lead capture configuration

When “Create lead on submit” is enabled:

  • A CRM Lead is created for each submission
  • Field mapping: connect form fields to lead attributes (name, email, phone, company)
  • Both a Name field and Email field must be mapped
  • The created lead's source defaults to 'website' 'form' is not a valid leads.source. Form origin is recorded on leads.source_form_id (FK → forms), and form_submissions.lead_id links the submission back to the created lead.

Public forms

Published forms are accessible at /[locale]/f/[formId] (e.g. /en/f/<uuid>) — no authentication required. Copy the embeddable <iframe> snippet from the “View form” dialog to embed on any external website. The public page (getPublicForm on load, submitPublicForm on submit) is rate-limited per IP (10 submissions/minute per form) and strips HTML tags from string fields.

Submission processing:

  1. Per-IP rate-limit gate + HTML-tag stripping on every string field
  2. Validates submission against form field definitions
  3. Creates a form_submissions row
  4. If lead capture is enabled, the submit_public_form RPC creates a leads row (source defaults to website) with source_form_id set to the originating form, and back-fills form_submissions.lead_id
  5. Returns success or validation error

Technical reference

ItemDetail
Action filesactions/forms.ts (authenticated), actions/public-forms.ts (public)
Server actionsgetForms, getForm, createForm, updateForm, duplicateForm, deleteForm, getFormSubmissions, getPublicForm, submitPublicForm
Feature flagsforms:builder (Free, capped), forms:submissions (Free, capped), forms:public (Free), forms:lead-capture (Sales), forms:duplicate (Sales)
Planned (reserved key, no UI)forms:ai-form-builder (Studio + ai-pack)
Migration00003_domain_tables.sql (forms, form_submissions)
Audit actionsform.created, form.updated, form.deleted, form.submission
Forms — OpsDash Docs | OpsDash