Feedback Forms

Feedback forms (also called widgets) are the configurable feedback collectors you embed on your site. Each form has a name, an allowed domain and a settings object that controls the widget's appearance, prompts, capture features, branding and automatic triggers.

Overview

A feedback form in Roast is the entity behind an embeddable feedback widget. Internally each form is referred to as a "widget", and your plan limits the number of forms (widgets) you can create.

Every form has three top-level properties: a name (a label for your own reference, 1–100 characters), a domain (the hostname the widget is allowed to run on), and a settings object (a JSON blob controlling everything about how the widget looks and behaves). Forms belong to the workspace owner's account, even when an admin creates them on the owner's behalf.

Submissions collected through the widget are attached to the form. When you list your forms, each one is returned with a total submission count plus separate praise and roast counts.

Forms are owned by the workspace owner. Team members act within the owner's workspace, and all forms they see or edit belong to that owner.

Deleting a form is permanent and removes the form and its associated data — there is no undo.

Who can create and manage forms

Creating, editing and deleting forms all require the forms:write permission. Reading/listing forms only requires forms:read.

By role: Owners and Admins can create, edit and delete forms. Editors and Viewers can only view forms (forms:read) — they cannot create, change or delete them. Attempting a write action without permission returns a 403 Forbidden.

Owner: full access (create, edit, delete).

Admin: full access (create, edit, delete).

Editor: read-only on forms.

Viewer: read-only on forms.

All form actions require you to be signed in; an unauthenticated request returns 401 Unauthorized.

Creating a form

When you create a form you must supply a name and a domain. If either is missing the request is rejected with a 400 error. If you don't pass a settings object, the form is created with Roast's default settings (see "Form settings reference").

  1. 1Provide a Name for the form (your own internal label).
  2. 2Provide the Domain the widget will run on (see "Domain rules" below).
  3. 3Optionally provide custom settings; otherwise the defaults are applied.
  4. 4Save. On success the new form is created and returned.

Plan limit is enforced on creation. Spark allows 1 widget; Flame and Inferno allow unlimited widgets.

If you are already at your plan's widget limit, creation is rejected with: "Plan limit reached. Upgrade to create more widgets." (403).

The limit check is enforced both before and after insert, so concurrent creation attempts that would overshoot the limit are rolled back automatically.

Widget limits are keyed on the workspace OWNER's plan — an admin creating a form is constrained by the owner's plan, not their own.

Domain rules

The domain must be a bare hostname — no scheme (http://), no path and no port (except for localhost). Examples of valid values: example.com, app.example.com.

Two special values are accepted: "*" allows the widget on any domain, and "localhost" (optionally with a port, e.g. localhost:3000) is accepted for local development.

A domain longer than 253 characters, or one containing a scheme/path/port, is rejected as invalid (400).

Use "*" only when you genuinely want the widget to run anywhere; it removes the domain restriction.

The same domain validation applies both when creating and when editing a form.

Editing a form

You can update a form's name, domain and/or settings. Only the fields you send are changed. Names are trimmed and must be 1–100 characters; domains are validated by the same rules as creation.

Settings are deep-merged into the existing settings: any top-level settings key you don't send is preserved as-is. Each settings key you do send is fully validated, and an invalid value returns a 400 with a descriptive message (for example, an invalid theme or a non-hex accent colour).

You can only edit a form that belongs to your workspace. Editing a form that doesn't exist returns 404; a form owned by a different workspace returns 403.

Settings validation only accepts known keys. Sending an unrecognised key inside features or triggers is rejected with an error naming the offending key.

Turning off the "Powered by Roast" branding (branding.showPoweredBy = false) requires the Flame plan or above. On Spark this returns 403 with code UPGRADE_REQUIRED and a prompt to upgrade at /dashboard/settings/billing.

Branding removal is gated on the workspace OWNER's plan, not the editing member's.

Deleting a form

Deleting a form permanently removes it and its associated data. The action requires forms:write (Owner or Admin) and the form must belong to your workspace.

A non-existent form returns 404; a form owned by another workspace returns 403. On success the API confirms the deletion.

There is no soft-delete or trash — deletion is immediate and permanent.

Form settings reference — appearance

These settings control how the widget looks. Each has a default that is applied to new forms unless you override it.

theme — "dark", "light" or "auto". Default: dark. "auto" follows the visitor's system preference.

accentColor — a 6-digit hex colour (e.g. #FF4500). Must include the leading # and exactly 6 hex digits. Default: #FF4500 (orange).

borderRadius — corner rounding of the widget: "none", "sm", "md", "lg" or "full". Default: lg.

position — where the widget sits on the page: "bottom-right", "bottom-left", "top-right" or "top-left". Default: bottom-right.

Form settings reference — text and prompts

These settings control the words your visitors see. Roast separates feedback into two modes: praise (positive feedback) and roast (critical feedback).

triggerText — the labels on the two call-to-action buttons: { praise, roast }. Both are required strings, each 200 characters or fewer. Defaults: praise "Leave Feedback", roast "Roast Us 🔥".

prompts — the question prompts shown to visitors, as two lists: { praise: string[], roast: string[] }. Each list can hold up to 10 prompts, and each prompt is 500 characters or fewer.

Default praise prompts: "What do you love about our product?", "How has this helped you?", "Would you recommend us to a friend?".

Default roast prompts: "What frustrates you the most?", "What would you change immediately?", "Where did we drop the ball?".

Form settings reference — capture features

The features object toggles which capture methods the widget offers. Each value is a boolean and only the three known keys are accepted.

videoEnabled — allow video feedback. Default: true.

screenRecordingEnabled — allow screen recording. Default: true.

roastModeEnabled — enable the critical "roast" feedback mode alongside praise. Default: true.

Sending any feature key other than these three returns a validation error.

Form settings reference — branding

The branding object controls the Roast attribution and an optional custom logo.

showPoweredBy — whether the "Powered by Roast" badge is shown. Default: true. Setting this to false requires the Flame plan or above (otherwise 403, UPGRADE_REQUIRED).

logoUrl — a URL to your own logo, or null for none. Default: null. If provided it must be a string no longer than 2048 characters.

Form settings reference — automatic triggers

The triggers object controls whether and when the widget opens automatically, rather than only when a visitor clicks it. The master switch must be on for any trigger to fire.

Triggers fire based on visitor behaviour, and a cooldown prevents the widget re-opening too often. Cooldown state is stored in the visitor's browser (localStorage), scoped to the form, so a dismissed widget won't immediately reappear.

enabled — master switch for automatic triggers. When false, no automatic opening happens. Default: false.

exitIntent — open when the visitor's mouse moves toward the browser chrome to leave (desktop). Boolean. Default: false.

scrollDepthPercent — open once the visitor scrolls past this percentage of the page. A number between 1 and 100, or null to disable. Default: null.

timeOnPageSeconds — open after this many seconds on the page. A number between 1 and 86400 (24 hours), or null to disable. Default: null.

rageClick — open when a rapid rage-click pattern is detected (3 clicks within 1 second). Boolean. Default: false.

cooldownHours — minimum hours between automatic opens for this form. An integer between 0 and 8760 (one year). Default: 24.

Only these six keys are accepted inside triggers; any other key is rejected.

Public widget settings

The widget itself fetches a public, read-only copy of a form's settings (no sign-in required, since site visitors are anonymous). Only an explicit allowlist of keys is exposed publicly: theme, accentColor, borderRadius, position, triggerText, prompts, features, branding and triggers. Any other data stored in settings is never sent to the widget.

Public settings responses are cached for 5 minutes, so appearance or prompt changes may take up to a few minutes to appear on your live site. If a form can't be found, the widget falls back to Roast's default settings so it keeps working.

Because of the 5-minute cache, allow a short delay before checking changes on your live site.

Any missing setting falls back to its default in the public response, so the widget always has a complete, valid configuration.

Frequently asked questions

How many feedback forms can I create?
It depends on your plan. The Spark plan allows 1 widget (form). The Flame and Inferno plans allow unlimited widgets. If you hit your limit you'll see "Plan limit reached. Upgrade to create more widgets." The limit is based on the workspace owner's plan.
Can team members create or edit forms?
Owners and Admins can create, edit and delete forms. Editors and Viewers can only view them. Members who lack the forms:write permission get a 403 Forbidden if they try to make changes.
What domain format should I use?
Use a bare hostname with no http://, path or port — for example example.com or app.example.com. Use "*" to allow any domain, or "localhost" (optionally localhost:3000) for local development. Schemes, paths, ports (other than on localhost) and hostnames over 253 characters are rejected.
How do I remove the "Powered by Roast" badge?
Set the branding option showPoweredBy to off. This requires the Flame plan or above; on Spark the change is blocked with an upgrade prompt (UPGRADE_REQUIRED). Upgrade at /dashboard/settings/billing.
I changed my widget's colour/prompts but the live site looks the same — why?
The widget's public settings are cached for 5 minutes. Wait a few minutes and refresh. The change is saved immediately on the form itself; only the public copy the widget reads is cached.
If I only change one setting, will my other settings be lost?
No. Settings are deep-merged — any top-level settings key you don't include in your update is preserved exactly as it was. Only the keys you send are changed.
What happens to my feedback if I delete a form?
Deleting a form is permanent and removes the form and its associated data. There is no trash or undo, so export or move anything you need first.
What are praise mode and roast mode?
Roast splits feedback into two modes: praise (positive feedback) and roast (critical feedback). Each has its own call-to-action button label and its own set of prompts. You can turn roast mode off via the roastModeEnabled feature toggle.