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

# Next.js contact form without an API route

> Add a contact form to a Next.js app — including static exports — with no API route or server action. Submissions, spam filtering, and notifications via Crunchforms.

The usual Next.js answer to a contact form is an API route or a server action — which means your form now needs a server, which rules out `output: 'export'` static deployments and adds code you have to maintain. Pointing the form at a Crunchforms endpoint removes all of it: works with the App Router, the Pages Router, and fully static exports.

## Before you start: create your endpoint

Every guide on this page needs a Crunchforms form ID. Getting one takes about two minutes:

1. [Sign up free](https://crunchforms.com/auth/signup) — 1,000 submissions a month included, no credit card required.
2. In your [dashboard](https://crunchforms.com/dashboard), click **New Form**, give it a name, and pick a response type: **Redirect** for classic form posts (the visitor lands on your thank-you page), or **JSON** if you'll submit with JavaScript and handle the response yourself.
3. Your endpoint is `https://crunchforms.com/form/{formID}` — copy it with the **Copy Action URL** button, or use the dashboard's snippet generator.

The [quickstart](/quickstart) covers this in more detail.

## Option 1: plain form post (works everywhere, zero JS)

A server component is enough. Set the form's response type to **Redirect** and the visitor lands on your thank-you page:

```jsx app/contact/page.js theme={null}
export const metadata = { title: 'Contact' };

export default function ContactPage() {
  return (
    <form action="https://crunchforms.com/form/{formID}" method="post">
      <label htmlFor="email">Email</label>
      <input name="email" type="email" id="email" required />

      <label htmlFor="message">Message</label>
      <textarea name="message" id="message" rows={5} required />

      <button type="submit">Send</button>
    </form>
  );
}
```

This ships no client JavaScript for the form at all.

## Option 2: client component with a JSON response

To keep visitors on the page with inline feedback, make the form a client component and set the response type to **JSON**:

```jsx app/contact/ContactForm.js theme={null}
'use client';

import { useState } from 'react';

export default function ContactForm() {
  const [status, setStatus] = useState('idle');

  async function handleSubmit(e) {
    e.preventDefault();
    setStatus('sending');
    const data = Object.fromEntries(new FormData(e.currentTarget));
    try {
      const res = await fetch('https://crunchforms.com/form/{formID}', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data),
      });
      const result = await res.json();
      setStatus(result.success ? 'sent' : 'error');
    } catch {
      setStatus('error');
    }
  }

  if (status === 'sent') return <p>Thanks — we&apos;ll be in touch!</p>;

  return (
    <form onSubmit={handleSubmit}>
      <input name="email" type="email" required placeholder="you@example.com" />
      <textarea name="message" rows={5} required />
      <button type="submit" disabled={status === 'sending'}>
        {status === 'sending' ? 'Sending…' : 'Send'}
      </button>
      {status === 'error' && <p role="alert">Something went wrong — please try again.</p>}
    </form>
  );
}
```

<Tip>
  Both options work under `output: 'export'` — no server, no API routes, no server actions. This documentation site's parent product, crunchforms.com itself, is a static Next.js export using exactly this pattern.
</Tip>

## Stop the spam before it starts

Every public form gets found by bots eventually. Crunchforms filters submissions server-side on **every plan, including Free**:

<CardGroup cols={3}>
  <Card title="Honeypot" icon="honey-pot" href="/advanced/honeypot">
    A hidden field humans never see — if it's filled, the submission is rejected. Zero friction for real visitors.
  </Card>

  <Card title="Cloudflare Turnstile" icon="cloudflare" href="/advanced/turnstile">
    Invisible bot detection. Add the widget to your form and Crunchforms validates the token server-side.
  </Card>

  <Card title="reCAPTCHA v3" icon="google" href="/advanced/recaptcha">
    Score-based validation with a threshold you control per form.
  </Card>
</CardGroup>

The honeypot alone stops most drive-by spam and takes one extra line of markup — enable it in your form's settings, then include the hidden field in your form.

## Troubleshooting

<AccordionGroup>
  <Accordion title="The form posts, but nothing shows in my dashboard" icon="magnifying-glass">
    * Check the form is set to **Active** in your dashboard.
    * If you've enabled Turnstile or reCAPTCHA on the form, submissions without a valid token are rejected — including your own tests.
    * Check you haven't exceeded your plan's monthly submission quota.
  </Accordion>

  <Accordion title="The visitor isn't redirected after submitting" icon="arrow-right">
    Set the form's response type to **Redirect** and provide a success URL (and a failure URL) in the form settings. If you're submitting with JavaScript, use the **JSON** response type instead and navigate in your code.
  </Accordion>

  <Accordion title="Submitting with fetch/XHR fails" icon="code">
    The endpoint accepts cross-origin requests, JSON bodies (`Content-Type: application/json`), and classic URL-encoded form bodies. Set the form's response type to **JSON** so your code gets `{ "success": true }` back instead of a redirect.
  </Accordion>

  <Accordion title="I want to test without deploying my site" icon="flask">
    Use the **Send Test Submission** action next to your form in the dashboard — it posts a sample submission to your live endpoint so you can see the pipeline working end to end.
  </Accordion>
</AccordionGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Form configuration" icon="sliders" href="/form-config">
    Response types, notification emails, daily summaries, and more
  </Card>

  <Card title="Free HTML form templates" icon="file-code" href="https://crunchforms.com/templates">
    Contact, feedback, RSVP, job application, and quote-request forms ready to paste
  </Card>
</CardGroup>

## Need help?

<Card title="Get Support" icon="envelope" horizontal href="https://crunchforms.com/support">
  Send us a note — we read everything.
</Card>
