# Recoge peticiones de funcionalidades que puedas contar, priorizar y responder

> Un formulario de peticiones de funcionalidades que pregunta por el problema en lugar de la solución, guarda las peticiones por tema, cuenta personas y no filas, y les avisa por email cuando sale.

Publicado el 2026-10-25 · https://ikiform.com/es/guides/feedback-form/feature-request

Pregunta qué intenta hacer la persona y cómo lo hace hoy, no qué funcionalidad quiere, y exige un email para poder avisarle cuando salga. Guarda cada petición en una tabla mediante un webhook, agrupa las peticiones en temas y ordena los temas por cuántas personas distintas están bloqueadas. Cuando sale un tema, escribe a todos los que lo pidieron.

## Qué tienen de distinto las peticiones de funcionalidades

Un reporte de bug termina cuando se arregla. Una petición de funcionalidad es un dato: una de muchas personas que describen la misma carencia con palabras distintas. De ahí se siguen tres cosas:

- **La gente describe soluciones.** "Añade un botón de CSV" puede significar "mi contable necesita las facturas del mes pasado". Pregunta por la tarea y podrás elegir una solución mejor que la pedida.
- **La misma necesidad llega muchas veces.** Ikiform guarda cada envío y no fusiona repeticiones, y de todos modos dos personas rara vez usan las mismas palabras. Tú agrupas las peticiones por tema y cuentas personas distintas.
- **El valor está en el seguimiento.** Decirle a alguien "lo pediste y lo hemos hecho" es la mejor razón para preguntar. Eso exige un email en cada petición, así que este formulario lo pide como obligatorio.

Diagrama: Cómo una petición de funcionalidad se convierte en un tema contado y en un email de lanzamiento

1. Alguien describe lo que intenta hacer, elige un área y un impacto, y deja un email.
2. Un relay de webhook inserta la petición en tu base de datos, una vez por id de envío.
3. Cada semana etiquetas las nuevas peticiones con un tema, a mano o con un patrón.
4. Si encaja en un tema existente, ese tema tiene ahora una persona más detrás.
5. Si no, empieza un tema nuevo.
6. Cuando sale un tema, seleccionas todos sus emails y mandas un solo mensaje.

La clasificación es personas por tema, no peticiones en bruto. Un cliente que pide lo mismo cinco veces sigue siendo un cliente.

## Pregunta por el problema

Formulario: Feature request

- **¿Qué intentas hacer?** (`problem`, textarea, obligatorio)
- **¿Cómo lo haces hoy?** (`workaround`, textarea)
- **¿Qué parte del producto?** (`area`, select, obligatorio)
- **¿Cuánto te importa?** (`impact`, radio, obligatorio)
- **Email** (`email`, email, obligatorio)

`problem` exige un mínimo de 30 caracteres, lo que convierte "modo oscuro porfa" en una frase con un motivo.

| Campo | Para qué sirve |
| --- | --- |
| `problem` | La tarea que quieren hacer, en sus palabras. Con diferencia, el campo más útil |
| `workaround` | Te dice cuánto duele. "Lo copio a mano en una hoja de cálculo" es una señal fuerte |
| `area` | Una primera clasificación gruesa, para etiquetar dentro de facturación y no entre todo |
| `impact` | Separa a los clientes bloqueados de los curiosos, con opciones redactadas como resultados que la gente puede valorar |
| `email` | Obligatorio. Sin él no puedes cerrar el ciclo ni hacer una pregunta |

No incluyas un campo de prioridad ni de votos. Todo el mundo marca su propia solicitud como de alta prioridad, y el número de personas por tema es un voto mejor que cualquier botón.

## El formulario

El formulario no necesita script: envía y redirige. Configura **Redirect after submit** con una página que explique qué pasa después. Para una versión que se quede en la página dentro de tu framework, toma el [código del formulario](https://ikiform.com/es/guides/feedback-form.md#form) de la guía principal y cambia los campos por estos.

`feature-request.html`:

```html
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
  <label for="problem">What are you trying to do?</label>
  <textarea id="problem" name="problem" rows="5" required minlength="30"
    placeholder="Send last month's invoices to our accountant in one go"></textarea>
  <label for="workaround">How do you do it today?</label>
  <textarea id="workaround" name="workaround" rows="3"></textarea>
  <label for="area">Which part of the product?</label>
  <select id="area" name="area" required>
    <option value="billing">Billing and invoices</option>
    <option value="reports">Reports</option>
    <option value="team">Team and permissions</option>
    <option value="integrations">Integrations and API</option>
    <option value="other">Something else</option>
  </select>
  <fieldset>
    <legend>How much does it matter?</legend>
    <label><input type="radio" name="impact" value="blocking" required /> It stops us using the product for something</label>
    <label><input type="radio" name="impact" value="slow" /> It costs us time every week</label>
    <label><input type="radio" name="impact" value="nice" /> It would be nice</label>
  </fieldset>
  <label for="email">Email</label>
  <input id="email" name="email" type="email" required />
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button>Send request</button>
</form>
```

## Guarda las solicitudes con un webhook

El panel y la exportación CSV sirven para las primeras docenas de solicitudes. Cuando ya etiquetas temas y cuentas personas cada semana, una tabla es más cómoda. Crea una en Postgres:

`schema.sql`:

```text
create table feature_requests (
  submission_id text primary key,
  area text not null,
  impact text not null,
  problem text not null,
  workaround text,
  email text not null,
  theme text,
  created_at timestamptz not null
);
```

Después añade un endpoint de [webhook](https://ikiform.com/es/docs/webhooks.md) en Ikiform que apunte a esta ruta. Funciona en cualquier host de Node con el paquete `pg`, y [tu propio servidor](https://ikiform.com/blog/form-submissions-to-your-own-server.md) cubre el mismo patrón con más detalle:

`app/api/feature-requests/route.ts`:

```ts
import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";
import { Pool } from "pg";

const pool = new Pool({ connectionString: process.env.DATABASE_URL });

const INSERT = `insert into feature_requests (submission_id, area, impact, problem, workaround, email, created_at)
values ($1, $2, $3, $4, $5, lower($6), $7)
on conflict (submission_id) do nothing`;

export async function POST(request: Request) {
  const payload = await request.text();
  let event;
  try {
    event = await verifyWebhook({
      payload,
      headers: request.headers,
      secret: process.env.IKIFORM_WEBHOOK_SECRET!,
    });
  } catch (error) {
    if (error instanceof WebhookVerificationError) return new Response(error.reason, { status: 400 });
    throw error;
  }
  if (event.type !== "submission.created") return new Response(null, { status: 204 });

  const { problem, workaround, area, impact, email } = event.data.fields;
  await pool.query(INSERT, [
    event.data.submission_id,
    area,
    impact,
    problem,
    workaround ?? null,
    email,
    event.data.created_at,
  ]);
  return new Response(null, { status: 204 });
}
```

- `verifyWebhook` rechaza todo lo que no esté firmado con el secreto `whsec_` de tu endpoint.
- `on conflict (submission_id) do nothing` hace que los reintentos sean seguros. Ikiform reenvía una entrega fallida con el mismo envío, y el segundo insert no hace nada.
- Un error de la base de datos lanza una excepción, la ruta responde `500` e Ikiform lo reintenta más tarde. No pierdes solicitudes durante un reinicio de la base de datos.
- El email se pasa a minúsculas al entrar, así que contar personas distintas funciona.

> Ikiform no fusiona ni rechaza envíos repetidos por email. Una repetición idéntica en 24 horas solo suma a la puntuación de spam. Elimina duplicados donde vive la lista, o al exportar.

## Etiqueta y ordena

### Etiqueta las solicitudes nuevas

Una vez por semana, lee las filas sin etiquetar y asigna un tema a cada una. Los patrones resuelven las obvias; el resto léelas tú, porque las solicitudes interesantes no encajan en ningún patrón.

`tag.sql`:

```text
update feature_requests
set theme = 'invoice-export'
where theme is null
  and area = 'billing'
  and problem ilike any (array['%export%', '%accountant%', '%download%']);
```

### Ordena los temas

Esto ordena los temas por cuántas solicitudes dicen estar bloqueadas y luego por cuántas personas distintas lo pidieron:

`ranking.sql`:

```text
select coalesce(theme, 'untagged') as theme,
       count(*) as requests,
       count(distinct email) as people,
       count(*) filter (where impact = 'blocking') as blocking
from feature_requests
group by 1
order by blocking desc, people desc;
```

1. Lee completos los textos de `problem` de los tres temas principales antes de diseñar nada.
2. Fíjate en las soluciones provisionales. A menudo un cambio pequeño elimina lo peor.
3. Contrasta la clasificación con tu plan; muestra demanda, no lo que conviene construir.

## Cierra el ciclo

Cuando se lance un tema, saca a todos los que lo pidieron:

`notify.sql`:

```text
select distinct email
from feature_requests
where theme = 'invoice-export';
```

Envía un email breve desde tu herramienta de email o tu propia bandeja, contando qué se lanzó y con un enlace. Ikiform no envía emails a la persona que rellena el formulario. Las notificaciones por email solo os llegan a ti y a tu equipo, así que no hay respuesta automática, email de confirmación ni doble opt-in. Envíalos desde tu herramienta de email, activados por un [webhook](https://ikiform.com/es/docs/webhooks.md). Aquí pasa lo mismo: el email del lanzamiento sale de ti, no de Ikiform.

## Comprueba que funciona

1. Envía una solicitud con un problema de 10 caracteres. Ikiform responde `422` indicando `problem`.
2. Envía una solicitud real. Aparece en **Submissions** y como fila en `feature_requests`.
3. En **Webhooks**, reenvía la entrega. La tabla sigue teniendo una sola fila para ese envío.
4. Envía dos veces con el mismo email en distinta combinación de mayúsculas. La consulta de clasificación cuenta una persona.

## Errores comunes

- Un tablero público de feedback, como Canny, añade votaciones y una página pública de estado. Si quieres que los clientes vean las solicitudes de los demás, esa es la mejor herramienta; esta configuración mantiene las solicitudes privadas.
- Las solicitudes con varios enlaces pueden puntuar como spam. Revisa el filtro **Spam** cada semana mientras el volumen sea bajo.
- Si más adelante añades una opción a `area`, añádela primero a la definición. Un valor que no esté en la lista se rechaza.
- Guarda lo que necesitas y nada más. Una tabla de solicitudes con emails son datos personales; dilo en tu aviso de privacidad y borra las filas que ya no necesites.

## Solución de problemas

| Problema | Qué hacer |
| --- | --- |
| Faltan filas en la tabla | Abre el endpoint en **Webhooks**. Un `400` significa que el secreto es incorrecto; un `500` con un error de base de datos significa que el insert falló e Ikiform lo está reintentando. |
| `422 validation_failed` | El envío no coincide con la definición de campos del formulario. `error.fields` indica cada campo y el motivo. Haz que el `name` del input coincida con el id del campo. |
| El envío está en el panel pero no llegó ningún email ni webhook | Se 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. |

## Preguntas

### ¿Qué debe preguntar un formulario de solicitud de funcionalidades?

Qué intenta hacer la persona, cómo lo hace hoy, qué parte del producto toca, cuánto le importa y un email. Preguntar por el problema en lugar de por la funcionalidad te deja margen para encontrar una solución mejor.

### ¿Cómo gestiono las solicitudes de funcionalidades duplicadas?

Cuenta con ellas y cuenta personas, no filas. Etiqueta cada solicitud con un tema y ordena los temas por emails distintos. Ikiform guarda cada envío y no fusiona repeticiones.

### ¿Pueden los usuarios votar las solicitudes de funcionalidades?

Con un formulario solo, no. Un formulario mantiene las solicitudes privadas; un tablero público como Canny añade votaciones. Contar personas distintas por tema te da un equivalente privado.

### ¿Cómo aviso a la gente cuando se lanza lo que pidió?

Guarda el email con cada solicitud, selecciona todos los emails del tema lanzado y envía un mensaje desde tu herramienta de email. Ikiform no envía emails a quienes rellenan el formulario.

## Más guías

- [Formulario de feedback para un sitio web o una app](https://ikiform.com/es/guides/feedback-form.md): 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.
- [Formulario de reporte de bugs](https://ikiform.com/es/guides/feedback-form/bug-report.md): Un formulario de reporte de bugs que pide a la gente los pasos y la gravedad, y deja que la página añada por su cuenta la URL, el navegador, el viewport y los errores recientes.
- [Feedback de beta testers](https://ikiform.com/es/guides/feedback-form/beta-tester-feedback.md): Un formulario de feedback para betas con un enlace personal por tester y build, dos escalas de valoración y un resumen semanal que muestra si cada build mejoró.
- [Encuesta NPS](https://ikiform.com/es/guides/feedback-form/nps-survey.md): Haz una encuesta NPS con una puntuación de 0 a 10 en el email, una pregunta de seguimiento en tu propia página que cambia según la puntuación y un script que calcula el NPS.
- [Widget de feedback en React](https://ikiform.com/es/guides/feedback-form/react-feedback-widget.md): Un botón flotante de feedback para una app React que abre un panel pequeño, envía la pantalla, la versión de la app y la cuenta con cada respuesta, y nunca pierde un borrador.
- [Encuesta de cancelación](https://ikiform.com/es/guides/feedback-form/cancellation-survey.md): Pregunta por qué cancelan tus clientes dentro del flujo de baja de tu SaaS, deja Omitir a un clic, guarda el motivo en Stripe e Ikiform y nunca retrases la baja.
