Forms — Ciketo Astro
Ciketo has one form, the quote request, and it works as soon as you run the site. It appears in three places:
- “Get a Quote” on Home;
- the Contact page, beside the address and the business hours;
- the end of every service page.
Each one checks the required fields, shows a spinner while sending, says “Thank you”, keeps what the visitor typed when something fails, and drops spam with a hidden honeypot field.
Out of the box it runs in demo mode: nothing is sent, and the fields are logged in the browser console. That’s fine while you build; pick a destination before you publish.
Choose a mode
Section titled “Choose a mode”| You want | Mode | Hosting |
|---|---|---|
| Quote requests by email, with no server to run | Static: a form service (Formspree, Web3Forms, Getform, Basin) | Any static host |
| Quote requests in a CRM, a spreadsheet, Slack… | Static: a webhook (Zapier, Make, n8n, Pipedream) | Any static host |
| Mailchimp or Resend directly, no third party | Server: the site’s own route | A host with an Astro adapter |
Most sites want static mode: it keeps the site 100% static and takes two minutes.
Static mode in two minutes
Section titled “Static mode in two minutes”-
Create a form at your service and copy its endpoint URL (Formspree:
https://formspree.io/f/<id>). -
Copy the example settings and paste the URL:
Terminal window cp .env.example .envPUBLIC_FORM_ENDPOINT=https://formspree.io/f/abcdwxyzWeb3Forms also needs
PUBLIC_FORM_ACCESS_KEY. -
Restart
npm run dev, send a test request, and check that it arrived. -
Set the same variable in your host’s dashboard (or keep
.envif you build locally). The value is baked into the pages at build time, so rebuild after changing it.
The form posts to the same endpoint from all three places; every request carries the same form and subject fields.
Server mode
Section titled “Server mode”For Mailchimp or Resend without a third-party service:
- Add the adapter for your host:
npx astro add vercel(ornetlify,node,cloudflare). - Set
PUBLIC_FORM_MODE=serverand choose where requests go withFORM_PROVIDER(console,webhook,mailchimp,resend, or several comma-separated), plus that provider’s keys from.env.example. - The form now posts to
/api/forms/quoteon your own site. Every other page stays static.
Every detail is in Forms reference: what each service needs, the fields sent, Mailchimp consent settings, and writing your own provider.
What the form asks for
Section titled “What the form asks for”| Field | Name it arrives under | Required |
|---|---|---|
| Full Name | name |
yes |
| Company Name | company |
|
| Work Email | email |
yes |
| Phone Number | phone |
|
| Origin | origin |
|
| Destination | destination |
|
| Shipping Method (Ocean Freight, Air Freight, Road Freight, Multimodal) | method |
yes |
| Estimated Weight | weight |
|
| Preferred Departure Date | date (as 2026-10-12) |
|
| Tell us about your shipment | message |
|
| The consent box under the message | consent (yes when ticked) |
Every request also carries form (quote) and subject (“New quote request”). In server mode, Resend puts the
sender’s name in the email’s subject (“New quote request — Jane Doe”) and replies go to the sender; Mailchimp stores the
name as FNAME and the phone as PHONE.
Changing the form
Section titled “Changing the form”The labels, placeholders, the shipping methods, the group titles (“Contact Information”, “Shipment Details”,
“Additional Details”), the consent text, the button texts (“Request My Quote”, “Thank you”, “Something went wrong”) and
the subject (notification) are content: quoteForm in src/content/site.json. consentLabel is how the consent box
is named in server-mode emails and notes.
A field arrives at your service under its name, so keep the names you already map somewhere.
- To make a field required, set
"required": trueon it inquoteForm.fields(the browser checks it first). For server mode, also add its name torequiredinsrc/lib/forms/definitions.ts. - To add a field, add it to
quoteForm.fields, then to one of the groups insrc/components/sections/QuoteForm.astro. Server mode takes every field ofquoteForm.fields. - To remove a field, take it out of
QuoteForm.astroandquoteForm.fields, and out ofrequiredindefinitions.tsif it is there.npm run checknames any file that still uses it (the style guide’s sample form shows four of the fields). - To show a thank-you page instead of “Thank you” on the button, add
redirectTo="/thank-you"to<Form>inQuoteForm.astroand create that page (Pages and sections).
Testing before launch
Section titled “Testing before launch”- Submit the form on the live site with a real address, and reply to the test.
- Check the “Something went wrong” path once: point the endpoint at a wrong URL in a preview build, submit, and confirm that the visitor’s text is still there.
Spam and privacy
Section titled “Spam and privacy”The honeypot stops the usual bots (a bot that fills the hidden field is shown “Thank you” and nothing is sent), and form services filter spam on their side.
Requests go only where you point them. The demo’s privacy policy, terms and cookie policy (legal.json) are sample
texts: replace them with your own, and say in your privacy policy what happens to quote requests. The line above the
button is quoteForm.consent.
Ask for consent before you add senders to a marketing audience: in server mode, Mailchimp adds them as transactional
unless you change MAILCHIMP_STATUS.