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

# JavaScript form

> Submit a form with fetch and show the result on your own page.

Use JavaScript when the visitor should stay on your page after submitting.

## HTML

```html theme={null}
<form id="contact-form">
  <label for="name">Name</label>
  <input id="name" name="name" required />

  <label for="email">Email</label>
  <input id="email" name="email" type="email" required />

  <label for="message">Message</label>
  <textarea id="message" name="message" required></textarea>

  <button type="submit">Send message</button>
  <p id="form-status" role="status"></p>
</form>
```

## JavaScript

Replace `YOUR_FORM_PUBLIC_KEY` in the request URL with the Public Key from the Endpoint form's **General** tab.

```js theme={null}
const form = document.querySelector('#contact-form');
const status = document.querySelector('#form-status');
const button = form.querySelector('button[type="submit"]');

form.addEventListener('submit', async (event) => {
  event.preventDefault();
  button.disabled = true;
  status.textContent = 'Sending…';

  const body = Object.fromEntries(new FormData(form));

  try {
    const response = await fetch('https://api.surveyowl.co/v1/submit/YOUR_FORM_PUBLIC_KEY', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body),
    });

    const result = await response.json();
    const error = typeof result.error === 'string'
      ? result.error
      : result.error?.message;

    if (!response.ok) throw new Error(error || 'Could not send the form.');

    form.reset();
    status.textContent = 'Thanks — your message was sent.';
  } catch (error) {
    status.textContent = error.message;
  } finally {
    button.disabled = false;
  }
});
```

The important check is `response.ok`. `fetch()` does not throw automatically when the API returns a 400, 402, or 403 response.

## Sending files

Keep the data as `FormData` when the form contains a file. Do not set a `Content-Type` header—the browser will add the multipart boundary. See [Files and CAPTCHA](/developer-api/files-and-captcha).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.