SAVEFORM

Integrate · Last updated April 23, 2026

JavaScript / Fetch integration

For single-page apps, custom loading states, or any case where you do not want a full page reload, POST to the same endpoint from JavaScript. The response is JSON — see Response format for the exact shape.

Fetch example

Send a JSON body with fetch. This works from any modern browser, server, or edge runtime.

JavaScriptsubmit-form.js
const formData = {
  name:    'John Doe',
  email:   'john@example.com',
  message: 'Hello!',
};

fetch('https://saveform.io/api/submit/YOUR_FORM_ID', {
  method:  'POST',
  headers: { 'Content-Type': 'application/json' },
  body:    JSON.stringify(formData),
})
  .then((response) => response.json())
  .then((data)     => console.log('Success:', data))
  .catch((error)   => console.error('Error:', error));

React example

A typical controlled form in React, posting JSON and surfacing the result inline.

TSXContactForm.tsx
import { useState } from 'react';

export function ContactForm() {
  const [status, setStatus] = useState<'idle' | 'sending' | 'ok' | 'err'>('idle');

  async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    setStatus('sending');
    const data = Object.fromEntries(new FormData(e.currentTarget));

    const res = await fetch('https://saveform.io/api/submit/YOUR_FORM_ID', {
      method:  'POST',
      headers: { 'Content-Type': 'application/json' },
      body:    JSON.stringify(data),
    });

    setStatus(res.ok ? 'ok' : 'err');
  }

  return (
    <form onSubmit={onSubmit}>
      <input name="name"    required />
      <input name="email"   type="email" required />
      <textarea name="message" required />
      <button disabled={status === 'sending'}>Send</button>
      {status === 'ok'  && <p>Thanks — got it.</p>}
      {status === 'err' && <p>Something went wrong.</p>}
    </form>
  );
}

Tips

JavaScript / Fetch integration | SaveForm.io