Collecting Feedback

How the Roast widget captures feedback from your end users — the on-page experience, the difference between Roast and Praise modes, heat levels, text vs video submissions, and exactly what gets stored when someone submits.

How feedback is captured

Feedback is collected by the Roast widget, which you embed on your own site. It appears as a floating launcher button (labelled "Feedback" with a flame icon) pinned to one of four corners — bottom-right, bottom-left, top-right or top-left, depending on the widget's configured position.

When a visitor clicks the launcher (or the widget auto-opens via a trigger), a panel opens on the mode-select screen asking "How are you feeling about us?". From there the visitor chooses Praise or Roast, fills in the relevant form, optionally records a video, and submits. A celebratory success screen confirms receipt.

Every submission is posted to the public endpoint POST /api/submissions. This is an unauthenticated endpoint — end users do not need a Roast account or any login. The widget knows which form it belongs to via a form ID baked into the embed.

The widget themes itself independently of the host page (light/dark plus a configurable accent colour), so it looks consistent wherever it is embedded.

There is a "Powered by Roast" link in the footer, shown only when the form's branding.showPoweredBy setting is enabled.

A dashboard preview of the widget never fires triggers and never requests a real camera — it shows mock recording UI instead.

Roast vs Praise mode

The widget supports two feedback types: praise and roast. Praise is always available. The Roast button only appears on the mode-select screen when the form's roastModeEnabled feature is switched on; if it is off, visitors can only leave praise.

Praise mode ("Share Your Love") is built for positive feedback and testimonials. It asks for a 1–5 star rating, a written comment, and optional attribution details (name, email, job title, company) hidden behind an "Add your details" expander. If the visitor sets the rating to 3 stars or below, the form gently suggests switching to Roast mode instead.

Roast mode ("Roast Us") is built for critical feedback. It centres on a heat-level slider and a free-text box, with contextual prompts that change based on the page URL (pricing, checkout/payment, signup/register pages get tailored prompts, otherwise a default set is used). Owners can override these with custom prompts in the form settings. Roast mode also offers a tick-box "I'd like a response when this is fixed" which reveals an email field.

The two modes also differ in their consent model (see the consent and privacy section). Crucially, roasts are treated as private by default — the roast form always sends consentMarketing as false, regardless of what the visitor does.

Both modes require a written comment AND the display-consent tick-box before the Submit button enables.

Praise submit button reads "Submit Testimonial"; roast submit button reads "Send the Heat".

Heat levels (Roast mode)

Heat level captures how strongly a user feels about a problem. It is set with an interactive slider (drag, tap quick-select emoji buttons, or — on the compact variant — a range input). There are five levels, lowest to highest: Lukewarm ("Mild annoyance"), Warm ("Getting frustrated"), Hot ("Pretty annoyed"), Fire ("Major issue") and Nuclear ("Absolute disaster"). The slider defaults to Hot.

Each level has its own emoji, colour and label, and the form background tint shifts as the level changes. The Nuclear level adds a pulsing animation and a red border on the text box. On mobile the slider gives light haptic feedback as you move between levels.

The chosen heat level is sent with the submission and stored against it. The server validates it against the fixed set (lukewarm, warm, hot, fire, nuclear) and rejects anything else. Heat level applies to roasts only; praise submissions carry a star rating instead.

If no heat level is sent the submission is still accepted and stored with a null heat level — but in practice the roast form always sends one (it defaults to Hot).

Text vs video submissions

A submission can be text-based or video-based. The media type stored is determined server-side: if a video file is attached the submission is recorded as "video", otherwise "text". The server requires at least one of content or video to be present — an empty submission is rejected.

For text, the visitor types into the comment box (praise) or the roast text box. Content is capped at 10,000 characters server-side.

For video, clicking "Record a video" (shown only when the form's videoEnabled feature is on) opens the in-browser recorder. Visitors can choose Camera Only, or — on desktop browsers that support it — Screen + Face (picture-in-picture), which is recommended for roasts because it lets them point at exactly what is wrong. Screen + Face is hidden on mobile. Recording runs through a 3-2-1 countdown, can be paused/resumed, and is capped at 120 seconds (a warning shows in the final 20%). During screen recording the user can pause to draw annotations on the screen. After stopping, they get a preview with Re-record / Play / Use This, and must tick a consent box before submitting. A JPEG thumbnail is auto-generated from an early frame.

Videos are recorded as WebM (VP9). When submitted through the standard widget flow they are sent as part of the same multipart POST to /api/submissions, which accepts files up to 100MB. The server validates both the file extension (webm, mp4, mov, avi, mkv) and the MIME type (video/webm, video/mp4 or audio/webm) and uploads the file plus thumbnail to the roast-videos storage bucket, storing the resulting public URLs on the submission.

Camera/microphone and screen-share require the visitor to grant browser permission; if they decline, an error is shown and they can retry or fall back to text.

Mute can be toggled before/while recording.

Screen + Face is only offered if the browser exposes getDisplayMedia and the device is not detected as mobile.

Large videos: resumable (TUS) uploads

The direct submission endpoint caps videos at 100MB. For larger files there is a separate resumable upload service implementing the tus.io protocol, which uploads the file in chunks and can resume after interruptions. This path supports files up to 500MB.

Unlike the public submission endpoint, the TUS upload endpoints (POST /api/uploads/tus to create an upload, then PATCH/HEAD/DELETE on /api/uploads/tus/[uploadId]) require an authenticated Roast user — every request checks the session and a chunk upload is rejected unless the upload belongs to the calling user. Completed files are assembled and stored in the roast-feedback-media bucket under the user's ID.

Because of the auth requirement, the TUS path is for signed-in dashboard/app contexts rather than anonymous end-user widget submissions, which use the 100MB direct upload.

TUS enforces the 500MB cap both when the upload is created (via Upload-Length) and again on every chunk; over-sized uploads return 413 and the staged data is cleaned up.

Offsets are checked on each chunk — a mismatch returns 409 so the client can re-sync and resume.

What gets stored on submit

On a successful POST /api/submissions the server creates a row in roast_submissions linked to the form, with status set to "pending". Stored fields include: feedback type (praise/roast); media type (text or video); the text content; the video URL and thumbnail URL (if a video was uploaded); heat level (roasts) or rating 1–5 (praise); author name, email, job title and company (where provided); the page URL the feedback came from; the visitor's user-agent; and the two consent flags (display and marketing).

The server validates inputs before storing: type must be praise or roast; rating must be 1–5; email must look valid; author fields are capped at 200 characters; the page URL is capped at 2048 characters and must be a valid http(s) URL.

Newly created submissions start in the "pending" state, ready for review in the dashboard. Creating a submission also fires off your configured integrations (for example Slack, Discord, webhooks or issue trackers) in the background — this dispatch never blocks or fails the visitor's submission.

The endpoint is origin-checked: the request's Origin/Referer hostname must match the form's allowed domain (exact or subdomain). Even wildcard ('*') forms require a browser-set Origin or Referer, so server-side scripts can't post freely.

Rate limiting: submissions are capped at 10 per 60 seconds per client; exceeding this returns HTTP 429.

If the form ID doesn't exist the endpoint returns 404; a mismatched origin returns 403.

Listing/reading submissions (GET /api/submissions) is the authenticated dashboard side and is scoped to the workspace owner's forms — all workspace roles can read.

Frequently asked questions

Do my users need a Roast account to leave feedback?
No. The widget submission endpoint is public and unauthenticated — visitors just open the widget on your site and submit. Only the resumable large-video (TUS) upload path and the dashboard require a signed-in Roast user.
What's the difference between Roast and Praise?
Praise is for positive feedback/testimonials (star rating, optional attribution, optional public marketing consent). Roast is for criticism (heat-level slider, contextual prompts, optional "notify me when fixed" email) and is always private — roasts never carry marketing consent. Praise is always available; Roast only appears if roast mode is enabled on the form.
What are heat levels?
Heat levels are the five-step intensity scale used in Roast mode: Lukewarm, Warm, Hot, Fire and Nuclear. The slider defaults to Hot. The value is stored with the roast so you can prioritise the angriest feedback.
How big can a video be?
Videos submitted directly through the widget are capped at 100MB. The separate resumable (TUS) upload service handles larger files up to 500MB, but that path requires an authenticated user. In-browser recordings are limited to 120 seconds.
Can users record their screen, not just their face?
Yes, on desktop browsers that support screen capture. The "Screen + Face" mode records the screen with a camera picture-in-picture and is recommended for roasts so users can point at the problem. It's hidden on mobile and only offered when video is enabled on the form.
Is consent required?
Display/recording consent is always required — submissions without it are rejected. Public-marketing consent is a separate optional tick-box available only in Praise mode; roasts are always treated as private.
Why might a submission be rejected?
Common reasons: missing form ID (400), invalid feedback type (400), no content and no video (400), missing display consent (400), invalid heat level/rating/email/URL (400), a video over 100MB or with a disallowed format (400/413), the request origin not matching the form's allowed domain (403), an unknown form ID (404), or too many requests — more than 10 per minute (429).
What status are new submissions in?
Every new submission is created with status "pending", ready to be reviewed in the dashboard. Creating it also triggers your configured integrations in the background.