ID del formulario

Gatsby

Un formulario de Gatsby que ya funciona en el HTML estático antes de la hidratación, mejorado con fetch después, más una Gatsby Function para envíos con una clave secreta.

Gatsby renderiza cada página a HTML en tiempo de build. Dale al formulario un action real y enviará antes de que React se hidrate, o si el bundle no carga; una vez hidratado, el componente envía con fetch y muestra el resultado en su sitio.

Envía desde el navegador

  1. Añade el id del formulario

    .env.production
    GATSBY_IKIFORM_FORM_ID=frm_xxxxxxxxxxxxxxxx

    Gatsby solo expone al código del navegador las variables que empiezan con GATSBY_, y las incrusta en tiempo de build. Añade la misma línea a .env.development para gatsby develop.

  2. Añade el componente

    src/components/contact-form.js
    import * as React from "react";
    
    const endpoint = `https://ikiform.com/f/${process.env.GATSBY_IKIFORM_FORM_ID}`;
    
    export default function ContactForm() {
      const [status, setStatus] = React.useState("idle");
      const [message, setMessage] = React.useState("");
    
      async function onSubmit(event) {
        event.preventDefault();
        setStatus("sending");
        try {
          const response = await fetch(endpoint, {
            method: "POST",
            headers: { Accept: "application/json" },
            body: new FormData(event.currentTarget),
          });
          const result = await response.json();
          if (result.ok) return setStatus("sent");
          setMessage(result.error.message);
        } catch {
          setMessage("Couldn't reach the server. Try again.");
        }
        setStatus("error");
      }
    
      if (status === "sent") return <p>Thanks, we got it.</p>;
    
      return (
        <form action={endpoint} method="post" onSubmit={onSubmit}>
          <label>
            Email
            <input name="email" type="email" autoComplete="email" required />
          </label>
          <label>
            Message
            <textarea name="message" rows={5} />
          </label>
          <input type="hidden" name="_redirect" value="https://example.com/thanks/" />
          <input name="_gotcha" type="text" tabIndex={-1} autoComplete="off" hidden />
          {status === "error" ? <p role="alert">{message}</p> : null}
          <button disabled={status === "sending"}>Send</button>
        </form>
      );
    }

    Renderízalo desde cualquier página, por ejemplo src/pages/contact.js, y añade src/pages/thanks.js para la redirección sin JavaScript. Para errores por campo y la verificación humana del SDK, amplíalo como en la guía de React.

Envía desde una Gatsby Function

Una Gatsby Function puede reenviar los datos con una clave secreta, lo que se salta los dominios permitidos y la verificación humana. Solo funciona en hostings que admiten Gatsby Functions, como Netlify con el adaptador de Gatsby; un hosting puramente estático como GitHub Pages no puede ejecutarla. Guarda IKIFORM_FORM_ID y una clave secreta con el permiso submissions:write como IKIFORM_SECRET_KEY, sin el prefijo GATSBY_ para que nunca lleguen al navegador.

src/api/contact.js
export default async function handler(req, res) {
  if (req.method !== "POST") return res.status(405).end();
  const response = await fetch(`https://ikiform.com/f/${process.env.IKIFORM_FORM_ID}`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json",
      Authorization: `Bearer ${process.env.IKIFORM_SECRET_KEY}`,
    },
    body: JSON.stringify(req.body),
  });
  res.status(response.status).json(await response.json());
}

Gatsby convierte los cuerpos JSON y form-encoded en req.body, así que la página puede enviar a /api/contact de cualquiera de las dos formas. Todos los envíos comparten entonces la dirección IP de tu función para los límites de frecuencia; consulta Desde un servidor.

Dominios permitidos

Esto aplica a los envíos desde el navegador. Los envíos desde la Gatsby Function usan una clave secreta y se saltan la comprobación.

Dónde funciona el formularioAñadir a Allowed domains
gatsby develop y gatsby servelocalhost. Coincide con http://localhost:8000 y http://localhost:9000: Ikiform solo compara el nombre de host, nunca el puerto.
Tu dominioexample.com, que también cubre www.example.com
Netlifyyour-site.netlify.app. Los deploy previews (deploy-preview-12--your-site.netlify.app) y los branch deploys (branch--your-site.netlify.app) no son subdominios suyos, así que añade el host exacto de la vista previa mientras la pruebas.
Cloudflare Pagesyour-project.pages.dev. Las URL de vista previa como abc123.your-project.pages.dev son subdominios suyos, así que ya coinciden.
  • Nunca añadas netlify.app ni pages.dev solos. Coincidiría cualquier sitio de ese host, incluidos los de otras personas.

Lista de pruebas

  1. Ejecuta gatsby build y abre public/contact/index.html. El action del formulario debería terminar en el id de tu formulario, no en undefined.
  2. Ejecuta gatsby serve con localhost en los dominios permitidos y envía. El mensaje de agradecimiento debería sustituir al formulario.
  3. Desactiva JavaScript, recarga y envía. Deberías ver la página de agradecimiento de Ikiform en local, o /thanks/ en tu dominio https:.
  4. Si usas la función, envía a /api/contact en un deploy preview y confirma que el envío aparece en Ikiform.

Solución de problemas

Qué vesPor quéSolución
404 not_found, y el action termina en /f/undefinedLa variable no tiene el prefijo GATSBY_, o no estaba definida en tiempo de buildLlámala GATSBY_IKIFORM_FORM_ID y vuelve a hacer el build.
La función responde 403 forbiddenLa clave secreta es de otro espacio de trabajo, está revocada o le falta submissions:writeCrea una clave secreta con ese permiso.
/api/contact devuelve 404 después de desplegarEl hosting solo sirve archivos estáticosDespliega en un hosting con Gatsby Functions o usa la versión del navegador.
Los envíos llegan al filtro de spam con origin_mismatchLa página que envió no está entre los dominios permitidos del formularioAñade el host de la tabla de arriba. Si eliges Reject, esos mismos envíos reciben 403 origin_not_allowed.