Guías

Guías18 min de lectura

Añade un formulario de feedback a tu sitio web o app

Pon un formulario de feedback en cualquier página o dentro de tu app: una valoración, un comentario, la página de origen, filtro antispam y avisos cuando la nota es baja.

Preet SutharFundador, Ikiform

Añade un formulario corto con una valoración del 1 al 5, un comentario opcional y un email opcional, y envíalo a un backend de formularios para no tener que mantener un servidor. Manda la dirección de la página con cada respuesta, porque el navegador no te dará la URL completa por sí solo. Lleva las notas bajas al chat de tu equipo el mismo día y guarda todas las respuestas en un solo sitio para ver tendencias.

La mayoría de la gente nunca te dice qué falla en tu sitio. Simplemente se va. Un pequeño formulario de feedback atrapa a los pocos que sí lo dirán, en el momento en que lo notan, en la página que lo causó. Esta guía construye uno que encaja en cualquier sitio o app, envía la página de la que viene, deja fuera a los bots y pone las respuestas descontentas delante de tu equipo el mismo día.

Cómo funciona un formulario de feedback

El formulario envía a Ikiform. Ikiform valida la nota, revisa el envío en busca de spam, lo guarda, avisa a tu equipo por email y manda un webhook firmado. Desde el webhook, las notas bajas van a un canal de chat y todas las respuestas pueden ir a una hoja de cálculo o una base de datos.

Cómo viaja un feedback desde tu página hasta tu equipocualquierpágina opantalla dela appnota,comentario,dirección de lapáginaIkiformvalida, filtraspam, guardapanelfiltra porformulario yfecha, exportaCSVemail denotificacióna tu equipo, larespuesta va alvisitantewebhookfirmadosubmission.createdcon campos ymetachat delequiposolo notas de 1o 2envíorelayCómo viaja un feedback desde tu página hasta tu equipocualquierpágina opantalla dela appnota,comentario,dirección dela páginaIkiformvalida, filtraspam, guardapanelfiltra porformulario y fecha,exporta CSVemail denotificacióna tu equipo, larespuesta va alvisitantewebhook firmadosubmission.createdcon campos y metachat del equiposolo notas de 1 o 2envíorelay
  1. Un visitante elige una nota, quizá escribe un comentario, y el formulario lo envía con la dirección de la página.
  2. Ikiform comprueba que la nota sea un número entero del 1 al 5, pasa las comprobaciones antispam y guarda la respuesta.
  3. La respuesta aparece en el panel, donde puedes filtrarla y exportarla como CSV.
  4. Ikiform avisa a tu equipo por email. Si el visitante dejó un email, al responder le llega directamente a él.
  5. Ikiform manda un webhook submission.created firmado con los campos y los metadatos del navegador.
  6. Un pequeño relay publica solo las notas bajas en el chat de tu equipo, para que se lean hoy.
El relay es opcional. Empieza con el email y el panel, y añade el aviso por chat cuando las respuestas empiecen a acumularse.

Formas de recoger feedback

Cada tipo de herramienta está pensado para un trabajo distinto. Elige según lo que necesitas ver cuando llega una respuesta, no por el aspecto del widget.

EnfoquePunto fuerteInconvenientes
Herramientas de feedback para webs, como Hotjar o UsersnapCapturas, anotaciones y contexto de la página sin más código que una etiqueta script.Un script de terceros en cada página, respuestas guardadas en su producto y precios fijados por sus planes.
El widget de un rastreador de errores, como Sentry User FeedbackVincula un reporte al error y, con la reproducción de sesiones activada, a una grabación de lo que pasó.Pensado para bugs, no para opiniones. Primero necesitas el SDK del rastreador en tu app.
Creadores de formularios, como Typeform, Tally o Google FormsFormularios pulidos sin código. Buenos para una encuesta que envías por enlace.Un iframe o una página aparte, así que la respuesta pierde la página a la que se refería salvo que la pases en la URL.
Tableros de feedback, como CannyVotación pública y actualizaciones de estado sobre peticiones de funcionalidades.Pensados para ideas, no para reacciones rápidas. Las respuestas son públicas por diseño.
Tu propia ruta de API y base de datosControl total sobre los datos y cualquier lógica.Tú construyes el filtro antispam, los límites de frecuencia, el email de aviso y la exportación, y necesitas un servidor.
Un backend de formularios, como IkiformTu propio markup en cualquier sitio o app. Validación, filtro antispam, almacenamiento, email y webhooks firmados sin servidor.Sin capturas, porque no se admite la subida de archivos, y sin votaciones ni reproducción de sesiones.

Si necesitas capturas en cada reporte, una herramienta de feedback o un rastreador de errores justifica su script. Si quieres que el formulario se parezca a tu sitio, que las respuestas sean portables y decidir tú adónde van, usa un backend de formularios. El resto de esta guía hace eso.

El formulario

Bastan tres preguntas: una nota, un comentario y un email opcional. La nota es lo que la gente responde; el comentario es donde está el valor; el email es cómo cierras el círculo. Elige tu stack abajo; la elección se aplica a todos los ejemplos de código de estas guías.

Un bloque de markup y un script corto. Sin JavaScript, el formulario sigue enviándose y redirigiendo; con él, el visitante se queda en la página y ve el error del servidor junto al botón. El script rellena page con la dirección sin la query string, para que los tokens de las URLs nunca lleguen a tu bandeja.

feedback.html
<form id="feedback" action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
  <fieldset>
    <legend>How useful was this page?</legend>
    <label><input type="radio" name="rating" value="1" required /> 1</label>
    <label><input type="radio" name="rating" value="2" /> 2</label>
    <label><input type="radio" name="rating" value="3" /> 3</label>
    <label><input type="radio" name="rating" value="4" /> 4</label>
    <label><input type="radio" name="rating" value="5" /> 5</label>
  </fieldset>
  <label for="comment">What would make it better?</label>
  <textarea id="comment" name="comment" rows="4" maxlength="4000"></textarea>
  <label for="feedback-email">Email, if you'd like a reply</label>
  <input id="feedback-email" name="email" type="email" />
  <input type="hidden" name="page" />
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button>Send feedback</button>
  <p id="feedback-status" role="status"></p>
</form>

<script>
  const form = document.getElementById("feedback");
  const status = document.getElementById("feedback-status");
  form.elements.page.value = location.origin + location.pathname;

  form.addEventListener("submit", async (event) => {
    event.preventDefault();
    const button = form.querySelector("button");
    button.disabled = true;
    status.textContent = "Sending";
    try {
      const response = await fetch(form.action, {
        method: "POST",
        headers: { Accept: "application/json" },
        body: new FormData(form),
      });
      const result = await response.json();
      if (result.ok) {
        form.replaceChildren(Object.assign(document.createElement("p"), { textContent: "Thanks. The team reads every note." }));
        return;
      }
      const fields = result.error.fields ?? {};
      status.textContent = fields.rating?.[0] ?? fields.comment?.[0] ?? fields.email?.[0] ?? result.error.message;
    } catch {
      status.textContent = "Couldn't send it. Try again in a moment.";
    }
    button.disabled = false;
  });
</script>
  • Sustituye frm_xxxxxxxxxxxxxxxx por el id de tu formulario, que está en el panel.
  • rating es un grupo de radios con cinco valores. Ikiform lo guarda como número, así que las medias no necesitan parseo.
  • email es opcional. La gente escribe con más sinceridad cuando no tiene que identificarse, y quien quiera una respuesta lo dejará.
  • El input oculto _gotcha es el honeypot. Las personas nunca lo ven; los bots que rellenan todos los inputs se marcan solos como spam.
  • page registra a qué página se refiere la respuesta. La siguiente sección explica por qué la envías tú.
Las versiones de servidor envían con una clave secreta, así que Ikiform se salta Allowed domains (dominios permitidos) y su verificación humana. Todos los envíos vienen entonces de la IP de tu servidor, y el límite Standard de 5 por minuto por visitante cuenta a todos tus visitantes juntos. Elige el límite de frecuencia Relaxed o Custom para un formulario que envías a través de un servidor, y guarda IKIFORM_SECRET_KEY en variables de entorno solo de servidor.

Las guías de frameworks de la documentación cubren la configuración con más detalle: Next.js, Astro, SvelteKit, Nuxt, React, Vue y HTML puro. La plantilla de formulario de feedback genera los mismos campos en HTML, React y una server action; las plantillas de reporte de bugs y de encuesta cubren los formularios más largos.

Define los campos

Pega una definición en la pestaña Fields del formulario e Ikiform la aplica en cada envío, desde cualquier página. Pruébalo abajo: la vista previa ejecuta el validador de Ikiform en tu navegador, así que una nota de 0 o un email mal formado muestra el 422 que recibirías.

Vista previa

Ejecuta el validador de Ikiform en tu navegador. No se envía nada.

¿Qué tan útil fue esta página?

La rellena el script con la dirección de la página, sin la query string.

Un rating acepta un número entero del 1 a su max, aquí 5. Puede llegar a 10, pero cinco opciones se responden más rápido.
CampoTipoPor qué
ratingrating, máx. 5Un clic. Se guarda como número, así que puedes promediarlo por página
commenttextarea, hasta 4.000 caracteresEl motivo de la nota
emailemail, opcionalResponder a quien hace una pregunta. Pasa a ser el reply-to del aviso
pageurl, opcionalA qué página se refiere la respuesta

Con los campos definidos, cualquier otro nombre en el envío se rechaza como Unknown field. Si más adelante envías más contexto, como una versión de la app o el nombre de un plan, añade antes un campo para ello. Los ids de campo van en snake_case en minúsculas.

Saber a qué página se refiere

Una nota sin página es difícil de aprovechar. Ikiform registra los metadatos del navegador con cada envío, pero uno de esos valores es menos útil de lo que parece:

ValorDe dónde vieneQué obtienes
meta.user_agentLo registra IkiformEl navegador y el sistema operativo, en un envío desde el navegador
meta.originLo registra IkiformEl origen de tu sitio, como https://example.com
meta.referrerLo registra IkiformNormalmente solo el origen. Los navegadores usan por defecto la política strict-origin-when-cross-origin, que quita la ruta al enviar a otro sitio
meta.countryLo registra IkiformUn código de país de dos letras
pageLo envía tu formularioLa ruta completa, para saber a qué página se refiere la respuesta

Por eso todos los ejemplos de arriba envían page por su cuenta. Las versiones HTML y SPA leen location; las versiones de servidor leen la dirección que su framework ya conoce. Todas quitan la query string, que puede contener términos de búsqueda, ids de seguimiento o tokens de un solo uso que no quieres guardar.

Las versiones de servidor envían desde tu servidor, así que meta.user_agent es el runtime de tu servidor, no el navegador del visitante. Para el feedback sobre páginas rara vez importa. Para los reportes de bugs sí, y la guía de reportes de bugs reenvía el user agent del navegador como un campo.

Dónde preguntar

El sitio donde está el formulario decide lo que oyes. Un formulario en el pie de cada página recibe un goteo de opiniones fuertes. Una pregunta al final de una tarea recibe respuestas constantes y concretas.

UbicaciónBueno paraCuidado con
Final de una página de documentación o un artículoEncontrar páginas que no responden a la preguntaPoco volumen por página. Léelo por sección, no por página
Tras una tarea en tu app, como una exportación o un primer proyectoCómo se siente un flujo concreto, mientras está recientePregunta una vez por persona, no cada vez que terminan la tarea
Un botón flotante en cada pantallaCualquier cosa, en cualquier momento. Consulta el widget de ReactNo debe tapar tus propios botones, banners de cookies ni burbujas de chat
Un enlace en un emailNotas que quieres seguir en el tiempo, como el NPSEl cliente de email no es tu página, así que el formulario necesita una página de destino en tu sitio

Mantén el formulario pequeño esté donde esté. Pide primero la nota y muestra el cuadro de comentario junto a ella, no en un segundo paso. Un segundo paso pierde a la mayoría, y una nota sin motivo sigue valiendo la pena.

Pon las notas bajas delante de las personas

Qué pasa con una respuesta según su notarespuestaguardadacada nota, cadapáginawebhooksubmission.createdel relaymira lanota3, 4 o 5:nada másrevisiónsemanalmedias porpágina del CSVchat delequiponota, página,comentarioalguienrespondesi dejó unemailfirmadoexportar1 o 2Qué pasa con una respuesta según su notarespuestaguardadacada nota, cada páginawebhooksubmission.createdel relaymira la nota3, 4 o 5: nadamásrevisión semanalmedias por página delCSVchat delequiponota, página,comentarioalguienrespondesi dejó unemailfirmadoexportar1 o 2
  1. Todas las respuestas se guardan, sea cual sea su nota y la página de la que vengan.
  2. Ikiform manda un webhook submission.created firmado a tu relay.
  3. El relay lee la valoración. Las notas de 3 a 5 no necesitan nada más de momento.
  4. Una nota de 1 o 2 va al chat de tu equipo con la página y el comentario.
  5. Si el visitante dejó un email, alguien responde el mismo día.
  6. Una vez por semana, la exportación muestra las medias por página, que es donde aparecen las tendencias.
Avisa solo de las notas malas. Un canal que suena por cada 5 de 5 acaba silenciado en una semana.

Los emails de aviso van a hasta 10 destinatarios confirmados por formulario y llegan con cada respuesta. Eso está bien para unas pocas respuestas al día. A partir de ahí, manda las notas bajas al chat con un relay como esta ruta de Next.js; el mismo código funciona en un Cloudflare Worker:

app/api/feedback-alerts/route.ts
import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";

export async function POST(request: Request) {
  const payload = await request.text();
  try {
    const event = await verifyWebhook({
      payload,
      headers: request.headers,
      secret: process.env.IKIFORM_WEBHOOK_SECRET!,
    });
    if (event.type !== "submission.created") return new Response(null, { status: 204 });
    const { rating, comment, page, email } = event.data.fields;
    if (Number(rating) > 2) return new Response(null, { status: 204 });

    const lines = [
      `*${rating}/5* on ${page ?? event.data.meta.origin ?? "an unknown page"}`,
      comment ? `> ${String(comment).slice(0, 500)}` : "_No comment._",
      email ? `Reply to ${email}` : "Anonymous",
    ];
    const response = await fetch(process.env.SLACK_WEBHOOK_URL!, {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ text: lines.join("\n") }),
    });
    if (!response.ok) return new Response(`Slack answered ${response.status}`, { status: 502 });
    return new Response(null, { status: 204 });
  } catch (error) {
    if (error instanceof WebhookVerificationError) return new Response(error.reason, { status: 400 });
    throw error;
  }
}
  • verifyWebhook comprueba la firma y el timestamp, así que nadie más puede publicar en tu canal a través de esta URL.
  • Las notas por encima de 2 responden 204 y se detienen. Ikiform considera entregado cualquier 2xx.
  • Una llamada fallida a Slack responde 502, e Ikiform reintenta con el mismo webhook-id, así que una caída breve no hace perder un aviso.
  • Los valores de los campos son lo que escribió el visitante. El relay recorta el comentario a 500 caracteres antes de que llegue al chat.

Añade el endpoint en Webhooks y copia su secreto whsec_ en IKIFORM_WEBHOOK_SECRET. Un espacio de trabajo puede tener 3 endpoints. Para rutas sin código, consulta Slack, Discord y Google Sheets. Para el feedback que debería convertirse en un ticket, Linear y GitHub Issues tiene un relay que crea uno por envío.

No hay integraciones de un clic. Cada herramienta se alcanza mediante un webhook firmado, directamente o a través de una herramienta de automatización como Zapier o n8n.

Deja fuera a los bots

Un formulario de feedback en cada página es un formulario público en cada página. Los bots lo encuentran, y casi todo lo que envían son enlaces. Los ajustes por defecto de Ikiform se ocupan de la mayor parte:

DefensaQué frenaConfiguración
HoneypotBots que rellenan todos los inputsEl input oculto _gotcha de los ejemplos
Puntuación de spamTres o más enlaces (+2), frases de spam conocidas (+2), emails desechables (+2), repeticiones idénticas (+3). Con 5 se guarda como spamNinguna
Límites de frecuenciaScripts que envían en bucleActivos por defecto: Standard, 5 por minuto por visitante y 300 por minuto para todo el formulario
Dominios permitidosEnvíos desde otros sitiosAñade tu dominio en los ajustes del formulario
Verificación humanaBots que usan un navegador realPon Spam check en Ikiform. Los envíos con fetch desde el navegador necesitarán entonces un token de challenge()

El spam recibe la misma respuesta de éxito que un envío real, no manda email ni webhook y no cuenta para el uso. Un visitante real que pegue tres enlaces en un comentario puede activar la regla de enlaces junto con una repetición, así que revisa de vez en cuando el filtro Spam. Marcar una respuesta como no spam envía entonces su webhook. La documentación antispam explica cada comprobación.

Lee las respuestas

Lee todos los comentarios las primeras semanas. Después, la vista útil es la nota media por página, de menor a mayor, con los comentarios al lado.

Exportar

Abre Submissions, elige el formulario de feedback, escoge un rango de fechas y pulsa Export CSV. Las columnas son id, created_at, form y status, y luego una por campo, así que con los campos de arriba rating es la columna E y page la columna H. Una exportación admite hasta 100.000 filas; la guía de exportación cubre la API para más.

Importa el archivo en Google Sheets y pon esto en una hoja vacía. Lista cada página con su nota media y el número de respuestas, de peor a mejor:

Google Sheets
=QUERY(A2:H, "select H, avg(E), count(E) where D = 'received' and E is not null group by H order by avg(E) asc label avg(E) 'average', count(E) 'answers'", 0)
  1. Ignora las páginas con solo una o dos respuestas. Un visitante enfadado no es una tendencia.
  2. Lee los comentarios de las tres páginas con peor nota. La solución suele estar en los primeros.
  3. Cuando cambies una página, compara su media de las semanas anteriores y posteriores, no la cifra histórica.
El feedback no es anónimo para Ikiform aunque no haya email: cada respuesta registra el user agent, el origen, el referrer y el país, y un hash de la IP que nunca se devuelve. Indica lo que recoges en tu aviso de privacidad.

Elige tu caso

El formulario de arriba cubre reacciones rápidas en cualquier página. Estas páginas cubren feedback con otro propósito: un bug que reproducir, una petición que valorar, una nota que seguir o un cliente que se va.

Comprueba que funciona

Repasa esto antes de poner el formulario en todas las páginas. Ikiform no tiene plan gratuito. Probar es gratis: un espacio de trabajo sin plan acepta 50 envíos de prueba al mes desde localhost. Para salir a producción, elige Pro desde 6 $/mes por 500 envíos, o paga una vez: 10.000 envíos por 49 $ o 50.000 envíos por 149 $, con créditos que nunca caducan. Consulta los precios.

  1. En Allowed domains del formulario, añade el dominio de tu sitio, y localhost mientras desarrollas. Déjalo vacío para aceptar envíos desde cualquier lugar.
  2. Elige una nota, escribe un comentario y envía. La línea de agradecimiento sustituye al formulario, o el navegador llega a tu página de redirección en la versión de HTML puro.
  3. Abre Submissions en el panel. La respuesta muestra rating como número y page con la ruta completa.
  4. Envía una nota de 6 con curl o desde la consola del navegador. Ikiform responde 422 nombrando rating.
  5. Revisa la bandeja de entrada de cada destinatario de las notificaciones. Cada uno recibe un email con los campos, y Reply va a quien envió el formulario cuando este tiene un campo email.
  6. Envía una nota de 1. Tu relay la publica en el chat del equipo, y la entrega en Webhooks muestra succeeded.
  7. Envía con el honeypot relleno, _gotcha=bot. Igualmente recibe una respuesta de éxito, pero el envío se guarda como spam y no envía email ni webhook.
  8. ¿No llegó nada? Cambia el filtro de estado del panel a Spam. El spam recibe la misma respuesta de éxito que un envío real.

Solución de problemas

ProblemaQué hacer
403 origin_not_allowed, o todos los envíos acaban en spamEl dominio de la página no está en Allowed domains del formulario. Añádelo, y localhost para las pruebas locales. Los subdominios de un dominio de la lista están permitidos.
422 con Rating must be at most 5El formulario envía una nota mayor que el max del campo. Cambia los valores de los radios o sube max en la definición, hasta 10.
422 con un Unknown fieldEl formulario envía un nombre que no está en la definición, a menudo un input oculto nuevo. Añade un campo con ese id o quita el input.
page está vacíoEl script que lo rellena no se ejecutó, o se ejecutó antes de que existiera el formulario. Ponlo después del formulario, o asigna page al enviar como hacen los ejemplos SPA.
meta.referrer solo muestra tu dominioEs lo esperado. Por defecto, los navegadores solo envían el origen en los envíos entre sitios. Usa el campo page en su lugar.
El envío está en el panel pero no llegó ningún email ni webhookSe guardó como spam. El spam no envía nada. Ábrelo en el filtro Spam para ver los motivos y márcalo como no spam para enviar su email y sus webhooks.
429 rate_limitedUn visitante envió más de lo que permite el límite de frecuencia del formulario. Standard permite 5 por minuto por visitante. Espera lo que indique Retry-After, o elige Relaxed o Custom para formularios que envían desde una IP compartida.
402 test_limit_reachedEl espacio de trabajo no tiene plan y ya usó sus 50 pruebas gratuitas desde localhost este mes. Elige un plan o usa Send test en el panel.

Preguntas

¿Te atascaste en un paso o quieres una guía para tu caso? Escribe a hello@ikiform.com.