---
title: "Hosted forms"
description: "Share a link to a themed form page that quickforms hosts for you, in a classic, steps or compact layout."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.getquickforms.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Hosted forms

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](https://docs.getquickforms.com/submit/): `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](https://docs.getquickforms.com/api/#form-settings), or with `create-form` and `update-form` in [MCP](https://docs.getquickforms.com/mcp/#hosted-forms).

## 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](#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. |

```bash title="Switch a form to the steps layout"
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](https://docs.getquickforms.com/drafts-and-publishing/) 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:

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

The preview shows the form's [draft](https://docs.getquickforms.com/drafts-and-publishing/) 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](https://docs.getquickforms.com/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](https://docs.getquickforms.com/file-uploads/).
- **Honeypots** are added to every post, so the form's [honeypots](https://docs.getquickforms.com/spam-protection/#honeypots) keep working.
- **Turnstile.** When the form has [Cloudflare Turnstile](https://docs.getquickforms.com/spam-protection/#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](https://docs.getquickforms.com/personal-links/) 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](#suspending-a-form-or-team).

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](https://docs.getquickforms.com/payments/).
- 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.

```bash
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](https://docs.getquickforms.com/embed/) and the [iframe embed](https://docs.getquickforms.com/embed/#iframe) keep working. Sandbox previews still work, so you can keep designing the page while it is off.

## Filling in answers from the link

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:

```text
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](https://docs.getquickforms.com/personal-links/) 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.

Source: https://docs.getquickforms.com/hosted-forms/index.mdx
