Introduction

Formserve is a simple way to save information from your website via forms or front-end JavaScript. That is, you can save data from your website without a serverβ€”Formserve is your server.

Formserve works great when you want the simplicity of a static website, but don't want to setup a server for a form or two. Capture leads on landing pages, use for contact forms, collecting emails for a newsletter, polls, surveys, etc.

Formserve works anywhere you can put an HTML form. It works with any static site generator e.g. Jekyll, Hugo, Hexo, GitBook, Gatsby and all others. Formserve also works on any hosting provider, from blog hosting providers like WordPress, to static hosting providers like GitHub Pages or S3, to Platform-as-a-Service providers like Heroku and Docker, and any other method of hosting you have up your sleeve.

πŸš€ Quick Start Guide

Get your first form submission in under 5 minutes! This guide walks you through everything from signup to receiving your first submission.

What You'll Accomplish

  • Create a free Formserve account
  • Set up your first form endpoint
  • Test your form locally
  • Receive your first email notification
1

Create Your Account

Sign up for a free Formserve account. No credit card required!

πŸ“ What you'll need:

  • β€’ A valid email address
  • β€’ A password (8+ characters)
Sign Up Now
2

Create Your First Endpoint

An endpoint is where your forms send their data. Creating one takes just seconds!

Quick Setup - Just 2 Fields:

Example: My Contact Form

Give it a descriptive name so you can identify it later

localhost:3000 (pre-filled)

Start with localhost for testing, add your domain later

✨ Smart Defaults: Email notifications, spam protection, and localhost testing are automatically configured!

Sign in first to create an endpoint

3

Copy Your Access Key

After creating your endpoint, you'll see the Setup tab with your unique access key.

Access Key: Click to copy
abc123def456ghi789

You'll also find ready-to-use code snippets in:

  • HTML - Plain form markup
  • JavaScript - AJAX form handling
  • React - React component example
4

Create a Test HTML File

Create a simple HTML file to test your form. Copy this code and save it as test-form.html:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Test Form</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      max-width: 500px;
      margin: 50px auto;
      padding: 20px;
    }
    input, textarea {
      width: 100%;
      padding: 10px;
      margin: 10px 0;
      border: 1px solid #ddd;
      border-radius: 4px;
    }
    button {
      background: #2563eb;
      color: white;
      padding: 12px 24px;
      border: none;
      border-radius: 4px;
      cursor: pointer;
      font-size: 16px;
    }
    button:hover { background: #1d4ed8; }
  </style>
</head>
<body>
  <h1>Test Contact Form</h1>

  <form action="https://formserve.io/f/YOUR_ACCESS_KEY" method="POST">
    <label>Name</label>
    <input type="text" name="name" required>

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

    <label>Message</label>
    <textarea name="message" rows="4" required></textarea>

    <button type="submit">Send Message</button>
  </form>
</body>
</html>

⚠️ Don't forget: Replace YOUR_ACCESS_KEY with your actual access key!

5

Test Your Form

Open your test-form.html file in your browser and submit the form!

Testing Checklist:

πŸ“§ What to expect: Within seconds, you'll receive an email notification with the form data at the email address you signed up with!

6

View Your Submission

Go to the Submissions tab to see your form data:

  • View all form fields and values
  • Filter by spam, unread, or search
  • Export submissions as CSV, JSON, or XLSX

πŸŽ‰ Congratulations! What's Next?

Customize Settings

Visit the Settings tab to configure:

  • β€’ Add production domains
  • β€’ Adjust spam protection
  • β€’ Customize email notifications
  • β€’ Set up redirect URLs

Add Integrations

Connect your favorite tools:

  • β€’ Slack - Team notifications
  • β€’ Webhooks - Custom workflows
  • β€’ Mailchimp - Email marketing

Deploy to Production

Ready to go live?

  • β€’ Add your production domain
  • β€’ Update your website's form
  • β€’ Test from production
  • β€’ Monitor submissions

Learn Advanced Features

Explore more capabilities:

Setup

Getting started with Formserve is quick and easy - you'll be up and running in less than 5 minutes!

Step 1: Create Your Account

Sign up for a free Formserve account. No credit card required to get started.

Step 2: Create Your First Endpoint

An endpoint is ready to use in just two simple fields:

  • Name - A descriptive name for your form (e.g., "Contact Form")
  • Allowed Domains - Your website domain (pre-filled with "localhost:3000" for local testing)

✨ Smart Defaults: Formserve automatically configures email notifications to your account email, enables spam protection, and allows localhost testing. You can customize everything later!

Step 3: Get Your Access Key

After creating your endpoint, you'll see the Setup tab with:

  • Your unique access key
  • Ready-to-use code snippets (HTML, JavaScript, React)
  • Instructions for integration

Understanding Endpoints

An endpoint is a unique URL where your HTML forms submit data. Each endpoint acts as a secure receiver for your form submissions.

Endpoint Management Tabs

After creating an endpoint, you'll have access to four organized tabs:

  • Setup - Your access key, code snippets (HTML/JavaScript/React), and integration instructions
  • Settings - Configure domains, spam protection, notifications, redirects, and file uploads
  • Submissions - View, search, filter, and export all form submissions
  • Integrations - Connect Webhooks, Slack, Mailchimp, and other services

⚠️ Security Notice: Allowed domains are required for all endpoints. This security measure prevents unauthorized access, protects your submission quota, and blocks spam attacks. Only forms on your specified domains can submit to your endpoint.

Allowed Domains Configuration

Allowed domains determine which websites can submit to your endpoint. This is your primary security control.

Domain Format Examples:

  • example.com - Allows example.com and www.example.com
  • *.example.com - Allows all subdomains (app.example.com, blog.example.com, etc.)
  • localhost:3000 - For local development (include the port number)
  • example.com, *.myapp.com, localhost:3000 - Multiple domains (comma-separated)

Important: Forms from domains not in your allowed list will be rejected, and the attempt will be logged as spam in your endpoint's spam log.

πŸ’‘ Pro Tip: Start with localhost:3000 to test locally, then add your production domain before going live. You can update allowed domains anytime in the Settings tab.

Working with Multiple Forms

Each endpoint can receive submissions from multiple forms on your website. You can organize submissions by using different field names or by creating separate endpoints.

Option 1: Multiple Forms, One Endpoint

Use the same endpoint for different forms and identify them with a hidden field:

<!-- Contact Form -->
<form action="https://formserve.io/f/YOUR_ACCESS_KEY" method="POST">
  <input type="hidden" name="form_type" value="contact">
  <!-- Your fields -->
</form>

<!-- Newsletter Form -->
<form action="https://formserve.io/f/YOUR_ACCESS_KEY" method="POST">
  <input type="hidden" name="form_type" value="newsletter">
  <!-- Your fields -->
</form>

Option 2: Separate Endpoints (Recommended)

Create individual endpoints for different purposes:

  • "Contact Form" endpoint - for general inquiries
  • "Newsletter Signup" endpoint - for email collection
  • "Support Request" endpoint - for customer support

This approach provides better organization, separate spam protection settings, and dedicated integrations for each form type.

Website Integration

Integrating Formserve with your website is simple. You have two options: use plain HTML forms or enhance them with our JavaScript library for AJAX submissions.

Option 1: Plain HTML Form (Simplest)

A basic HTML form that redirects to a thank you page after submission:

<form action="https://formserve.io/f/YOUR_ACCESS_KEY" method="POST">
  <label for="name">Name</label>
  <input type="text" name="name" id="name" required>

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

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

  <button type="submit">Send Message</button>
</form>

πŸ’‘ Important: Replace YOUR_ACCESS_KEY with the actual access key from your endpoint's Setup tab. Only fields with a name attribute will be saved.

Option 2: AJAX Form with Formserve.js (Enhanced)

For a better user experience with no page reload, use our JavaScript library:

Step 1: Include the Script

Add this script before the closing </body> tag:

<script src="https://formserve.io/v1/formserve.js?v=1.3"></script>

Step 2: Add the Class

Add class="formserve" to your form:

<form action="https://formserve.io/f/YOUR_ACCESS_KEY"
      class="formserve"
      method="POST">

  <label for="name">Name</label>
  <input type="text" name="name" id="name" required>

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

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

  <button type="submit" class="formserve-form__submit">
    <span>Send Message</span>
  </button>
</form>

The form will now submit asynchronously (no page reload) and show a success message to the user.

✨ Features with Formserve.js: Automatic AJAX submission, loading spinner support, success/error messages, and custom validation hooks. See the Formserve.js Integration Guide for advanced usage.

Formserve.js Integration Guide

Formserve.js is a lightweight JavaScript library that makes it easy to integrate form submissions with Formserve. It handles AJAX submissions, loading states, success/error messages, and provides hooks for custom behavior.

What is Formserve.js?

Formserve.js is a client-side library that:

  • Automatically handles form submissions via AJAX (no page reloads)
  • Provides built-in loading spinner support
  • Shows success messages after submission
  • Handles errors gracefully
  • Offers callback hooks for custom validation and response handling
  • Works with any HTML form (vanilla HTML, React, Vue, etc.)

Step 1: Installation

Add the Formserve.js script tag before the closing </body> tag in your HTML:

<script src="https://formserve.io/v1/formserve.js?v=1.3" charset="utf-8"></script>

Note: The script is loaded from Formserve's CDN and is always up-to-date. No npm installation or build step required!

Step 2: Create Your Form

Once the script is loaded, any form with the class formserve will be automatically handled by Formserve.js:

<form action="https://formserve.io/f/YOUR_ENDPOINT_KEY"
      class="formserve"
      method="POST">

  <label for="name">Name</label>
  <input type="text" name="name" id="name" required>

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

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

  <button type="submit" class="formserve-form__submit">
    <span>Submit</span>
  </button>
</form>

That's it! The form will now submit asynchronously and show a success message when complete.

Key Components

  • action="https://formserve.io/f/YOUR_ENDPOINT_KEY" - Your unique endpoint URL from the dashboard
  • class="formserve" - Tells Formserve.js to handle this form
  • method="POST" - Required for form submission
  • name attributes - Only fields with a name will be saved

Loading Spinner (Optional)

Formserve.js can automatically show a loading spinner on your submit button during form submission. To enable this:

  1. Add the class formserve-form__submit to your submit button
  2. Wrap your button text in a <span> tag
<button type="submit" class="formserve-form__submit">
  <span>Submit</span>
</button>

Styling the Spinner

The spinner is white by default. To change the color, add CSS:

/* Custom spinner color */
.formserve-form__submit::after {
  border-color: rgba(0, 123, 255, 0.3);
  border-left-color: #007bff;
}

/* Or use the built-in dark loader */
<button class="formserve-form__submit formserve-form__submit--dark-loader">
  <span>Submit</span>
</button>

Advanced Usage

Manual Initialization with Options

For more control, you can manually initialize forms with custom options:

const form = document.querySelector('#myForm');

Formserve.form(form, {
  // Called before submission - return false to prevent submission
  onSubmit: function(event) {
    console.log('Form is about to submit');

    // Custom validation
    const email = form.querySelector('[name="email"]').value;
    if (!email.includes('@')) {
      alert('Please enter a valid email');
      return false; // Prevents submission
    }

    return true; // Allow submission
  },

  // Called when response is received
  onResponse: function(error, response) {
    if (error) {
      console.error('Submission failed:', error);
      alert('Error: ' + error.message);
      return false; // Prevents default success message
    }

    console.log('Submission successful:', response);

    // Custom success handling
    if (response.redirect_url) {
      window.location.href = response.redirect_url;
    } else {
      alert('Thank you for your submission!');
    }

    return false; // Prevents default success message
  },

  // Custom success message template (HTML)
  successTemplate: '<div class="success-message">Thank you! We\'ll be in touch soon.</div>'
});

Sending Data Without a Form

You can send data programmatically using Formserve.send():

// Prepare your data
const data = {
  name: 'John Smith',
  email: 'john@example.com',
  message: 'Hello from JavaScript!'
};

// Send to Formserve
Formserve.send(
  'YOUR_ENDPOINT_KEY',  // Your endpoint key
  data,                  // Data object
  function(error, response) {
    if (error) {
      console.error('Submission failed:', error.message);
    } else {
      console.log('Submission successful:', response);
    }
  }
);

Complete Examples

Example 1: Contact Form with Custom Validation

<!DOCTYPE html>
<html>
<head>
  <style>
    .form-group { margin-bottom: 1rem; }
    label { display: block; margin-bottom: 0.5rem; }
    input, textarea { width: 100%; padding: 0.5rem; }
    .error { color: red; font-size: 0.875rem; }
    .success-message {
      padding: 1rem;
      background: #d4edda;
      color: #155724;
      border-radius: 4px;
      margin-bottom: 1rem;
    }
  </style>
</head>
<body>
  <form id="contactForm"
        action="https://formserve.io/f/YOUR_ENDPOINT_KEY"
        class="formserve"
        method="POST">

    <div class="form-group">
      <label for="name">Name *</label>
      <input type="text" name="name" id="name" required>
      <span class="error" id="name-error"></span>
    </div>

    <div class="form-group">
      <label for="email">Email *</label>
      <input type="email" name="email" id="email" required>
      <span class="error" id="email-error"></span>
    </div>

    <div class="form-group">
      <label for="phone">Phone</label>
      <input type="tel" name="phone" id="phone">
    </div>

    <div class="form-group">
      <label for="message">Message *</label>
      <textarea name="message" id="message" rows="5" required></textarea>
    </div>

    <button type="submit" class="formserve-form__submit">
      <span>Send Message</span>
    </button>
  </form>

  <script src="https://formserve.io/v1/formserve.js?v=1.3"></script>
  <script>
    const form = document.getElementById('contactForm');

    Formserve.form(form, {
      onSubmit: function(event) {
        // Clear previous errors
        document.querySelectorAll('.error').forEach(el => el.textContent = '');

        // Custom validation
        const name = form.querySelector('[name="name"]').value.trim();
        const message = form.querySelector('[name="message"]').value.trim();

        if (name.length < 2) {
          document.getElementById('name-error').textContent = 'Name must be at least 2 characters';
          return false;
        }

        if (message.length < 10) {
          document.getElementById('message-error').textContent = 'Message must be at least 10 characters';
          return false;
        }

        return true;
      },

      onResponse: function(error, response) {
        if (error) {
          alert('Failed to send message: ' + error.message);
          return false;
        }

        // Show success message and reset form
        form.reset();
        return true; // Shows default success message
      },

      successTemplate: '<div class="success-message">βœ“ Thank you! We\'ve received your message and will respond soon.</div>'
    });
  </script>
</body>
</html>

Example 2: Newsletter Signup with Analytics

<form id="newsletter"
      action="https://formserve.io/f/YOUR_ENDPOINT_KEY"
      class="formserve"
      method="POST">

  <input type="email"
         name="email"
         placeholder="Enter your email"
         required>

  <button type="submit" class="formserve-form__submit">
    <span>Subscribe</span>
  </button>
</form>

<script>
  const newsletterForm = document.getElementById('newsletter');

  Formserve.form(newsletterForm, {
    onSubmit: function(event) {
      // Track submission attempt
      if (typeof gtag !== 'undefined') {
        gtag('event', 'newsletter_submit_attempt');
      }
      return true;
    },

    onResponse: function(error, response) {
      if (error) {
        // Track error
        if (typeof gtag !== 'undefined') {
          gtag('event', 'newsletter_submit_failed', {
            error_message: error.message
          });
        }
        return false;
      }

      // Track success
      if (typeof gtag !== 'undefined') {
        gtag('event', 'newsletter_submit_success');
      }

      // Clear the form
      newsletterForm.reset();

      return true; // Show success message
    },

    successTemplate: '<p style="color: green;">βœ“ You\'re subscribed! Check your email for confirmation.</p>'
  });
</script>

Example 3: Multi-Step Form

<div id="multiStepForm">
  <!-- Step 1 -->
  <div class="step" data-step="1">
    <h2>Step 1: Personal Information</h2>
    <input type="text" id="step1-name" placeholder="Name" required>
    <input type="email" id="step1-email" placeholder="Email" required>
    <button onclick="nextStep(2)">Next</button>
  </div>

  <!-- Step 2 -->
  <div class="step" data-step="2" style="display:none;">
    <h2>Step 2: Company Details</h2>
    <input type="text" id="step2-company" placeholder="Company Name">
    <input type="text" id="step2-role" placeholder="Your Role">
    <button onclick="prevStep(1)">Back</button>
    <button onclick="nextStep(3)">Next</button>
  </div>

  <!-- Step 3 -->
  <div class="step" data-step="3" style="display:none;">
    <h2>Step 3: Message</h2>
    <textarea id="step3-message" placeholder="Your message" rows="5"></textarea>
    <button onclick="prevStep(2)">Back</button>
    <button onclick="submitMultiStepForm()">Submit</button>
  </div>
</div>

<script src="https://formserve.io/v1/formserve.js?v=1.3"></script>
<script>
  function nextStep(step) {
    document.querySelectorAll('.step').forEach(el => el.style.display = 'none');
    document.querySelector(`.step[data-step="${step}"]`).style.display = 'block';
  }

  function prevStep(step) {
    nextStep(step);
  }

  function submitMultiStepForm() {
    // Collect data from all steps
    const data = {
      name: document.getElementById('step1-name').value,
      email: document.getElementById('step1-email').value,
      company: document.getElementById('step2-company').value,
      role: document.getElementById('step2-role').value,
      message: document.getElementById('step3-message').value
    };

    // Submit using Formserve.send
    Formserve.send(
      'YOUR_ENDPOINT_KEY',
      data,
      function(error, response) {
        if (error) {
          alert('Submission failed: ' + error.message);
        } else {
          alert('Thank you! Your submission has been received.');
          // Reset and go back to step 1
          document.querySelectorAll('input, textarea').forEach(el => el.value = '');
          nextStep(1);
        }
      }
    );
  }
</script>

API Reference

Formserve.form(formElement, options)

Wraps a form element and handles submission automatically.

Parameters:

  • formElement (HTMLFormElement) - The form element to wrap
  • options (Object, optional) - Configuration options:
    • onSubmit(event) - Called before submission. Return false to prevent submission.
    • onResponse(error, response) - Called after receiving response. Return false to prevent default success message.
    • successTemplate - HTML string for custom success message

Formserve.send(endpointKey, data, callback)

Sends data directly to a Formserve endpoint without a form.

Parameters:

  • endpointKey (String) - Your endpoint key from the dashboard
  • data (Object) - The data to send (will be JSON stringified)
  • callback(error, response) - Function called after submission completes
    • error - Error object if submission failed, null otherwise
    • response - Response object from Formserve

Best Practices

βœ“ DO: Use HTML5 validation

Add required, type="email", etc. for instant client-side validation

βœ“ DO: Include name attributes

Only form fields with a name attribute will be submitted to Formserve

βœ“ DO: Handle errors gracefully

Use the onResponse callback to show user-friendly error messages

βœ— DON'T: Submit sensitive data without HTTPS

Always use HTTPS in production to protect user data

βœ— DON'T: Forget accessibility

Include proper labels and ARIA attributes for screen readers

Troubleshooting

Form not submitting?

  • Check that the action URL is correct
  • Verify the form has class="formserve"
  • Ensure formserve.js is loaded (check browser console)
  • Check browser console for JavaScript errors

Loading spinner not showing?

  • Button must have class formserve-form__submit
  • Button text must be wrapped in a <span>
  • Cannot use <input type="submit"> - use <button>

Custom validation not working?

  • Make sure onSubmit returns false to prevent submission
  • Initialize the form manually with Formserve.form()
  • Don't add both class="formserve" AND manual initialization

Next Steps

Data Handling

What data is saved?

Any form <input>, <textarea>, or <select> element with a name attribute is saved into Formserve. Some notes:

  • Naming inputs with square brackets (e.g. someName[aChildKey]) will save the input under a child object. This is useful for groups of things like checkboxes. e.g. {someName: {aChildKey: true}}
  • Checkboxes (<input type="checkbox">) are stored as booleans. When unchecked, the browser does not send the input in the request, so a checkbox value will either be true, or the key will not exist at all.
  • File inputs (<input type="file">) are ignored, and multipart requests will be rejected.

An example form:

                            
<form action="https://formserve.io/f/{yourEndpointID}" 
    class="formserve" data-formserve-endpoint="{yourEndpointID}"    
    method="post">
    <!-- Add your inputs as you normally would -->
    <label name="name" for="name">Name</label>
    <input type="text" name="name" placeholder="Your name">
    <label name="email" for="email">Email</label>
    <input type="email" name="email" placeholder="Your email">
    <label name="message" for="message">Message</label>
    <input type="textarea" name="message" placeholder="Your message">    
    <button class="formserve__submit" type="submit">
        <span>Submit</span>
    </button>
</form>
                            
                        

Will save the following payload:

                            
{
    email: 'user@example.com',
    heardFrom: 'ph',
    animal: 'tarantula',
    likes: {
        pizza: true
    },
    version: 'v1'
}
                            
                        

Special fields

Formserve can send you an email for each form submission and there are two specially named fields that make those emails easier to use:

  • email - the user's email. This will be used in the reply-to field of the email that Formserve sends you. So all you have to do is hit 'Reply' in your email client to respond to the user.
  • subject - This will set the subject of the email that Formserve sends you for each submission.

These fields are useful when you setup contact forms. An example contact form:

                            
<form action="https://formserve.io/f/{yourEndpointID}" 
    class="formserve" data-formserve-endpoint="{yourEndpointID}"    
    method="post">
    <!-- This will be used in the email's reply-to field. Must have name="email" -->
    <input type="email" name="email" value="user@example.com"/>
    <!-- This will be used in the email's subject. Must have name="subject" -->
    <input type="text" name="subject" value="Email subject"/>
    <textarea name="body">Email body</textarea>
    <button class="formserve__submit" type="button">
    <span>Submit</span>
    </button>
</form>
                            
                        

Bare minimum integration

You do not need to use the default asynchronous submission behavior. The absolute minimum you need to do is have your form POST to your project URL:

                            
<form action="https://formserve.io/f/{yourEndpointID}" 
    class="formserve" data-formserve-endpoint="{yourEndpointID}"    
    method="post">
    <input type="text" name="name" value="John Smith"/>
    <input type="text" name="email" value="john@example.com"/>
    <input type="submit" value="Send">
</form>
                            
                        

With this form, Formserve will save the data, then redirect back to the originating page.

Form Validation

Formserve works with any form validation library or scheme. If you have a favorite, just use that!

We recommend using HTML5 validation that is built into the browser. HTML5 validation is very rich these days, and has good browser support.

A basic example enforcing required attributes:

                            
<!-- Note the `required` attributes in inputs! -->
<form action="https://formserve.io/f/{yourEndpointID}" 
    class="formserve" data-formserve-endpoint="{yourEndpointID}"    
    method="post">
    <input type="text" name="name" required />
    <input type="text" name="email" required />
    <input type="submit" value="Send">
</form>
                            
                        

Other HTML5 Form Validation Resources

Advanced Integration

Using the loading spinner

Formserve can overlay a loading spinner on your submit button with some special markup. You must have a <button> element with the .formserve__submit and a <span> child.

                            
<form>...
    <button class="button formserve__submit" type="submit">
        <span>Submit</span>
    </button>
</form>
                            
                        

Styling the spinner

By default the spinner is white. You can change it to black by adding the formserve__submit--dark-loader class to the button.

You can specify a custom color by styling the border:

                            
.formserve__submit::after {
    border-color: rgba(0, 255, 0, 0.8);
    border-reft-color: blue;
}
                            
                        

Loading spinner details

When a form is submitted, the <button> will go through a few CSS class states. These classes provide CSS animations.

  • .formserve__submit--start-loading: fades the <span> text out, and pops the loader into view
  • .formserve__submit--loading: spins the loader
  • .formserve__submit--end-loading: hides the loader, and fades the <span> text back in.

Some notes:

  • If the inner <span> is not specified, it will just overlay the spinner on the text.
  • If an <input type="submit" /> is used, the loading spinner will not work. A button must be used as the loading spinner is rendered in the ::after pseudo element.
  • The start and animations can be removed from the button. If animations do not exist, the JS will detect it and only add the .formserve__submit--loading class to the button.

Formserve.js

When https://formserve.io/v1/formserve.js?v=1.3 is included on the page, a window.Formserve object is created. With it, you can hook into form submission, or send data to Formserve without a form at all.

Formserve.form(form[, options])

Formserve.form(...) wraps a form, submits the data to Formserve asynchronously, and gives you a couple hooks into the lifecycle. You can use these for things like validation or displaying messages to the user. By default, any forms with class formserve will be automatically wrapped with Formserve.form(...).

  • form:HTMLFormElement - the <form /> element to submit to Formserve. It must have an action pointing to your Formserve project.
  • options:Object - (optional)
    • onSubmit:Function - returning false from this will prevent submission to Formserve
    • onResponse:Function - returning false from this will prevent showing the successTemplate to the user
    • successTemplate:String
                            
var form = document.querySelector('.formserve')
    Formserve.form(form, {
    onSubmit: function (event) { },
    onResponse: function (error, response) { },
    successTemplate: '<span>Thank you!</span>'
})
                            
                        

Formserve.send(EndpointID, formName, data, callback)

Formserve.send(...) allows you to send arbitrary JSON data via XHR to a Formserve form.

  • EndpointID:String - Your public EndpointID; a unique token give to each project.
  • formName:String - The name of the form to save to. If you wish to send to a default form, formName must be 'default'.
  • data:Object - The actual data to save. JSON.stringify() will be called on this object before submission.
  • callback:Function - Called when submission is finished
    • error:Error - null when the request succeeds; Object with .message on failure.
    • response:Object - {"data":"ok"}
                            
var data = {
    name: 'John Smith',
    email: 'john@example.com'
}
Formserve.send('...yourEndpointID...', 'contact', data, function (error, response) {
    console.log('saved?', !!error, '; response:', error || response)
})
                            
                        

Third-Party Integrations

Auto-responder Emails

Send automatic confirmation emails to form submitters. This is perfect for letting users know you've received their submission and will respond soon.

Setting up Auto-responder

To enable auto-responder emails:

  1. Go to your endpoint's settings page
  2. Scroll to the "Notification Settings" section
  3. Enable "Auto-responder Email"
  4. Configure the email subject and body
  5. Optionally set a custom from name and reply-to address

Template Variables

You can use template variables in both the subject and body of your auto-responder emails. Variables are wrapped in double curly braces and will be replaced with actual values from the form submission.

Built-in variables:

  • {{name}} - The submitter's name
  • {{email}} - The submitter's email address
  • {{endpoint_name}} - The name of your form endpoint
  • {{date}} - Submission date (e.g., "January 15, 2025")
  • {{time}} - Submission time (e.g., "02:30 PM")

Custom form fields: You can also use any field name from your form as a variable.

Example Auto-responder

Subject:

Thank you for contacting us, {{name}}!

Body:

Hi {{name}},

Thank you for reaching out to us through our {{endpoint_name}} form.

We received your message on {{date}} at {{time}}, and our team will review it shortly. We typically respond within 24-48 hours.

If you have any urgent questions, please don't hesitate to reply to this email.

Best regards,
The Support Team

Requirements

  • Your form must collect an email address in a field named email, email_address, or user_email
  • The email address must be valid
  • Both subject and body must be configured

Webhook

You can set up Formserve to call a URL on your own server for each form submission. Formserve will make an HTTP POST request to the URL of your choice with JSON data about the new item. To be clear, a webhook will be called each time a user submits a form.

Go to the Integrations tab on your project's Formserve UI, and click Set Webhook

Webhook Token

In each POST request Formserve makes to your server, it will include a token in the request body. On your server, you can use this token to verify that the request is from Formserve.

You can copy this token in the Formserve UI once you have set your URL. We advise you keep this token in an environment variable on your server.

                            
{
    "action": "newItem",
    "isTest": true,
    "token": "99c59ojxCCFfwwsLtyZUppcHbIyGrfXd",
    ...,
}
                            
                        

On your server, you might do something like this:


server.handlePost('/formserve-webhook', (bodyJSON) => {
    if (bodyJSON.token === process.env.FORMBRIDGE_TOKEN) {
    // Do successful things
    } else {
        // Fail; probably sketchy!
    }
})
                            
                        

Webhook Payload

Each webhook request will contain data about the organization, project, form, and of course, the new item. Some notes:

  • item.payload is the actual data the user submitted.
  • isTest will be true if the request is from clicking the Test Webhook button in the UI
                            
{
    "action": "newItem",
    "isTest": true,
    "token": "99c59ojxCCFfwwsLtyZUppcHbIyGrfXd",
    "organization": {
    "organizationEid": "JyAmtMGNVAjWPg8RnyG5vJkSk4f9Ntf7",
    "name": "Test Org",
    "isPersonal": false,
    "billingEmail": "john@example.com"
    },
    "project": {
        "projectEid": "YD2jPJKGY1CedwKfvM5NcDCHm5bQMpZQ",
        "name": "Test Project",
        "slug": "test-project",
        "domains": "localhost,example.com"
    },
    "form": {
        "bucketEid": "HutBkLTizLfF7YFtOftpEWFjMCLxhR3j",
        "name": "contact-form",
        "displayName": "Contact Form"
    },
    "item": {
        "itemEid": "Wt3tiXgvsimZ7sUjnivxZG2AJtvHQjGi",
        "payload": {
            "name": "John Smith",
            "email": "john@example.com"
        }
    }
}
                            
                        

Mailchimp Integration

Automatically sync your form submissions to your Mailchimp audience lists. Perfect for building email newsletters, managing leads, and growing your subscriber base.

Overview

The Mailchimp integration allows you to:

  • Automatically add form submitters to your Mailchimp lists
  • Map form fields to Mailchimp merge fields
  • Sync submissions in real-time via background jobs
  • Track sync status and errors
  • Enable/disable syncing per endpoint

Important: Email Field Required

Mailchimp requires an email address to add subscribers to lists. Your form must collect an email field for syncing to work.

If your form doesn't collect emails (e.g., contact forms that only collect names and messages), submissions will be saved to Formserve but will NOT sync to Mailchimp.

Setup Guide

Step 1: Connect Your Mailchimp Account

Formserve offers two ways to connect your Mailchimp account:

✨ Recommended: OAuth 2.0 (One-Click)

  1. In Formserve, go to Mailchimp in the sidebar
  2. Click the yellow "Connect with Mailchimp" button
  3. Log in to your Mailchimp account (if not already)
  4. Click "Allow" to authorize Formserve
  5. You'll be redirected back and connected automatically!

Benefits: More secure, easier setup, automatic token refresh, can be revoked anytime from Mailchimp.

Alternative: API Key (Advanced)

If you prefer to use an API key instead:

  1. In Formserve, go to Mailchimp in the sidebar
  2. Click "Use API Key (Advanced)"
  3. Log in to your Mailchimp account
  4. Go to Account β†’ Extras β†’ API keys
  5. Click "Create A Key" and copy it
  6. Note the server prefix (the part after the last dash, e.g., "us19")
  7. Paste the API key and server prefix into Formserve
  8. Click "Connect Account"

Step 2: Map Endpoints to Lists

  1. Go to any of your endpoints
  2. Click "Mailchimp Sync" button
  3. Click "Add List Mapping"
  4. Select which Mailchimp list to sync to
  5. Map your form fields to Mailchimp merge fields (optional)
  6. Enable syncing and save

Field Mapping

Formserve automatically detects the email field in your form submissions. You can optionally map additional fields:

Form Field Mailchimp Merge Field Description
email EMAIL Required - subscriber's email address
name or first_name FNAME First name
last_name LNAME Last name
phone PHONE Phone number
company COMPANY Company name

You can find your list's available merge fields in Mailchimp under Audience β†’ Settings β†’ Audience fields and *|MERGE|* tags.

Example Form

Here's an example HTML form that works perfectly with Mailchimp integration:

<form action="https://formserve.io/f/YOUR_ENDPOINT_KEY" method="POST">
  <!-- Email is required for Mailchimp -->
  <input type="email" name="email" placeholder="Your email" required>

  <!-- Optional fields that can be mapped to Mailchimp -->
  <input type="text" name="name" placeholder="First name">
  <input type="text" name="company" placeholder="Company name">

  <button type="submit">Subscribe</button>
</form>

How It Works

  1. Form Submission: When someone submits your form, Formserve saves the submission
  2. Background Sync: A background job automatically syncs the data to Mailchimp
  3. Subscriber Added: The email is added/updated in your Mailchimp list with status "subscribed"
  4. Merge Fields: Any mapped fields are added to the subscriber's profile
  5. Status Tracking: Sync status and errors are tracked in your Formserve dashboard

Managing Your Integration

View Sync Status

For each endpoint, you can view:

  • Total successful syncs
  • Error count
  • Last sync time
  • Last error message (if any)

Enable/Disable Syncing

You can temporarily disable syncing:

  • Global: Disable all syncing in Mailchimp settings
  • Per Endpoint: Toggle syncing for individual endpoint-list mappings

Disconnect Account

To disconnect your Mailchimp account:

  1. Go to Mailchimp in the sidebar
  2. Click "Disconnect"
  3. Confirm the action

Note: Disconnecting will disable all endpoint mappings but won't delete existing subscribers in Mailchimp.

Troubleshooting

Common Issues

Connection Failed

Check that your API key and server prefix are correct. The server prefix should match the end of your API key.

Email Not Found in Submission / Nothing Syncing

Make sure your form has an email field named "email", "Email", or "email_address". If your form doesn't collect emails, submissions will be saved to Formserve but cannot sync to Mailchimp (Mailchimp requires an email address for all subscribers). You can also map custom field names in the field mapping settings.

Subscribers Not Appearing

Check that syncing is enabled for both the integration and the specific endpoint mapping. Also check the error log for any sync failures.

Invalid Email Error

Mailchimp validates email addresses. Make sure your form includes proper email validation to prevent invalid submissions.

Best Practices

  • Email Validation: Always use type="email" on your email input fields
  • Required Fields: Make the email field required to ensure all submissions can be synced
  • Field Naming: Use standard field names (email, name, company) for automatic detection
  • Monitor Errors: Regularly check sync status and address any errors
  • Test First: Create a test list in Mailchimp to test your integration
  • GDPR Compliance: Ensure you have consent to add people to your mailing list

Frequently Asked Questions

Q: Can I sync one form to multiple Mailchimp lists?

A: Yes! You can create multiple list mappings for the same endpoint.

Q: What happens if someone is already subscribed?

A: Mailchimp will update the subscriber's information with the new data.

Q: Are there any limits on syncing?

A: Formserve doesn't limit syncing, but Mailchimp has their own API rate limits. Normal usage won't hit these limits.

Q: Is the sync instant?

A: Syncing happens via background jobs, typically within a few seconds of form submission.

Q: Can I map custom merge fields?

A: Yes! You can map any form field to any Mailchimp merge field when creating or editing a list mapping.

Q: What if my form doesn't collect email addresses?

A: Mailchimp requires an email address to add subscribers. If your form doesn't collect emails (e.g., feedback forms, contact forms without email), submissions will be saved to Formserve but will NOT sync to Mailchimp. You'll need to add an email field to your form for syncing to work.

Q: Will I be charged/lose submissions if they don't have emails?

A: No! Submissions are always saved to Formserve regardless of Mailchimp syncing. The Mailchimp integration simply skips submissions that don't have an email field. Your form data is safe and accessible in your Formserve dashboard.

Q: Should I use OAuth or API Key to connect?

A: We recommend OAuth (the yellow "Connect with Mailchimp" button) because it's more secure, easier to set up, and tokens refresh automatically. Use the API key method only if you need it for advanced use cases or automation.

Q: Can I switch from API Key to OAuth (or vice versa)?

A: Yes! Simply disconnect your current connection and reconnect using your preferred method. Your list mappings will be preserved.

Q: What happens when my OAuth token expires?

A: OAuth tokens are automatically refreshed by Formserve. You don't need to do anything - your integration will continue working seamlessly.

Need Help?

If you have questions about the Mailchimp integration, please contact us at support@formserve.io

RESTFul API

Overview

The Formserve API provides programmatic access to:

  1. Submit form data to your form endpoints
  2. Retrieve form submissions for your endpoints

This simplified API focuses on these core functionalities to enable integration with static websites and other applications.

Authentication

All requests to retrieve submissions require authentication using an API key.

API Keys

API keys can be created and managed in the Formserve dashboard. Each API key is associated with a specific user account and inherits the permissions of that user.

Authentication Methods

Include your API key in one of the following ways:

HTTP Header (recommended):
            
X-API-Key: your_api_key_here
            
        

OR

Query Parameter:
            
https://formserve.example.com/api/v1/endpoints/abc123/submissions?api_key=your_api_key_here
            
        

Example Request with Authentication

        
curl -X GET \ 
  "https://formserve.example.com/api/v1/endpoints/{yourEndpointID}/submissions" \
  -H "X-API-Key: your_api_key_here"
        
    

Response Format

All API responses are in JSON format. Successful responses include the requested data or a confirmation message. Error responses include an error message and appropriate HTTP status code.

Common HTTP Status Codes

  • 200 OK - Success
  • 201 Created - Form submission created successfully
  • 400 Bad Request - Invalid parameters
  • 401 Unauthorized - Missing or invalid API key
  • 403 Forbidden - API key valid but not authorized for this action
  • 404 Not Found - Endpoint not found
  • 422 Unprocessable Entity - Validation errors
  • 429 Too Many Requests - Rate limit exceeded
  • 500 Internal Server Error - Server error

Rate Limiting

API requests are limited to 100 requests per minute per API key. If you exceed this limit, you'll receive a
429 Too Many Requests response.

API Endpoints

1. Submit Form

Submits data to a form endpoint. This endpoint does not require authentication.

1.1 Request

        
POST /api/v1/f/:yourEndpointID
        
    

1.2 Parameters

Any form fields can be included in the request body. Special fields:

Name Description
_gotcha Honeypot field. Should be left empty
_redirect Custom redirect URL (overrides endpoint setting)
_referrer Custom referrer (if not automatically detected)

1.3 Example Request

        
{
    "name": "John Doe",
    "email": "john@example.com",
    "message": "Hello, I'm interested in your services.",
    "_gotcha": ""
}
        
    

1.4 Response

For AJAX/XHR requests:

        
{
    "success": true,
    "message": "Form submitted successfully"
}
        
    

For regular form submissions:

  • Redirects to the redirect_url if specified
  • Otherwise, returns a success message

1.5 Error Response

        
{
    "success": false,
    "errors":  ["Email is required"]
}
        
    

2. List Submissions

Retrieves a paginated list of submissions for a specific endpoint.

2.1 Request

        
 GET /api/v1/endpoints/:endpoint_key/submissions
        
    

2.2 Query Parameters

Name Type Description
page integer Page number (default: 1)
per_page integer Items per page (default: 20, max: 100)
filter string Filter submissions by: "spam", "not_spam"
unread boolean Filter by read status (true/false)

2.3 Response

        
{
  "submissions": [
    {
      "id": 1,
      "endpoint_id": 1,
      "data": {
        "name": "John Doe",
        "email": "john@example.com",
        "message": "Hello, I'm interested in your services."
      },
      "created_at": "2025-05-10T16:30:00Z",
      "ip_address": "192.168.1.1",
      "user_agent": "Mozilla/5.0...",
      "referrer": "https://example.com/contact",
      "spam": false,
      "read": true
    },
    {
      "id": 2,
      "endpoint_id": 1,
      "data": {
        "name": "Jane Smith",
        "email": "jane@example.com",
        "message": "Please send me more information."
      },
      "created_at": "2025-05-10T15:45:00Z",
      "ip_address": "192.168.1.2",
      "user_agent": "Mozilla/5.0...",
      "referrer": "https://example.com/products",
      "spam": false,
      "read": false
    }
  ],
  "meta": {
    "total_count": 42,
    "total_pages": 3,
    "current_page": 1
  }
}
        
    

3. Get Submission

Retrieves details for a specific submission.

3.1 Request

        
    GET /api/v1/endpoints/:endpoint_key/submissions/:id
        
    

3.2 Response

        
{
  "id": 1,
  "endpoint_id": 1,
  "data": {
    "name": "John Doe",
    "email": "john@example.com",
    "message": "Hello, I'm interested in your services."
  },
  "created_at": "2025-05-10T16:30:00Z",
  "ip_address": "192.168.1.1",
  "user_agent": "Mozilla/5.0...",
  "referrer": "https://example.com/contact",
  "spam": false,
  "read": true
}
        
    

Error Codes and Troubleshooting

Common Error Codes

Code Description Solution
invalid_api_key API key is invalid or missing Check your API key and ensure it's included in the request
endpoint_not_found Endpoint does not exist Verify the endpoint_key is correct
quota_exceeded You've reached your plan's submission limit Upgrade your plan or wait for the next billing cycle
rate_limited Too many API requests Reduce request frequency and implement exponential backoff
invalid_origin Request origin not allowed Add the domain to the endpoint's allowed_domains
spam_blocked Submission blocked due to spam detection Review and adjust spam protection settings

Support

If you encounter issues not covered in this documentation, please contact Formserve support at support@formserve.io.