splitforms.com

Contact form · AJAX (vanilla JS)

AJAX contact form with vanilla JavaScript

No framework? No problem. Submit a form via the native fetch() API and show inline success/error messages — pure browser JavaScript, zero dependencies, no jQuery, no axios. Works in every modern browser back to Edge 18.

  • 500 free / mo
  • 14ms latency
  • No backend code
AJAX (vanilla JS) contact form — copy-paste code for splitforms

No backend code

No server, API route, or SDK. Your AJAX (vanilla JS) form posts straight to one endpoint.

Straight to your inbox

Every submission is emailed to you and saved to a searchable dashboard — spam filtered before it reaches you.

Design without limits

It's your own AJAX (vanilla JS) markup and styles. Splitforms is only the backend, so nothing constrains how the form looks.

Copy-paste ready

Your AJAX (vanilla JS) contact form, ready to paste.

Replace YOUR_ACCESS_KEY with the key from your dashboard — that's the whole integration. No SDK to install, no build step, just the html you already write.

Generate access key
contact.html
<form id="contact" autocomplete="off">
  <input type="text"  name="name"    placeholder="Name"    required />
  <input type="email" name="email"   placeholder="Email"   required />
  <textarea           name="message" placeholder="Message" required></textarea>
  <input type="checkbox" name="botcheck" style="display:none" tabindex="-1" />
  <button type="submit">Send</button>
  <p id="msg"></p>
</form>

<script>
  const form = document.getElementById("contact");
  const msg  = document.getElementById("msg");

  form.addEventListener("submit", async (e) => {
    e.preventDefault();
    msg.textContent = "Sending…";

    const formData = new FormData(form);
    formData.append("access_key", "YOUR_ACCESS_KEY");

    try {
      const res  = await fetch("https://splitforms.com/api/submit", {
        method: "POST",
        body: formData,
      });
      const data = await res.json();
      if (data.success) {
        msg.textContent = "Thanks! We'll be in touch.";
        form.reset();
      } else {
        msg.textContent = "Something went wrong: " + (data.message || "Try again");
      }
    } catch (err) {
      msg.textContent = "Network error. Try again.";
    }
  });
</script>

How to add it

How to add a contact form to a AJAX (vanilla JS) website.

To add a contact form to a AJAX (vanilla JS) website you need three things: a free splitforms access key, the html snippet above, and your key pasted into it. No backend, server, or SDK — the form posts to one URL and every submission lands in your inbox and dashboard.

Get your free splitforms access key

Sign up at splitforms.com, verify your email, and copy your access key from the dashboard. No credit card required.

Drop the AJAX (vanilla JS) snippet into your project

Copy the AJAX (vanilla JS) code example into your project and replace YOUR_ACCESS_KEY with the key from step 1.

Receive submissions in your dashboard

Submissions arrive in the splitforms dashboard within seconds. Free includes inbox delivery; Pro adds Slack, Discord, Sheets, or any signed webhook URL.

Where submissions go

Where do your AJAX (vanilla JS) form submissions go?

Every submission is emailed to you and saved to a searchable dashboard — spam filtered before it ever reaches you. Search, export to CSV, or forward it to a webhook or Slack on Pro.

  • 500 submissions per month, free forever
  • Honeypot + AI spam classifier on every plan
  • Signed webhooks to Slack, Discord, your server
AJAX (vanilla JS) contact form submissions in the splitforms dashboard

No backend needed

Do you need a backend for a AJAX (vanilla JS) form? No.

Your AJAX (vanilla JS) form posts standard FormData to one URL. Splitforms validates the access key, runs the spam classifier, and forwards it to your email — so there's no server, API route, or database for you to build or maintain.

  • Pure browser JavaScript — no jQuery, no axios, no framework
  • Inline success / error messages without a page reload
  • Works in every modern browser (Chrome, Firefox, Safari, Edge 18+)
How splitforms processes a AJAX (vanilla JS) form submission

Best practices

What a production-ready AJAX (vanilla JS) form needs.

The difference between a form that works in the demo and one that survives launch traffic — the production-tested defaults, in priority order.

  • Use form.elements and FormData together, not querySelector chains. FormData(form) is one line and handles disabled/unchecked fields correctly.
  • Set the submit button's text dynamically: 'Send' → 'Sending…' → 'Send' again. Users on slow networks need feedback or they re-click.
  • Wrap the fetch in try/catch AND check data.success. Network errors and HTTP errors are different things — catch both.
Production-ready AJAX (vanilla JS) contact form best practices

How SplitForms works

From form to workflow in 3 simple steps.

Connect your form, collect every submission, and send data where it needs to go — without building backend infrastructure.

A SplitForms contact form submission launching straight to your inbox

Add your endpoint

Point your form to your unique SplitForms endpoint. That's it.

HTML form pointing at a SplitForms submit endpoint

Receive submissions

We instantly capture and organize every submission in your inbox.

Submissions inbox with searchable leads and status pills

Route anywhere

Send data to email, spreadsheets, CRMs, webhooks, and 7,000+ apps.

Generic integration tiles for email, sheets, chat, CRM, automate, and webhook

No credit card required. Set up in under 60 seconds.

Connect & automate

Connect your favorite tools and automate everything

SplitForms works with the destinations you route to and the platforms you build on — from Slack and Sheets to WordPress, Shopify, and Next.js.

Connect your SplitForms form to Slack, Google Sheets, Mailchimp, Zapier and more

Trusted by indie teams and agencies shipping forms worldwide

PETAL/COKRAFT.DELINEAR-XBUILD.DEVSTUDIO 71MERIDIANFRAME&CO

Testimonials

Loved by developers shipping at every scale.

40 quotes on record — from indie hacks to agency migrations.

Questions

AJAX (vanilla JS) contact form questions.

View all FAQs
How do I add an AJAX contact form without a framework?

Copy the HTML + script snippet above into any page. Replace YOUR_ACCESS_KEY with your splitforms key. The script attaches a submit listener, builds FormData, posts to splitforms.com, and renders the response inline. No build step, no npm install.

Does splitforms work with jQuery's $.ajax / $.post?

Yes. Use jQuery's $.post or $.ajax with processData: false, contentType: false so it doesn't double-encode the FormData. Modern browsers don't need jQuery for this — but the splitforms endpoint accepts requests from any HTTP client.

How do I handle form errors with vanilla JavaScript?

Check data.success after parsing the JSON response. If false, render data.message into your status element. Wrap the fetch in try/catch for network errors, and check res.ok for HTTP-level errors — they're three separate failure modes.

Can I use splitforms with axios, ky, or other fetch libraries?

Yes — anything that POSTs FormData to a URL works. The splitforms endpoint doesn't care about the client library, only about the request body and the access_key field.

How do I customize the success / redirect behavior?

Two options. (1) Inline success: render a styled <p> with aria-live after a 2xx response (default in our snippet). (2) Configure a URL in Dashboard → Form settings → Redirect and let the browser submit natively for a server-side 302.

Does this work without JavaScript at all?

The AJAX version requires JS. For a no-JS fallback, add action="https://splitforms.com/api/submit" method="POST" to the form tag and configure any thank-you URL in the splitforms dashboard. With JS, your handler intercepts; without JS, the browser performs a native form POST.

Forgetting e.preventDefault() reloads the page

Without preventDefault, the browser does its own form submission to wherever the form's action attribute points (or the current page) AND your fetch runs. You see a flash, the page reloads, and your handler's effects are lost.

FormData includes ALL form fields — even disabled ones get dropped

new FormData(form) skips inputs without a name attribute, skips disabled inputs, skips unchecked checkboxes/radios. If a field doesn't show up in your splitforms inbox, check whether it's disabled at submit time.

fetch() doesn't reject on HTTP 4xx/5xx — only network errors

If splitforms returns a 401 (bad key) or 429 (rate limit), fetch resolves successfully. You have to check res.ok or data.success yourself. Wrapping in try/catch only catches network failures, not HTTP errors.

Double-click submit fires two requests

Without disabling the button on the first click, a quick double-click sends two POSTs. Both succeed; the user sees one success message; you see two submissions. Always set button.disabled = true at the start of the handler.

Strict CSP with connect-src 'self' blocks splitforms.com

If your site has a Content-Security-Policy header with connect-src 'self', fetch to splitforms.com is blocked. Add it explicitly: connect-src 'self' https://splitforms.com.

Setting Content-Type manually breaks the multipart boundary

Common mistake: writing fetch(url, { method: 'POST', headers: { 'Content-Type': 'multipart/form-data' }, body: formData }). The browser silently fails to append the boundary parameter (; boundary=---WebKitFormBoundary…) because you've overridden its automatic header — splitforms's parser then sees a malformed body and returns 400. Fix: omit the headers object entirely. The browser sets Content-Type correctly when you pass a FormData instance as the body. Same trap when copying example code from old jQuery tutorials that hardcode the header.

How does AJAX (vanilla JS) handle forms without splitforms?

Vanilla JS / AJAX forms have been the no-framework default since jQuery's heyday. Without splitforms, the 'AJAX' part is one fetch line; the operational part is everything else: a backend route, an SMTP provider, a database for submissions, a honeypot or reCAPTCHA, a thank-you page, error handling for HTTP 4xx/5xx, retry logic. For 'JS-only on a static host' setups (Cloudflare Pages, GitHub Pages, S3), there's literally no server to run the route on — historically that meant Formspree, Formspark, Web3Forms, Basin. Splitforms is the modern entry: same shape, better free tier, better spam filtering, and signed webhooks from Pro.

Any deployment notes for shipping AJAX (vanilla JS) to production?

Vanilla JS deploys to any static host — the snippet is HTML + inline <script>, no build step. CSP: if your site sets connect-src 'self', add https://splitforms.com to the directive or fetch is blocked. Browser support: native fetch is in every browser back to Edge 18 — the snippet runs without polyfills on every market-share-relevant browser. The progressive-enhancement variant (Pattern B) keeps the form working when JS fails to load — useful on flaky networks, ad-blocked clients, or for accessibility tools that disable JS.

Simple pricing

Start free. Scale when you need more.

Choose a plan that fits your workflow — from a free form endpoint to full automations, exports, and higher submission limits.

Free

$0

Free forever

 
Best for testing

For side projects and indie devs.

  • 500 submissions / mo
  • Unlimited forms
  • Email notifications included
  • Honeypot spam filtering
  • Submissions dashboard
  • MCP setup stays free
  • No credit card required

3-Year

$59/ 36 months
was $99 · save 40% · new-user price

Pay $59. 3 years sorted.

  • 15,000 submissions / mo
  • Unlimited forms
  • Everything in Pro
  • Renews every 3 years
  • Long-term discount
  • Priority support included
  • Vote on the roadmap

No credit card required on Free • Cancel anytime