Core concepts
Before you build a form, it helps to understand the primitives the product is built on. This page walks through every object you will encounter — forms, steps, fields, answers, logic, endings, submissions — and how they fit together at runtime. Read this once and the rest of the docs will make sense.
The mental model
AnimationFunnel is built around six primitives. Learn these and the rest of the product is just configuration:
- Forms — the top-level container. Has a slug, settings, and a collection of steps.
- Steps — the pages a visitor sees. Each step renders one or more fields.
- Fields — individual questions. The atom of the product.
- Logic — rules that branch, hide, or calculate based on earlier answers.
- Endings — terminal screens the visitor can be routed to.
- Submissions — the record of everything the visitor answered.
Around those sit three environmental concepts — workspaces (who owns what), languages (how the form is translated), and integrations (where answers flow afterward). Everything else in AnimationFunnel is a variation on these themes.
Forms
A form is the top-level container. It owns a slug, a set of settings, a collection of steps, and a published version history. Most user-facing operations (editing, publishing, sharing, analytics) happen at the form level.
Identity — slug, ID, and URL
- Form ID — a stable internal UUID. Used by the API and never changes, even if the slug is renamed.
- Slug — the human-readable path segment (e.g.
/f/lead-gen-2026). Must be unique per workspace; editable at any time without breaking old submissions. - Hosted URL —
https://<workspace>.animationfunnel.com/f/<slug>, or your own custom domain on Pro+ plans. - Embed URL — the same route served without the marketing chrome, intended for iframe or script embeds.
Form settings
Each form carries a settings record covering its visitor-facing and operator-facing behavior:
- Theme — colors, fonts, background, button radius, progress bar style.
- Languages — the canonical language plus any translations, and the auto-detection rule.
- Notifications — who gets emailed on each submission, digest frequency, Slack channel target.
- Redirect — optional post-completion URL that replaces the default ending screen.
- Tracking — UTM capture policy, consent requirements, server-side pixel targets.
- Access — public, password-protected, domain-restricted, or require-login.
- Retention — how long to keep submissions before automatic purge.
Form states
- Draft — the working copy. Visible to editors in the dashboard; not reachable by the public URL.
- Published — a frozen snapshot served to visitors. Each publish creates a new version; previous versions are preserved for rollback.
- Archived — public URL returns 410 Gone; submissions are preserved but no new ones are accepted.
- Deleted — soft-deleted for 30 days, then permanently removed. Submissions can be exported before permanent deletion.
Form shapes
Mechanically, every form is just a list of steps — but the builder surfaces a handful of "shapes" as starting templates that correspond to common use patterns:
- Classic form — one step, all fields on one page.
- Conversational funnel — one question per step, auto-advance on answer.
- Quiz / assessment — scored step sequence with a result screen keyed to the score.
- Multi-path qualifier — branching tree with per-branch endings (most lead-gen funnels).
- Payment flow — form + payment field + confirmation ending (Pro+ integrations).
Steps
A step is a page the visitor sees. A form always has at least one step; most have several. Steps are the unit of navigation: clicking next moves to the next step, clicking previous moves back, and logic can jump to any step by ID.
Anatomy of a step
- ID — stable identifier used by jump rules and analytics. Auto-generated from the step title; editable.
- Title— the step's display title (optional on fields-only layouts).
- Description — short copy shown under the title.
- Fields — ordered list of fields rendered on this step.
- Visibility rule — optional logic expression that determines whether the step is shown at all.
- Next-button behavior — visible, hidden (on auto-advance), or a custom label.
Step types
- Question step — one or more fields the visitor answers. The default.
- Welcome step — a cover screen with no inputs, just a call-to-action button. Optional; often used for funnels to set expectation.
- Ending step — terminal. Covered in detail in the Endings section.
- Content step — no inputs, just text / media. Useful for mid-form explainers or social-proof screens between question groups.
- Payment step — a single payment field checkout inside the funnel.
Navigation & progress
By default, steps advance in order. Logic can override this at any point:
- Sequential — next step is the step directly after the current one in the list.
- Jump — a logic rule moves the visitor to a specific step ID.
- Skip — a step with a visibility: false evaluation is silently skipped.
- Back — the visitor can always go back unless
allow_back: falseis set on the step. Going back preserves answers.
The progress bar calculates percentage as current_step_index / total_reachable_steps, where reachable-steps reflects the current logic evaluation. As answers change the reachable path, the progress bar recalculates.
Fields
A field is a single question. Fields are the atom of the product — nearly every feature (validation, logic, piping, scoring, translation) composes at the field level.
Anatomy of a field
- Key — short stable identifier used in logic, recall tokens, webhook payloads, and CSV exports (e.g.
email,team_size,use_case). Auto-generated from the label but should be edited to something short and predictable. - Type — the field type (
short_text,email,dropdown,rating, etc.). See Field types for the full list. - Label — the visible question. Supports recall tokens (
Hi {{field:name}}!). - Help text — secondary copy rendered below the label.
- Placeholder — the faint text shown inside the input before the visitor types.
- Required — boolean. Required fields block step advance until filled.
- Validation — type-specific rules (regex, min/max, accepted file MIME types).
- Default value — pre-fills the field; overridable via URL parameters for prefill scenarios.
- Visibility rule — optional logic expression that hides the field when false.
- Hidden — field is never rendered but still captures a value (from URL, default, or logic calculation).
Field keys — why they matter
Every field has a key, and that key is the name downstream systems see. Good keys pay off in four places:
- Logic —
team_size >= 50is readable;field_3 >= 50is not. - Recall tokens —
{{field:company}}beats{{field:shorttext_2}}. - Webhooks— stable keys mean your backend parser doesn't break when you rename a label.
- CSV exports — column headers are the keys; analysts will thank you.
Convention: lowercase, underscore-separated, noun-first (company_size, budget_range). Keep them stable — renaming a key does not migrate historical submissions to the new name.
Validation
Validation rules run client-side on blur and server-side on submit. A mismatch blocks form submission with a type-specific error message. Supported rules vary by type; the most common:
- Required — the value must be present.
- Min / max length — for text types.
- Min / max value — for numeric and date types.
- Regex — for short text with a specific shape (ZIP code, VAT number).
- File type & size — for file upload.
- Allowed values — whitelist enforcement for free-text answers.
Hidden fields
Hidden fields are invisible to the visitor but still captured on the submission. Common sources:
- URL parameters —
?utm_source=googleand arbitrary query params are captured automatically. - Referrer —
_referrer,_referrer_domain. - IP-derived geography —
_ip_country,_ip_region. - Computed values — results of calculation rules (
_score,_total). - Session metadata —
_user_agent, device type, browser language.
Answers
An answer is the value a visitor supplies for a field. Answers belong to a submission and are keyed by field key.
Per-field-type answer shape
{
"email": "[email protected]",
"team_size": 85,
"budget": 10000,
"industry": "SaaS",
"tools_used": ["Notion", "Slack", "Linear"],
"use_case": "We need a lead qualification form for inbound demos.",
"rating": 4,
"launch_date": "2026-06-15",
"consent": true,
"resume_file": {
"url": "https://files.animationfunnel.com/...",
"name": "alex_resume.pdf",
"size": 42981
}
}The shape is stable per field type: a multi-select is always an array of strings, a date is always an ISO-8601 string, a file upload is always an object with url, name, size. This means your webhook consumer can parse the payload with a single schema regardless of the form.
Updating answers
Visitors can revise answers by going back to a previous step. The canonical value is whatever was last written before submission. After submission, answers become immutable to the visitor but can be edited by operators from the dashboard (with an audit trail of who changed what).
Localized answers
Answers are stored in the visitor's input language. AnimationFunnel preserves the _language field alongside each submission so you know which translation the visitor saw. Free-text answers are never re-translated into a canonical language automatically — if you need that, run the raw answer through the OpenRouter integration in a post-processing step.
Logic rules
Logic rules make the form responsive to what the visitor has already answered. Every rule has a condition (an expression) and an effect (show / hide / jump / calculate).
The four kinds of rules
- Visibility — show or hide a field, a step, or a choice inside a multi-select based on earlier answers. Hidden inputs do not block submission and are not included in the final submission object.
- Jump— redirect the flow to a specific step ID after the current step completes. Used for branching funnels ("if industry = healthcare, jump to the HIPAA step").
- Calculation — compute a value from other answers and store it on a hidden field. Used for scores, totals, risk classifications, pricing.
- Routing — pick which ending screen the visitor lands on based on computed state. See Endings.
When logic evaluates
- On answer change — visibility rules re-evaluate immediately so the UI can hide/show fields without reload.
- On step advance — jump rules fire here; the visitor is moved to the target step before the next render.
- On submit — calculation and routing rules fire one last time to produce the final state of the submission.
Side effects
Calculation rules write their result to a hidden field; that hidden field becomes part of the submission payload and is available to downstream logic, routing, recall tokens, and integrations. Rules do not (cannot) make network calls, mutate other visible answers, or have any effect outside their own bound field.
The expression language
Logic conditions are written in a small expression language shared across visibility, jump, and calculation rules. The language is purposefully limited — enough to express qualification logic, not enough to execute arbitrary code.
Operators
- Equality —
=,!= - Comparison —
>,>=,<,<= - Inclusion —
in,not in - String —
contains,starts_with,ends_with,matches(regex) - Emptiness —
is empty,is not empty - Composition —
AND,OR,NOT, parentheses - Arithmetic —
+,-,*,/,%(in calculations only)
Referencing fields
Inside expressions, fields are referenced by their key without any prefix: team_size >= 50. Inside copy (labels, ending text, descriptions), fields are referenced with the recall-token syntax {{field:team_size}} — see the next section.
Example expressions
# Visibility: show the "company" field only for business inquiries
visibility: "inquiry_type = 'business'"
# Jump: route healthcare leads to the HIPAA step
jump:
when: "industry = 'healthcare'"
to: "hipaa-step"
# Calculation: simple quiz score
calculation:
target: "quiz_score"
expression: "correct_answers * 10"
# Calculation: BMI
calculation:
target: "bmi"
expression: "weight / (height * height)"
# Visibility: combined conditions
visibility: "(country = 'US' OR country = 'CA') AND budget >= 5000"Recall tokens (answer piping)
A recall token is a placeholder in copy that gets replaced with a previous answer at render time. It lets you personalize later questions, ending screens, and notifications based on what the visitor has already said.
Syntax
Simple: {{field:first_name}}
With fallback: {{field:first_name | fallback: "there"}}
Inside copy: Hi {{field:first_name}}! Tell us about {{field:company}}.Where recall tokens work
- Field labels, descriptions, placeholders, help text
- Step titles and descriptions
- Ending screen copy
- Webhook payloads (in string fields)
- Slack / email notification templates
- Pipedrive field mappings (in the mapped value)
- OpenRouter prompt templates
Fallbacks for empty values
If a recalled field has no value yet (because the visitor hasn't answered it, or the field is hidden via logic), AnimationFunnel substitutes the fallback if provided, or collapses the token silently otherwise. Never display a raw{{field:...}} to a visitor — configure a fallback for every token you use in user-facing copy.
Endings
An ending is a terminal screen: the visitor has reached it and the form is complete. Endings are first-class in AnimationFunnel — you can have as many as you want, and routing logic picks which one each submission lands on.
Anatomy of an ending
- ID — stable identifier referenced by routing logic.
- Title — headline shown to the visitor.
- Message — body copy; supports recall tokens for personalization.
- Call-to-action — optional button with a URL (Calendly link, resource page, app download).
- Media — optional image, video, or Calendly embed.
- Redirect — optional URL that auto-navigates after a delay, bypassing the ending screen.
Multi-ending routing
Routing rules decide which ending a submission lands on. Rules are evaluated top-down; the first match wins. A fallback ending is required so every submission is guaranteed to land somewhere.
endings:
- id: "book-demo"
when: "_tier = 'hot'"
cta:
label: "Book a demo"
href: "https://cal.com/team/demo"
- id: "nurture"
when: "_tier = 'warm'"
message: "Thanks {{field:first_name}} — a rep will be in touch soon."
- id: "self-serve"
when: "_tier = 'cold'"
cta:
label: "Read the docs"
href: "/docs"
- id: "default"
when: true # fallback
title: "Thanks!"Endings vs. post-submit redirects
A redirectskips the ending screen entirely and sends the visitor to an external URL. Redirects are best for "form is a bridge to another page" flows (e.g. gated content downloads). Endings are best for "form completion is the moment" flows (lead capture, applications) where the visitor experience itself is valuable.
Submissions
A submissionis the persistent record of one visitor's journey through a form — the answers, the path they took, the metadata captured along the way. Submissions are the unit of analysis in the dashboard and the payload shape of webhooks and integrations.
What's on a submission
{
"id": "sub_01HZK9...",
"form_id": "frm_01HX...",
"form_version": "v42",
"status": "completed", // or "partial", "failed"
"started_at": "2026-04-20T14:10:02Z",
"completed_at": "2026-04-20T14:12:41Z",
"duration_ms": 159231,
"ending_id": "book-demo",
"language": "en",
"answers": {
"email": "[email protected]",
"team_size": 85,
"use_case": "Inbound qualification form."
},
"computed": {
"_score": 82,
"_tier": "hot",
"_score_reason": "Enterprise-size team, decision-maker role, in-budget."
},
"metadata": {
"ip_country": "US",
"ip_region": "CA",
"user_agent": "Mozilla/5.0 ...",
"referrer": "https://google.com",
"utm_source": "google",
"utm_medium": "cpc",
"utm_campaign": "q2-demo"
}
}Status lifecycle
in_progress— visitor has started the form but not finished. Has a partial answer payload, updated as they advance.completed— visitor reached an ending. Submission is immutable and triggers integrations.partial— visitor abandoned. Transitions fromin_progressafter a configurable inactivity timeout (default: 30 minutes).failed— completed but an integration or validation failure occurred. The submission exists and is reviewable; a retry can promote it tocompleted.deleted— soft-deleted. Hidden from the dashboard but recoverable for 30 days.
Partial (abandoned) submissions
Partial submissions are captured automatically from the first answered field onward. They preserve whatever the visitor supplied before closing the tab or going idle. Partial capture enables:
- Drop-off analysis per step (where do visitors quit?).
- Re-engagement emails (if email was collected early).
- Debugging ("this field kills the conversion rate").
Partial submissions do not fire integrations by default — that behavior is opt-in per integration, because most downstream systems expect completed records.
Retention & deletion
Retention is configurable per form. Defaults: 24 months for Business plans, 12 months for Pro, unlimited on Enterprise. Individual submissions can also be deleted on demand (GDPR right-to-erasure workflow) from the dashboard or the DELETE /v1/submissions/{id} API.
Languages & translation
Multilingual support is a first-class primitive, not a bolt-on. A form has one canonical language (the one it was authored in) and zero or more translations.
Language detection
Which translation a visitor sees is resolved in this order:
?lang=frURL parameter — explicit override.- Saved preference (cookie) from a prior visit.
Accept-Languagebrowser header.- Form's configured default for the visitor's inferred country.
- Canonical language — fallback.
Translation model
Translations are stored as a per-language override of every translatable string (labels, help text, ending copy, button text, validation messages). Untranslated strings fall back to the canonical language silently — a partial translation never breaks the form.
Machine-seeded translations
New translations can be seeded from a machine translation pass (DeepL / Google / OpenRouter-mediated LLM translation), then edited field-by-field in the dashboard. The editor flags low-confidence machine output so a human reviewer knows where to spend time.
Publishing & versioning
Edits in the dashboard are never immediately visible to visitors. You build in the draft, then hit Publish to create a snapshot that serves the public URL.
Publish snapshots
Every publish creates an immutable snapshot with an incrementing version (v1, v2, v3 ...). Submissions always record the version they were captured against — if you change a field's label between v3 and v4, historical submissions still remember the v3 label and behave correctly in exports.
Preview mode
Draft changes are testable via a preview URL that includes a signed token. Preview does not write real submissions and does not fire integrations. Preview links can be shared with stakeholders for review.
Rollback
Any prior version can be restored as the live snapshot in one click. Rolling back does not delete the draft — your current working copy is preserved and can be re-published after fixing the issue that caused the rollback.
Publish hooks
A form.published webhook fires on every publish, with the full form definition in the payload. This lets downstream systems (documentation generators, spec validators, screenshot bots) stay in sync with whatever is currently live.
Integrations
An integration is a connection between AnimationFunnel and an external system. Integrations listen for events on a form (submission completed, step completed, form abandoned, form published) and act on them (send a webhook, create a Pipedrive deal, append a Google Sheets row, run an OpenRouter prompt).
Triggers
submission.completed— the visitor reached an ending.submission.partial— a session became partial after the inactivity timeout.submission.scored— scoring finished (if scoring is enabled).step.completed— a visitor finished a specific step. Opt-in; useful for multi-step drop-off analytics.form.published— a new form version went live.
Retry semantics
All integration dispatches retry with exponential backoff on 5xx responses or timeouts (1s, 5s, 30s, 2m, 10m, 1h, 6h, 24h). After the final attempt fails, the dispatch is marked failed in the integration log and can be manually replayed from the dashboard.
Ordering guarantees
Integrations fire in parallel per submission; there's no ordering guarantee between them. If one integration depends on another having completed (e.g. CRM needs the score first), wire the second integration to fire on submission.scored instead of submission.completed.
Workspaces & teams
A workspace is the container at the top of everything: it owns forms, team members, billing, API keys, and workspace-level settings (custom domains, branding, default languages).
Roles
- Owner — full control. Can delete the workspace, manage billing, invite admins.
- Admin — can manage forms, integrations, team members (except owners). Cannot manage billing.
- Editor — can create and edit forms, publish, view submissions. Cannot invite team or manage integrations.
- Viewer — read-only. Can see submissions and analytics but cannot edit forms.
- Form-scoped roles — on Business+ plans, any role can be scoped to a subset of forms instead of the whole workspace. Useful for agencies with separate client folders.
Multiple workspaces
A single user account can belong to multiple workspaces. Use cases: personal vs. work, agency managing multiple clients, internal segmentation between departments. Workspace switching lives in the top-left of the dashboard.
Audit log
Every state-changing action (publish, delete, invite, role change, integration change) is written to a workspace audit log, visible on Business+ plans. The log is retained for the life of the workspace and is exportable.
How it all fits together
At runtime, a single visitor interaction composes all of the above primitives in a predictable sequence:
Visitor lands on /f/<slug>
│
▼
[Form] is loaded from the currently published snapshot (v42)
│
▼
[Language] is detected (URL → cookie → Accept-Language → default)
│
▼
[Step 1] renders; [Fields] are displayed with [Visibility] logic applied
│
▼
Visitor answers → [Answer] written; [Visibility] re-evaluates live
│
▼
"Next" → [Jump] rules evaluated → move to next [Step]
│
▼
... loops through steps ...
│
▼
Last step → [Calculation] rules fire → [Routing] picks an [Ending]
│
▼
[Submission] persisted (status = completed)
│
▼
[Scoring] runs async (rules + AI, if enabled)
│
▼
[Integrations] fire in parallel:
├─ Webhook POST to your backend
├─ Pipedrive deal created
├─ Google Sheets row appended
├─ Slack notification sent
└─ OpenRouter enrichment prompt
│
▼
[Ending] screen renders; visitor sees CTA / Calendly / redirectDesign principles
A few opinions underpin the product. These aren't features you need to configure — they're defaults you will run into:
Stable keys > pretty labels
Field keys survive label edits; CSV columns survive renames; webhook payloads survive redesigns. The dashboard optimizes for the writer, but the underlying data model optimizes for the downstream consumer.
Declarative, not imperative
Logic is expressed as rules, not scripts. You describe whatshould happen ("hide this field if industry = healthcare"), not how. This keeps forms portable, auditable, and safe — there is no user-writable code path at runtime.
Visitor experience is non-blocking
Nothing that isn't strictly necessary to render the form blocks the visitor. Scoring runs async; integrations run async; translations fall back silently; partial submissions are captured without disruption. The ending screen shows immediately.
Everything is versioned
Publish snapshots are immutable. Submissions reference the version they ran against. Scoring models reference their_score_version. This means any submission in the database can be perfectly re-rendered, re-scored, or re-exported with the exact logic that was live at the time.
Data is yours, always exportable
Every submission is exportable as CSV, Excel, or JSON. The form itself is exportable as a portable JSON spec (importable into another workspace). There is no vendor-lock-in path that traps your data inside the product.
Glossary
- Answer — the value a visitor supplies for a field.
- Calculation — a logic rule that computes a value and writes it to a hidden field.
- Canonical language — the language a form was originally authored in; the fallback for untranslated strings.
- Draft — the editable working copy of a form.
- Ending — a terminal screen a visitor can be routed to.
- Field — a single question.
- Field key — the stable identifier for a field, used in logic, recall tokens, webhooks, and exports.
- Form — the top-level container.
- Hidden field — a field that captures a value but is never rendered.
- Integration — a connection to an external system that fires on form events.
- Jump — a logic rule that moves the visitor to a specific step.
- Logic rule — a conditional statement that changes form behavior at runtime.
- Partial submission — a submission where the visitor did not reach an ending.
- Publish snapshot — an immutable frozen version of a form served to visitors.
- Recall token — a
{{field:key}}placeholder that is replaced with a previous answer at render time. - Routing — the rule set that chooses which ending a submission lands on.
- Step — a page visitors see; a form is a sequence of steps.
- Submission— the persistent record of a visitor's journey through a form.
- Translation— a per-language override of a form's translatable strings.
- Version — a numbered publish snapshot.
- Visibility — a logic rule that shows or hides a field, step, or choice.
- Workspace — the top-level billing and permissions container.
Next steps
Was this page helpful?