Skip to content

Hosted forms

Share a link to a themed form page that quickforms hosts for you, in a classic, steps or compact layout.

Every published form has a hosted page at https://YOUR-QUICKFORMS-HOST/f/FORM_ID. Open it in a browser and people fill the form in on a page styled the way you chose, with no website of your own needed. It is the same URL as the submit endpoint: GET shows the page and POST takes the submission.

The hosted page is on by default. Change how it looks in the Hosted page section of the form editor, with settings.hosted in the REST API, or with create-form and update-form in MCP.

Layouts

settings.hosted.layout picks one of three layouts.

Layout What it looks like
classic Every field on one page in a single column, with comfortable spacing. The default.
compact Every field on one page with tighter spacing. On wider screens neighbouring short fields (text, email, URL, phone, number, date and single selects) sit side by side in two columns. Longer fields span the full width.
steps One question at a time, with a progress bar and a “1 of 5” counter.

The steps layout

The steps layout is a wizard. Each field is checked as the person moves on, so they fix a problem on the question it belongs to.

  • Enter goes to the next question. In a long text field, Enter adds a new line and Cmd+Enter or Ctrl+Enter moves on.
  • On a question with options (select, radio or checkboxes), the letter keys A, B, C and so on pick an option. On checkboxes they tick and untick.
  • Back goes to the previous question.
  • With more than two questions, the last step is a review, “Check your answers”, listing every answer with a way to go back and change it. The button before it says Review, and the review step has the submit button.
  • If the server rejects an answer, the form jumps back to that question.

Hidden fields are never shown as a step. They are sent with the submission as usual.

Settings

Key Default Description
hosted.enabled true Serve the hosted page. Switch it off to stop serving the page (see switching it off).
hosted.layout classic classic, steps or compact.
hosted.appearance auto auto follows the visitor’s light or dark preference, and changes with it. light or dark forces one.
hosted.accent #0b0b0f Accent colour for buttons, focus rings and the progress bar, as a six-digit hex colour such as #2563eb.
hosted.font sans sans, serif or mono.
hosted.radius rounded Corners: sharp, rounded or pill.
hosted.background plain plain, gradient or grid.
hosted.title null Heading at the top of the page, up to 120 characters. Defaults to the form name.
hosted.intro null Text under the heading, up to 1000 characters. Line breaks are kept.
hosted.submit_label "Submit" Text on the submit button, up to 40 characters.
hosted.logo_url null An https URL of a logo shown to the left of the heading. If the image fails to load, it is left out.
hosted.favicon_url null An https URL of the icon shown in the browser tab. Without one, the page uses the quickforms icon.
hosted.show_branding true Show a small “Powered by quickforms” link under the form. Teams younger than QUICKFORMS_NEW_TEAM_BRANDING_DAYS (30 by default) always show it.
Switch a form to the steps layoutbash
curl -X PATCH https://YOUR-QUICKFORMS-HOST/api/v1/forms/FORM_ID \
  -H "Authorization: Bearer $QUICKFORMS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"settings": {"hosted": {"layout": "steps", "accent": "#2563eb", "intro": "Takes about a minute."}}}'

Only the keys you send change. Like the rest of a form’s settings, settings.hosted is part of a draft when you save with "draft": true, so you can preview a new look before it goes live.

Preview a draft

Add the form’s sandbox key to the URL to preview the draft:

https://YOUR-QUICKFORMS-HOST/f/FORM_ID?sandbox=qf_sandbox_...

The preview shows the form’s draft if it has one, works on forms that have never been published and on forms with the hosted page switched off, and shows a “Preview - sandbox, nothing is sent” ribbon. Submissions from it are sandbox submissions: they are validated and stored, and every email and webhook is simulated. Preview pages are marked noindex. In the dashboard, the Preview draft button on the form page opens the same URL.

What the page does

  • Posts to the same URL. The page sends the submission to POST /f/FORM_ID with fetch and shows the result in place. Validation errors appear next to their fields.
  • After submitting, it shows the form’s success_message (with {{field}} placeholders filled in), or sends the person to redirect_url when one is set. Sandbox previews always show the message.
  • File uploads. File fields are sent with the submission as multipart/form-data, with the same type and size rules as any other post. See file uploads.
  • Honeypots are added to every post, so the form’s honeypots keep working.
  • Turnstile. When the form has Cloudflare Turnstile on, the page shows the widget and sends its token. Add your quickforms host to the widget’s hostnames in Cloudflare. Sandbox previews skip Turnstile.
  • Closed forms. When a form is not accepting submissions, the page says so instead of showing the fields.
  • Personal links. Add ?link=lnk_... to send someone a personal link to the page.

Submissions from the hosted page have source: "hosted".

Closing a form

Set settings.close to stop taking responses, or use Close form under General.

Key Description
max_submissions Close after this many submissions. Spam and sandbox submissions don’t count.
closes_at Close at this time, as an ISO 8601 date.
message Shown to visitors once it’s closed, up to 500 characters.

A closed form answers 410 with "code": "form_closed". The hosted page and the embed show the message instead of the questions. Sandbox tests and your own API submissions still go through, and a payment that was already taken is always kept.

When the page returns 404

  • The form has never been published and the URL has no sandbox key.
  • hosted.enabled is false and the URL has no sandbox key.
  • The form or its team is deleted or suspended.

A wrong sandbox key counts as no key.

Safeguards on hosted pages

Hosted pages are public pages that anyone can send a link to, so they have a few limits:

  • They start no session and receive no account data, and each visitor can load QUICKFORMS_HOSTED_PAGE_RATE_LIMIT pages a minute (120 by default).
  • Every hosted page has a noindex tag, so search engines leave it out.
  • A field can’t ask for passwords or card details. Saving a label or name such as “Password”, “Card number” or “CVV” is rejected with a 422. Take payments with the payment step.
  • With QUICKFORMS_ABUSE_EMAIL set, the page shows a “Report abuse” link that opens an email to that address.

Suspending a form or team

An admin can take a form, or every form on a team, offline from the command line. A suspended form’s hosted page, embed page, public endpoints and file download links return 404.

php artisan quickforms:suspend form FORM_ID
php artisan quickforms:suspend team TEAM_SLUG
php artisan quickforms:suspend form FORM_ID --lift

On a separate domain

Set QUICKFORMS_FORMS_DOMAIN to a domain such as forms.example.com to keep public form traffic off the dashboard’s origin:

  • POST /f/{form} and the other public endpoints, hosted pages, the embed page and the embed scripts answer on that domain only, and every generated URL uses it.
  • GET /f/{form} on the app domain redirects there with a 301, keeping the query string.
  • The root of the forms domain redirects to QUICKFORMS_MARKETING_URL when it is set, otherwise to APP_URL, and nothing else from the app can be reached on it.

Point the domain at the same app. Leave the variable empty to serve everything from APP_URL, which is what local development uses. SESSION_DOMAIN stays unset, so the dashboard’s session cookie never reaches the forms domain.

Switching it off

Set settings.hosted.enabled to false, or switch off Public link under Hosted page. GET /f/FORM_ID then returns a 404, while the submit endpoint, the embed widget and the iframe embed keep working. Sandbox previews still work, so you can keep designing the page while it is off.

Add a field’s name to the form’s link to fill it in. This works for visible and hidden questions, so UTM tags and your own IDs can travel with a response:

https://<forms domain>/f/<form id>?name=Lucy&utm_source=newsletter

Choice questions accept an option’s value or label. Separate several answers with commas on checkboxes. A value that isn’t one of the options is ignored, and anything from a personal link takes priority. People can change what’s in a link, so don’t use it for anything you need to trust, and avoid putting personal details in links you share widely.

Showing earlier answers

Use {{field_name}} in a question’s label or help text to show an answer given earlier in the form. Combined with the link above, Hi {{name}}, can you confirm your details? greets Lucy by name.

Type to search…

↑↓ navigate↵ selectEsc close