React - SpamBlock Pixel and Forms Integration

Learn how to integrate SpamBlock Pixel and Forms solution with React forms using hooks and component patterns. Complete React component example with error handling.

Overview

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

import { useEffect, useRef, useState } from "react";

function ContactForm() {
  const formRef = useRef(null);
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [message, setMessage] = useState("");

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

    const form = formRef.current;
    if (!form) return;

    // Listen for allowed submissions from SpamBlock
    const handleAllowed = async (event) => {
      event.preventDefault();
      setIsSubmitting(true);
      setMessage("");

      const formData = new FormData(event.target);

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

        if (response.ok) {
          setMessage("Submission successful!");
          form.reset();
        } else {
          setMessage("There was an error submitting the form.");
        }
      } catch (error) {
        setMessage("Network error. Please try again.");
        console.error("Error:", error);
      } finally {
        setIsSubmitting(false);
      }
    };

    form.addEventListener("spamblock:allowed", handleAllowed);

    return () => {
      form.removeEventListener("spamblock:allowed", handleAllowed);
      document.head.removeChild(script);
    };
  }, []);

  return (
    <form ref={formRef}>
      <label htmlFor="name">Name</label>
      <input id="name" name="name" type="text" required />

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

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

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

      {message && <p>{message}</p>}
    </form>
  );
}

export default ContactForm;

What This Example Shows

  • How to integrate SpamBlock Pixel with React components
  • Using React hooks (useEffect, useRef, useState) for form handling
  • Proper cleanup of event listeners and script tags
  • Loading state management during form submission
  • Error handling in React context

When to Use It

Use this approach when:

  • You're building a React application
  • You want to use React hooks for state management
  • You need component-level form handling
  • You're using functional components (React 16.8+)

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

Common Mistakes

  1. Not cleaning up event listeners - Always remove event listeners in the useEffect cleanup function
  2. Not cleaning up script tag - Remove the pixel script when component unmounts
  3. Missing ref - Use useRef to access the form DOM element
  4. Race conditions - Ensure pixel loads before form submission attempts
  5. State updates after unmount - Check if component is still mounted before updating state
  6. Not preventing default - Always call event.preventDefault() in the event handler

Learn More