Skip to content

Forms

The Contact form and the career application form work as soon as you run the site: they validate, show a sending state, say “Thank you”, keep what the visitor typed when something fails, and drop spam with a honeypot field.

Out of the box, submissions are written to the server log (FORM_PROVIDER=console) — fine while you build, useless once you publish. Pick a destination before launch.

  1. Copy the example settings:

    Terminal window
    cp .env.example .env.local
  2. Choose one:

    You want Set
    An email for every submission FORM_PROVIDER=resend + RESEND_API_KEY, FORM_EMAIL_TO, FORM_EMAIL_FROM
    It in your CRM, Slack, a spreadsheet… FORM_PROVIDER=webhook + FORM_WEBHOOK_URL (Zapier, Make, n8n, Formspree, your own API)
    The sender in a Mailchimp audience FORM_PROVIDER=mailchimp + MAILCHIMP_API_KEY, MAILCHIMP_AUDIENCE_ID

    Several at once work: FORM_PROVIDER=resend,mailchimp.

  3. Restart npm run dev and send a test submission.

  4. Put the same variables in your host’s dashboard before deploying — .env.local is not uploaded.

Details for each provider, the webhook payload, Mailchimp consent settings and how to write your own provider: Forms reference.

Form Fields
Contact (/contact) First name, last name, email, phone, the services the visitor is interested in, message
Career application (/careers/<role>) First name, last name, email, phone, the role, LinkedIn, other profiles, website, message

The fields are content, not code: they are listed in src/content/pages/contact.ts and career.ts, each with its name, label, placeholder, type and whether it is required. Add, remove or rename them there — a field arrives at your provider under its name, so keep those you already map somewhere. The service checkboxes on the Contact form are the same list, and they are what a visitor picks, not what you sell — update them to match your services.

  • Submit both forms on your own site after deploying, with a real address.
  • Check the destination (inbox, spreadsheet, audience) and reply to the test.
  • Try a failure on purpose: set a wrong API key, submit, and confirm the visitor sees “Something went wrong” and their text is still there.

The honeypot stops the usual bots. If you start getting spam anyway, put a service in front through the webhook provider (Formspree, Web3Forms and Basin all include spam filtering), or add a captcha to the form component.

Submissions go only where you point them; nothing is sent anywhere else. Most countries expect you to say what happens to the data people send you, so add a line under the form (its copy is in src/content/pages/contact.ts) linking to a privacy page of your own — and keep a consent checkbox there if you plan to add senders to a marketing audience.