Simple Serverless Contact Form

I added a simple message feature to my site that allows visitors to send me messages directly from the homepage. It’s just a text input field - no apps, phone numbers, accounts, or third-party services required.

What Are Cloudflare Workers and KV?

Cloudflare Workers are lightweight programs that run on Cloudflare’s global network. They handle web requests quickly and securely.

Cloudflare KV (Key-Value) is a simple database that stores data as key-value pairs. Perfect for storing small amounts of data like messages.

Why KV over D2? While Cloudflare D2 offers SQL capabilities, KV is better for this use case:

  • Simple key-value lookups
  • Lower latency
  • More cost-effective for small data

Why This Approach?

  • No barriers: No apps, accounts, or personal info required
  • Works everywhere: Any device with a web browser
  • Fast: Messages processed in milliseconds
  • No dependencies: No external services
  • Customizable: Easy to modify
  • Free: No cost for personal use

How It Works

Three simple parts:

  1. Frontend: HTML form with text input
  2. Worker: JavaScript that processes messages
  3. Storage: Messages stored in Cloudflare KV

Frontend Form

 1<form id="messageForm">
 2  <input 
 3    type="text" 
 4    id="messageInput" 
 5    placeholder="Whisper something into the void..." 
 6    maxlength="200" 
 7    required
 8  />
 9  <button type="submit">Send</button>
10</form>

JavaScript Handler

 1document.getElementById('messageForm').addEventListener('submit', async (e) => {
 2  e.preventDefault();
 3  const message = document.getElementById('messageInput').value.trim();
 4  
 5  const response = await fetch('https://your-worker.workers.dev/message', {
 6    method: 'POST',
 7    headers: { 'Content-Type': 'application/json' },
 8    body: JSON.stringify({ message })
 9  });
10  
11  const result = await response.json();
12  if (result.success) {
13    alert('Message sent!');
14    document.getElementById('messageInput').value = '';
15  }
16});

Worker Processing

The Worker handles:

  1. Validation: Checks message length/content
  2. Sanitization: Removes HTML/harmful content
  3. Metadata: Collects anonymous sender info
  4. Spam detection: Uses patterns to detect spam
  5. Storage: Saves to KV with unique ID

Data Collected

For transparency, here’s what’s collected with each message:

  • Message content (sanitized, max 200 chars)
  • Timestamp and unique ID
  • IP address (for rate limiting only)
  • Browser/device info (user agent)
  • Location data (country, city, timezone from Cloudflare)
  • Source page (referrer)

Spam Protection

Since this is a public form, spam protection is essential:

  • Rate limiting: 10 messages per hour per IP
  • Duplicate detection: Same message from same IP blocked
  • Pattern matching: Common spam keywords flagged
  • Bot detection: User agent analysis
  • Input validation: Text only, character limits
  • Auto-expiration: Messages deleted after 1 year

Future: Turnstile Integration

I’m considering adding Cloudflare Turnstile which is a privacy-preserving CAPTCHA alternative that verifies legitimate users without puzzles or data collection.

Setup Steps

  1. Create KV namespace for message storage
  2. Write Worker script in JavaScript
  3. Deploy Worker to Cloudflare
  4. Add form to homepage HTML
  5. Implement JavaScript to send data to Worker

Total setup time: ~2-3 hours including testing.

Technical Stack

  • Frontend: Vanilla JavaScript + CSS
  • Backend: Cloudflare Worker (JavaScript)
  • Database: Cloudflare KV
  • Deployment: Cloudflare dashboard
  • Monitoring: Cloudflare Built-in analytics

~500 lines of code total, handles thousands of messages daily.