Orbit Forms
Orbit Forms is your self-hosted Google Forms / TypeForm replacement. Build a form in a drag-drop builder, share a clean public URL at /f/<token>, and watch responses land as rows in an Orbit Sheet of your choice. File-upload fields bridge to Orbit Drive, so the entire submission stays inside your Workspace.
This is the fourth app in Quazzar Workspace, alongside Drive, Mail, and Calendar.
What you get
- Drag-drop builder at
/forms. Seven field types: short text, long text, email, number, single choice, multi choice, file upload. - Public submit URL at
/f/<token>— clean, shell-less page rendered without the Quazzar dock or sidebar. - Submissions become Sheet rows — pick a destination Orbit Sheet (or create one); each submit appends a row in field-order.
- File uploads bridge to Drive — a dedicated form-owned Drive folder receives the files, the Sheet cell value is a Drive share URL.
- Anonymous-friendly by default — turn on
require_loginfor internal-only forms. - Anti-abuse: 30 submissions per IP per form per hour by default, raise/lower per form on Pro+. Optional hCaptcha (operator supplies
HCAPTCHA_SECRET).
Building a form
- Open Forms in the dock (Work group, clipboard icon) or navigate to
/forms. - Click New form. Give it a title and description.
- Build tab — drag a field type from the palette into the field stack on the right (or click to append). Click any field to inline-edit:
- Required toggle.
- Placeholder for text/email/long-text.
- Max length for long text.
- Min / max for number.
- Options list (one per line) for single/multi choice.
- Max size MB / accept mime list for file uploads.
- Preview tab — submit through a sandboxed preview that echoes the cells; nothing writes to the destination Sheet here.
- Share tab — set the destination Sheet ID + tab name, the upload-folder Drive ID (only shown when a
filefield exists), therequire_logintoggle, and the captcha toggle. Copy the public URL or grab the embed snippet. - Click Publish. The header row of the destination Sheet syncs to the current schema labels in field order; the form is now live at
/f/<token>.
Publishing model
Editing a published form mutates in place — there’s no schema versioning. Old responses keep their values aligned with the labels they were submitted under (the labels become Sheet column headers on first publish). Renaming a label after publish does NOT rename the Sheet column header; treat label changes as additive.
File uploads
When a field of type file is in the schema, Orbit Forms auto-creates an upload folder in your Drive (named Form: <title> under /Forms/) the first time a submission with a file lands. Each upload writes the file to that folder; the Sheet row’s cell for that field is a Drive share link.
- The form owner controls the folder — you can move it, rename it, share it externally with a Drive share link.
- Per-field
max_size_mbis enforced server-side — clients that try to upload a larger file are rejected before the file ever reaches Drive. acceptis a list of MIME types (application/pdf,image/*, …). Strict matching only on type/subtype;image/*matches anyimage/....
Anti-abuse
- Rate limit: 30 submits / IP / form / hour (default). Lowered/raised in form settings (Pro+ for non-default values). Persisted server-side, survives restarts.
require_login: flip the public submit endpoint to require an authenticated Quazzar session — handy for internal employee forms.- hCaptcha: enable the toggle in the Share tab. Operator must set
HCAPTCHA_SECRETenv var. If the toggle is on but no secret is configured, the OS logs a warning and accepts submissions (better than bricking a public form).
Plans
| Tier | Forms | File uploads | Captcha |
|---|---|---|---|
| Free (Community) | 1 active form | ❌ | ❌ |
| Pro | unlimited | ✅ | ✅ |
| Team / Enterprise | unlimited | ✅ | ✅ |
Surfaced in /api/license/orbit-features as orbit_forms, orbit_form_uploads, orbit_form_captcha. Hitting a paid limit triggers the standard OrbitUpgradeDialog.
API surface
Authenticated owner endpoints:
GET /api/forms— list owned forms.POST /api/forms— create.GET /api/forms/{id}— fetch (with schema).PUT /api/forms/{id}— update title/description/schema/target.POST /api/forms/{id}/publish— flipis_published, sync header row in destination Sheet.DELETE /api/forms/{id}— delete.GET /api/forms/{id}/export.csv— CSV export of the destination Sheet.
Public peers (no auth required by default):
POST /forms/{public_token}/submit— multipart/form-data or urlencoded.GET /f/{public_token}— HTML shell with the form schema embedded as a JSON island.
Limitations & roadmap
- No branching / conditional logic — TypeForm-style “show field X only when Y answers Z” is a v2 surface.
- No payments / Stripe blocks — Pro+ later.
- Destination Sheet picker is currently a Sheet-ID + tab text input, not a visual picker dialog. The wire format is final; the UI swap is cosmetic and ships in 0.7.5.
- No response-charts dashboard yet — for now use the Sheet’s pivot/chart surface. A dedicated Responses dashboard ships alongside the picker swap.