Svelte - SpamBlock Pixel and Forms Integration

Learn how to integrate SpamBlock Pixel and Forms solution with Svelte forms using the Fetch API. Complete Svelte component example with reactive state.

Overview

This example shows how to integrate both the SpamBlock Pixel and SpamBlock Forms solution in a Svelte component using the Fetch API. 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.

<script>
  import { onMount, onDestroy } from "svelte";

  let formElement;
  let isSubmitting = false;
  let message = "";
  let formData = {
    name: "",
    email: "",
    message: "",
  };

  let pixelScript = null;
  let allowedHandler = null;

  onMount(() => {
    // Load SpamBlock Pixel
    pixelScript = document.createElement("script");
    pixelScript.src = "https://pixel.spamblock.io/latest.js";
    pixelScript.defer = true;
    document.head.appendChild(pixelScript);

    pixelScript.onload = () => {
      if (formElement) {
        allowedHandler = async (event) => {
          event.preventDefault();
          isSubmitting = true;
          message = "";

          const formDataObj = new FormData(event.target);

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

            if (response.ok) {
              message = "Submission successful!";
              formElement.reset();
              formData = { name: "", email: "", message: "" };
            } else {
              message = "There was an error submitting the form.";
            }
          } catch (error) {
            message = "Network error. Please try again.";
            console.error("Error:", error);
          } finally {
            isSubmitting = false;
          }
        };

        formElement.addEventListener("spamblock:allowed", allowedHandler);
      }
    };
  });

  onDestroy(() => {
    if (formElement && allowedHandler) {
      formElement.removeEventListener("spamblock:allowed", allowedHandler);
    }
    if (pixelScript && document.head.contains(pixelScript)) {
      document.head.removeChild(pixelScript);
    }
  });
</script>

<form bind:this={formElement}>
  <label for="name">Name</label>
  <input
    id="name"
    bind:value={formData.name}
    name="name"
    type="text"
    required
  />

  <label for="email">Email Address</label>
  <input
    id="email"
    bind:value={formData.email}
    name="email"
    type="email"
    required
  />

  <label for="message">Message</label>
  <textarea
    id="message"
    bind:value={formData.message}
    name="message"
    required
  ></textarea>

  <button type="submit" disabled={isSubmitting}>
    {isSubmitting ? "Sending..." : "Send"}
  </button>

  {#if message}
    <p>{message}</p>
  {/if}
</form>

What This Example Shows

  • How to integrate SpamBlock Pixel with Svelte components
  • Using Svelte lifecycle functions (onMount, onDestroy)
  • Reactive state management with Svelte's reactive declarations
  • Template binding with bind:this for DOM element access
  • Two-way data binding with bind:value

When to Use It

Use this approach when:

  • You're building a Svelte application
  • You want compile-time optimization
  • You need component-level form handling
  • You prefer Svelte's reactive syntax

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. Svelte component handles the allowed submission

Common Mistakes

  1. Not cleaning up event listeners - Always remove event listeners in onDestroy
  2. Not cleaning up script tag - Remove the pixel script when component unmounts
  3. Missing element binding - Use bind:this to access the form DOM element
  4. Race conditions - Wait for pixel script to load before setting up listeners
  5. Not preventing default - Always call event.preventDefault() in the event handler
  6. Form reset - Reset both the form element and Svelte reactive data

Learn More