Skip to content

Forminit + Neocities Integration Guide

Neocities is a free static website hosting service that lets you create HTML, CSS, and JavaScript websites. Since Neocities doesn’t support server-side code (like PHP or Node.js), you need a form backend service to handle form submissions.

Forminit handles everything for you:

  • Receives and stores submissions — No database setup required
  • Email notifications — Get notified when someone submits your form
  • Spam protection — Built-in rate limiting and optional CAPTCHA support
  • File uploads — Accept files up to 25 MB
  • Validation — Automatic email, phone, and URL validation

Requirements:

  • A Neocities account with a website
  • A Forminit account and Form ID

  1. Sign up or log in at forminit.com
  2. Create a new form from your dashboard
  3. Copy your Form ID (looks like frm_abc123xyz)
  4. Important: Set authentication mode to “Public” in Form Settings

Create or edit your HTML file on Neocities:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Contact Me</title>
  <style>
    * {
      box-sizing: border-box;
    }
    
    body {
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
      max-width: 500px;
      margin: 40px auto;
      padding: 20px;
      background: #f5f5f5;
    }
    
    h1 {
      margin-bottom: 24px;
    }
    
    form {
      background: white;
      padding: 24px;
      border-radius: 8px;
      box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    }
    
    label {
      display: block;
      margin-bottom: 4px;
      font-weight: 500;
    }
    
    input, textarea {
      width: 100%;
      padding: 10px;
      margin-bottom: 16px;
      border: 1px solid #ddd;
      border-radius: 4px;
      font-size: 16px;
    }
    
    textarea {
      min-height: 120px;
      resize: vertical;
    }
    
    button {
      background: #4f46e5;
      color: white;
      padding: 12px 24px;
      border: none;
      border-radius: 4px;
      font-size: 16px;
      cursor: pointer;
      width: 100%;
    }
    
    button:hover {
      background: #4338ca;
    }
    
    button:disabled {
      background: #9ca3af;
      cursor: not-allowed;
    }
    
    #form-status {
      margin-top: 16px;
      padding: 12px;
      border-radius: 4px;
      display: none;
    }
    
    #form-status.success {
      display: block;
      background: #d1fae5;
      color: #065f46;
    }
    
    #form-status.error {
      display: block;
      background: #fee2e2;
      color: #991b1b;
    }
  </style>
</head>
<body>
  <h1>Contact Me</h1>
  
  <form id="contact-form">
    <label for="firstName">First Name</label>
    <input type="text" id="firstName" name="fi-sender-firstName" required>
    
    <label for="lastName">Last Name</label>
    <input type="text" id="lastName" name="fi-sender-lastName" required>
    
    <label for="email">Email</label>
    <input type="email" id="email" name="fi-sender-email" required>
    
    <label for="message">Message</label>
    <textarea id="message" name="fi-text-message" required></textarea>
    
    <button type="submit" id="submit-btn">Send Message</button>
  </form>
  
  <div id="form-status"></div>

  <!-- Forminit SDK -->
  <script src="https://forminit.com/sdk/v1/forminit.js"></script>
  
  <script>
    // Initialize Forminit
    const forminit = new Forminit();
    
    // Replace with your Form ID from Forminit dashboard
    const FORM_ID = 'YOUR_FORM_ID';
    
    const form = document.getElementById('contact-form');
    const submitBtn = document.getElementById('submit-btn');
    const statusDiv = document.getElementById('form-status');
    
    form.addEventListener('submit', async function(event) {
      event.preventDefault();
      
      // Disable button while submitting
      submitBtn.disabled = true;
      submitBtn.textContent = 'Sending...';
      statusDiv.className = '';
      statusDiv.style.display = 'none';
      
      // Create FormData from the form
      const formData = new FormData(form);
      
      // Submit to Forminit
      const { data, error } = await forminit.submit(FORM_ID, formData);
      
      if (error) {
        // Show error message
        statusDiv.textContent = error.message || 'Something went wrong. Please try again.';
        statusDiv.className = 'error';
        submitBtn.disabled = false;
        submitBtn.textContent = 'Send Message';
        return;
      }
      
      // Success!
      statusDiv.textContent = 'Thank you! Your message has been sent.';
      statusDiv.className = 'success';
      form.reset();
      submitBtn.disabled = false;
      submitBtn.textContent = 'Send Message';
    });
  </script>
</body>
</html>

Find this line in the code:

const FORM_ID = 'YOUR_FORM_ID';

Replace YOUR_FORM_ID with your actual Form ID from Forminit (e.g., frm_abc123xyz).

  1. Log in to your Neocities dashboard
  2. Upload the HTML file (or edit an existing page)
  3. Visit your page and test the form

Forminit uses a special naming convention for form fields. All field names must start with fi- followed by the block type and field name.

Use these for collecting information about the person filling out the form:

FieldName AttributeDescription
Emailfi-sender-emailSubmitter’s email address
First Namefi-sender-firstNameFirst name
Last Namefi-sender-lastNameLast name
Full Namefi-sender-fullNameFull name (use instead of first/last)
Phonefi-sender-phonePhone number (E.164 format)
Companyfi-sender-companyCompany name
Positionfi-sender-positionJob title

At least one sender field is required (email, name, or phone).

For additional data, use the appropriate block type:

TypePatternExampleUse For
Textfi-text-{name}fi-text-messageMessages, comments
Numberfi-number-{name}fi-number-quantityQuantities, amounts
Emailfi-email-{name}fi-email-referralAdditional emails
Phonefi-phone-{name}fi-phone-emergencyAdditional phones
URLfi-url-{name}fi-url-websiteLinks
Datefi-date-{name}fi-date-appointmentDates (ISO 8601)
Ratingfi-rating-{name}fi-rating-satisfactionRatings (1-5)
Selectfi-select-{name}fi-select-categoryDropdowns, radios
Countryfi-country-{name}fi-country-shippingCountry codes
Filefi-file-{name}fi-file-attachmentFile uploads

For a complete reference, see the Form Blocks documentation.


<form id="feedback-form">
  <label for="email">Your Email</label>
  <input type="email" name="fi-sender-email" id="email" required>
  
  <label for="rating">How would you rate your experience? (1-5)</label>
  <input type="number" name="fi-rating-experience" id="rating" min="1" max="5" required>
  
  <label for="feedback">Your Feedback</label>
  <textarea name="fi-text-feedback" id="feedback" required></textarea>
  
  <button type="submit">Submit Feedback</button>
</form>
<form id="newsletter-form">
  <label for="email">Email Address</label>
  <input type="email" name="fi-sender-email" id="email" required>
  
  <label for="name">Name (optional)</label>
  <input type="text" name="fi-sender-fullName" id="name">
  
  <button type="submit">Subscribe</button>
</form>
<form id="contact-form">
  <label for="name">Your Name</label>
  <input type="text" name="fi-sender-fullName" id="name" required>
  
  <label for="email">Email</label>
  <input type="email" name="fi-sender-email" id="email" required>
  
  <label for="subject">Subject</label>
  <select name="fi-select-subject" id="subject" required>
    <option value="">Select a subject...</option>
    <option value="General Inquiry">General Inquiry</option>
    <option value="Collaboration">Collaboration</option>
    <option value="Bug Report">Bug Report</option>
    <option value="Other">Other</option>
  </select>
  
  <label for="message">Message</label>
  <textarea name="fi-text-message" id="message" required></textarea>
  
  <button type="submit">Send</button>
</form>
<form id="upload-form">
  <label for="name">Your Name</label>
  <input type="text" name="fi-sender-fullName" id="name" required>
  
  <label for="email">Email</label>
  <input type="email" name="fi-sender-email" id="email" required>
  
  <label for="file">Attach File (PDF, images, max 25MB)</label>
  <input type="file" name="fi-file-attachment" id="file" accept=".pdf,.jpg,.jpeg,.png,.gif">
  
  <label for="notes">Notes</label>
  <textarea name="fi-text-notes" id="notes"></textarea>
  
  <button type="submit">Upload</button>
</form>

Here’s a reusable JavaScript template you can adapt for any form:

<script src="https://forminit.com/sdk/v1/forminit.js"></script>

<script>
(function() {
  const forminit = new Forminit();
  const FORM_ID = 'YOUR_FORM_ID'; // Replace with your Form ID
  
  const form = document.getElementById('contact-form');
  const submitBtn = form.querySelector('button[type="submit"]');
  const statusDiv = document.getElementById('form-status');
  
  // Store original button text
  const originalBtnText = submitBtn.textContent;
  
  form.addEventListener('submit', async function(event) {
    event.preventDefault();
    
    // UI: Show loading state
    submitBtn.disabled = true;
    submitBtn.textContent = 'Sending...';
    hideStatus();
    
    try {
      const formData = new FormData(form);
      const { data, error } = await forminit.submit(FORM_ID, formData);
      
      if (error) {
        showStatus(error.message || 'An error occurred. Please try again.', 'error');
        return;
      }
      
      // Success
      showStatus('Thank you! Your submission was received.', 'success');
      form.reset();
      
    } catch (err) {
      showStatus('Network error. Please check your connection and try again.', 'error');
    } finally {
      // Reset button
      submitBtn.disabled = false;
      submitBtn.textContent = originalBtnText;
    }
  });
  
  function showStatus(message, type) {
    statusDiv.textContent = message;
    statusDiv.className = type;
    statusDiv.style.display = 'block';
  }
  
  function hideStatus() {
    statusDiv.style.display = 'none';
    statusDiv.className = '';
  }
})();
</script>

When a form is submitted successfully, Forminit returns:

{
  data: {
    hashId: "7LMIBoYY74JOCp1k",      // Unique submission ID
    date: "2026-01-17 14:30:00",     // Submission timestamp
    blocks: {                         // Submitted values
      sender: {
        firstName: "John",
        lastName: "Doe",
        email: "[email protected]"
      },
      message: "Hello!"
    }
  },
  redirectUrl: "https://forminit.com/thank-you"
}

If there’s an error:

{
  error: {
    error: "FI_SCHEMA_FORMAT_EMAIL",
    code: 400,
    message: "Invalid email format. Please enter a valid email address."
  }
}

If you want to redirect users to a thank-you page instead of showing an inline message:

const { data, redirectUrl, error } = await forminit.submit(FORM_ID, formData);

if (error) {
  // Handle error
  return;
}

// Redirect to thank you page
window.location.href = '/thanks.html';

// Or use Forminit's default thank you page:
// window.location.href = redirectUrl;

Forminit automatically validates:

Field TypeValidation
EmailValid email format
PhoneE.164 format (+12025550123)
URLValid URL format
RatingMust be 1-5
CountryISO 3166-1 alpha-2 code
DateISO 8601 format

Add HTML5 validation attributes for better user experience:

<!-- Required field -->
<input type="email" name="fi-sender-email" required>

<!-- Email pattern -->
<input type="email" name="fi-sender-email" 
       pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$">

<!-- Phone with pattern -->
<input type="tel" name="fi-sender-phone" 
       pattern="\+[0-9]{10,15}" 
       placeholder="+12025550123">

<!-- Rating range -->
<input type="number" name="fi-rating-score" min="1" max="5">

<!-- Text length -->
<textarea name="fi-text-message" minlength="10" maxlength="1000"></textarea>

Add a hidden field that bots will fill out but humans won’t:

<form id="contact-form">
  <!-- Honeypot - hide this with CSS -->
  <div style="position: absolute; left: -9999px;">
    <label for="website">Website</label>
    <input type="text" name="website" id="website" tabindex="-1" autocomplete="off">
  </div>
  
  <!-- Real fields -->
  <input type="text" name="fi-sender-fullName" required>
  <input type="email" name="fi-sender-email" required>
  <textarea name="fi-text-message" required></textarea>
  
  <button type="submit">Send</button>
</form>

<script>
form.addEventListener('submit', async function(event) {
  event.preventDefault();
  
  // Check honeypot
  const honeypot = document.getElementById('website');
  if (honeypot.value) {
    // Bot detected - silently reject
    statusDiv.textContent = 'Thank you for your message!';
    statusDiv.className = 'success';
    return;
  }
  
  // Continue with real submission...
});
</script>

See the Honeypot documentation for more details.

Forminit supports CAPTCHA integration:


All form submissions appear in your Forminit dashboard at forminit.com:

  • View individual submissions
  • Search and filter
  • Export to CSV
  • Set up email notifications
  • Configure webhooks for integrations

  1. View your submissions in the Forminit dashboard
  2. Set up email notifications for new submissions
  3. Explore webhook integrations for advanced workflows