Alpine.js - SpamBlock Pixel and Forms Integration

Learn how to integrate SpamBlock Pixel and Forms solution with Alpine.js using the Fetch API. Lightweight JavaScript framework for progressive enhancement.

Overview

This example shows how to integrate both the SpamBlock Pixel and SpamBlock Forms solution using Alpine.js, a lightweight JavaScript framework for progressive enhancement. The Pixel intercepts form submissions and scores them at the edge, while the Forms solution provides a hosted endpoint for receiving submissions.

Note: While the SpamBlock Pixel works with any backend endpoint, this example specifically demonstrates using both the Pixel and SpamBlock Forms together. The SpamBlock Forms endpoint (https://api.spamblock.io/f/{form_id}) provides a complete hosted form solution. Learn more about Forms or use your own backend endpoint with the Pixel.

<!-- Load Alpine.js -->
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>

<!-- Load SpamBlock Pixel -->
<script src="https://pixel.spamblock.io/latest.js" defer></script>

<div
  x-data="{
    name: '',
    email: '',
    message: '',
    isSubmitting: false,
    statusMessage: '',
    async handleSubmit(event) {
      event.preventDefault();
      this.isSubmitting = true;
      this.statusMessage = '';

      const form = event.target;
      const formData = new FormData(form);

      try {
        const response = await fetch('https://api.spamblock.io/f/{form_id}', {
          method: 'POST',
          body: formData
        });

        if (response.ok) {
          this.statusMessage = 'Submission successful!';
          form.reset();
          this.name = '';
          this.email = '';
          this.message = '';
        } else {
          this.statusMessage = 'There was an error submitting the form.';
        }
      } catch (error) {
        this.statusMessage = 'Network error. Please try again.';
        console.error('Error:', error);
      } finally {
        this.isSubmitting = false;
      }
    }
  }"
>
  <form
    id="contact-form"
    @submit.prevent="handleSubmit"
    @spamblock:allowed="handleSubmit"
  >
    <label for="name">Name</label>
    <input
      id="name"
      x-model="name"
      name="name"
      type="text"
      required
    />

    <label for="email">Email Address</label>
    <input
      id="email"
      x-model="email"
      name="email"
      type="email"
      required
    />

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

    <button type="submit" :disabled="isSubmitting">
      <span x-text="isSubmitting ? 'Sending...' : 'Send'"></span>
    </button>

    <p x-show="statusMessage" x-text="statusMessage"></p>
  </form>
</div>

What This Example Shows

  • How to integrate SpamBlock Pixel with Alpine.js
  • Progressive enhancement approach (no build step required)
  • Using Alpine.js x-data for component state
  • Event handling with Alpine.js directives
  • Two-way data binding with x-model

When to Use It

Use this approach when:

  • You want lightweight reactive functionality without a build step
  • You're doing progressive enhancement on existing HTML
  • You need minimal JavaScript overhead
  • You want declarative syntax similar to Vue
  • You're working with static sites or simple pages

How it Works

  1. User submits form
  2. SpamBlock Pixel intercepts submission
  3. Submission scored at the edge
  4. If spam: submission blocked, event not fired
  5. If allowed: spamblock:allowed event fired
  6. Alpine.js handler processes the allowed submission

Common Mistakes

  1. Not loading Alpine.js - Make sure Alpine.js loads before the form
  2. Event handler scope - Define handlers in x-data object to access component state
  3. Not preventing default - Use @submit.prevent or call event.preventDefault() in handler
  4. Form reset - Reset both the form element and Alpine.js reactive data
  5. Loading order - Ensure both Alpine.js and SpamBlock Pixel scripts load before form interaction
  6. Missing x-show/x-text - Use Alpine directives for conditional rendering and text binding

Learn More