# Crea un formulario de consulta de proyecto para una agencia o un freelance

> Un formulario de inicio de proyecto para estudios y freelances que clasifica las consultas en calientes, templadas y sin encaje por presupuesto y plazos antes de que nadie lea el briefing.

Publicado el 2026-10-25 · https://ikiform.com/es/guides/lead-capture/project-inquiry

Pide los servicios como checkboxes, el presupuesto y la fecha de inicio como opciones fijas, y una descripción lo bastante larga para valorar el encaje. Envía cada consulta por webhook a un pequeño relay que la clasifica en los carriles caliente, templado o sin encaje según presupuesto y plazos. Luego responde el carril caliente el mismo día, y declina con educación el carril sin encaje en un día, porque ambas respuestas construyen tu reputación.

## Qué tiene de distinto una consulta de proyecto

Una solicitud de presupuesto pide precio para un trabajo conocido. Una consulta de proyecto hace una pregunta más grande: ¿encajamos? A menudo el visitante aún está dando forma al proyecto, y tú decides si le dedicas una llamada de descubrimiento. Para un estudio o un freelance, lo escaso no son los leads, son las horas de los socios leyendo briefings que nunca iban a salir adelante.

Así que este formulario recoge la estructura suficiente para clasificar antes de leer. Bastan tres respuestas: qué necesitan, cuánto pueden gastar más o menos y cuándo. Todo lo que querrías comentar va en una descripción larga que solo se lee entera cuando las respuestas estructuradas dicen que vale la pena.

Diagrama: Cómo clasifica un relay las consultas de proyecto en carriles

1. La consulta llega como un webhook firmado con servicios, presupuesto y fecha de inicio.
2. El relay verifica la firma y puntúa el presupuesto y los plazos.
3. Comprueba la puntuación.
4. Un presupuesto de 30.000 $ o más que empieza en menos de tres meses va al carril caliente.
5. Un presupuesto menor o un inicio más tardío va al carril templado.
6. Menos de 10.000 $ para algo que no sea una web va al carril sin encaje, para un rechazo rápido y amable.

Los carriles son canales de chat. No se rechaza a nadie automáticamente: una persona sigue respondiendo en cada carril, en otro orden.

## Los campos

Para un formulario más ligero con un solo tema, parte de la [plantilla de formulario de contacto](https://ikiform.com/forms/contact-form). Este añade las tres preguntas de clasificación. Marca varios servicios en la vista previa para ver cómo se guardan como lista.

Formulario: Project inquiry

- **Nombre** (`name`, text, obligatorio)
- **Email** (`email`, email, obligatorio)
- **Tu web actual** (`website`, url)
- **¿Qué necesitas?** (`services`, multi_select, obligatorio)
- **Presupuesto** (`budget`, select, obligatorio)
- **¿Cuándo debería empezar?** (`start`, radio, obligatorio)
- **Cuéntanos el proyecto** (`description`, textarea, obligatorio)

`services` es un `multi_select`, guardado como un array como `["brand", "website"]`. `website` es un campo `url`, así que `example.com` se guarda como `https://example.com/`.

| Campo | Por qué tiene esta forma |
| --- | --- |
| `services` | Casillas, porque los proyectos reales combinan servicios. Llega como array en el webhook |
| `budget` | Obligatorio aquí, a diferencia de un formulario de presupuesto. Tus rangos deberían empezar donde empieza tu encargo mínimo |
| `start` | **Solo explorando por ahora** es una respuesta honesta, y útil: va al carril templado |
| `description` | Al menos 40 caracteres, como mucho 4.000. Lo bastante largo para valorar el encaje, lo bastante corto para que la gente lo termine |

## El formulario

Las casillas comparten un mismo `name`. El navegador envía `services=brand&services=website`, e Ikiform junta las repeticiones en una lista. Terminar el nombre en `[]` también funciona, si tus herramientas lo esperan.

`start-a-project.html`:

```html
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="POST">
  <label for="name">Name</label>
  <input id="name" name="name" autocomplete="name" required />
  <label for="email">Email</label>
  <input id="email" name="email" type="email" autocomplete="email" required />
  <label for="website">Your current website</label>
  <input id="website" name="website" inputmode="url" placeholder="example.com" />

  <fieldset>
    <legend>What do you need?</legend>
    <label><input type="checkbox" name="services" value="brand" /> Brand identity</label>
    <label><input type="checkbox" name="services" value="website" /> Website</label>
    <label><input type="checkbox" name="services" value="app" /> Web or mobile app</label>
    <label><input type="checkbox" name="services" value="seo" /> Search and content</label>
  </fieldset>

  <label for="budget">Budget</label>
  <select id="budget" name="budget" required>
    <option value="under_10k">Under $10,000</option>
    <option value="10k_30k">$10,000 to $30,000</option>
    <option value="30k_75k">$30,000 to $75,000</option>
    <option value="over_75k">Over $75,000</option>
  </select>

  <fieldset>
    <legend>When should it start?</legend>
    <label><input type="radio" name="start" value="this_month" required /> This month</label>
    <label><input type="radio" name="start" value="next_quarter" /> In the next three months</label>
    <label><input type="radio" name="start" value="exploring" /> Exploring for now</label>
  </fieldset>

  <label for="description">Tell us about the project</label>
  <textarea id="description" name="description" rows="6" minlength="40" maxlength="4000" required></textarea>

  <input type="hidden" name="_redirect" value="https://studio.example/inquiry/thanks" />
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button>Send inquiry</button>
</form>
```

## Clasifica las consultas con un webhook

Este servidor Express recibe cada consulta, la verifica, elige un carril y publica un resumen corto en el canal de Slack de ese carril. Lee el cuerpo sin procesar con `express.raw`, porque la firma cubre los bytes exactos que envió Ikiform, y pasa `req.headers` de Node a `verifyWebhook` tal cual.

`server.ts`:

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

const BUDGET: Record<string, number> = { under_10k: 0, "10k_30k": 1, "30k_75k": 2, over_75k: 3 };
const START: Record<string, number> = { this_month: 2, next_quarter: 1, exploring: 0 };
const CHANNEL = {
  hot: process.env.SLACK_HOT_LEADS!,
  warm: process.env.SLACK_LEADS!,
  "no-fit": process.env.SLACK_NO_FIT!,
};

function lane(fields: Record<string, unknown>): keyof typeof CHANNEL {
  const budget = BUDGET[String(fields.budget)] ?? 0;
  const start = START[String(fields.start)] ?? 0;
  const services = Array.isArray(fields.services) ? fields.services : [];
  if (budget === 0 && !services.includes("website")) return "no-fit";
  if (budget >= 2 && start >= 1) return "hot";
  return "warm";
}

const app = express();

app.post("/webhooks/inquiries", express.raw({ type: "application/json" }), async (req, res) => {
  let event;
  try {
    event = await verifyWebhook({
      payload: req.body.toString("utf8"),
      headers: req.headers,
      secret: process.env.IKIFORM_WEBHOOK_SECRET!,
    });
  } catch (error) {
    if (error instanceof WebhookVerificationError) return res.status(400).send(error.reason);
    throw error;
  }
  if (event.type !== "submission.created") return res.sendStatus(204);

  const fields = event.data.fields;
  const which = lane(fields);
  const summary = String(fields.description ?? "").slice(0, 280);
  const response = await fetch(CHANNEL[which], {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({
      text: `[${which}] ${fields.name}: ${(fields.services as string[]).join(", ")}, ${fields.budget}, ${fields.start}\n> ${summary}\nmailto:${fields.email}`,
    }),
  });
  res.sendStatus(response.ok ? 204 : 502);
});

app.listen(3000);
```

- Cambia `lane()` para que encaje con tu forma de vender. Los umbrales de arriba son un ejemplo, no un consejo.
- El resumen son los primeros 280 caracteres de la descripción. El texto completo está en el panel y en `event.data.fields`.
- Un `502` cuando falla Slack hace que Ikiform reintente la misma entrega durante unos 3 días, así que una consulta no se pierde por una caída del chat.

Añade la URL `https:` pública del servidor en **Webhooks**. Si prefieres no mantener un servidor, la misma ramificación funciona como paso de router en [Zapier](https://ikiform.com/blog/form-submissions-to-zapier.md), [Make](https://ikiform.com/blog/form-submissions-to-make.md) o [n8n](https://ikiform.com/blog/form-submissions-to-n8n.md).

## Cuando tus propios servicios suenan a spam

La puntuación de spam incluye frases conocidas de venta, como `seo services`, `backlinks` y `rank your website`, y cada una suma 2. Si vendes trabajo de posicionamiento, un cliente real puede escribir exactamente eso. Los enlaces también suman: `website` se guarda como enlace, y tres o más enlaces suman 2.

| Una consulta real que contiene | Puntuación | Resultado |
| --- | --- | --- |
| "We need SEO services" y una web | +2 | Recibido |
| Lo mismo, más dos enlaces a competidores en la descripción | +2 y +2 | Recibido, una señal por debajo del umbral |
| Todo lo anterior, enviado dos veces en 24 horas | +2, +2 y +3 | Spam, por encima de 5 |

Una opción de búsqueda y contenido en `services` permite a los clientes decir lo que necesitan sin escribir la frase. Revisa igualmente el filtro **Spam** cada semana; perder una consulta de 50.000 $ cuesta más que leer diez envíos de spam.

## Comprueba que funciona

1. Envía con dos servicios marcados. El envío guarda `services` como una lista de dos elementos.
2. Envía con **Más de 75.000 $** y **Este mes**. El resumen llega al canal caliente.
3. Envía con **Menos de 10.000 $** y solo **Identidad de marca**. Llega al canal sin encaje.
4. Pega una descripción de 3.000 caracteres. El email de notificación corta el valor en 500 caracteres; el panel lo muestra entero.
5. Para tu servidor y envía. La entrega muestra intentos fallidos en **Webhooks**, y luego tiene éxito cuando lo vuelves a arrancar y eliges **Retry**.

## Errores comunes

- **Ninguna casilla marcada.** Un grupo de casillas vacío no envía nada, así que el `required` de HTML no puede exigirlo. Ikiform rechaza el envío con `Choose at least one option`; muestra ese error en la página con la versión `fetch` de la [guía de captación de leads](https://ikiform.com/es/guides/lead-capture.md#form).
- **Renombrar opciones.** Cambia las etiquetas libremente. Cambia los valores solo a la vez que el relay, o las consultas caerán en el carril equivocado.
- **Briefs largos en el email.** Los emails de notificación muestran hasta 20 campos y 500 caracteres por valor. La descripción se corta ahí. Los miembros del espacio de trabajo reciben en el email un enlace al envío completo.
- **El rechazo.** Ikiform no envía nada a la persona que rellenó el formulario, así que un lead sin encaje no sabe nada a menos que alguien responda. Un rechazo de dos líneas con una recomendación deja la puerta abierta.

## Preguntas

### ¿Qué debe preguntar un formulario de consulta de proyecto?

Datos de contacto, los servicios que necesitan, un rango de presupuesto, una fecha de inicio y una descripción del proyecto. Las tres preguntas de opción fija te permiten clasificar las consultas antes de que nadie lea la descripción.

### ¿Cómo se guardan las respuestas de las casillas?

Las casillas que comparten nombre se juntan en una lista. Con un campo multi_select definido, Ikiform solo acepta los valores listados y los guarda como array, que es lo que lleva el webhook.

### ¿Debo exigir un presupuesto en un formulario de consulta?

En una consulta de proyecto, normalmente sí: es la mejor señal individual de encaje, y unos rangos que empiezan en tu encargo mínimo hacen que la pregunta parezca normal. En una solicitud de presupuesto, donde el precio lo pones tú, hazlo opcional.

### ¿Por qué una consulta real sobre SEO acabó en spam?

Frases como seo services cuentan como señal de spam, y los enlaces suman a la puntuación. Junto con una repetición idéntica en 24 horas, se alcanza el umbral de 5. Márcala como no spam para que salgan su email y su webhook, y ofrece el trabajo de posicionamiento como casilla para que los clientes no tengan que escribir la frase.

## Más guías

- [Formulario de captación de leads](https://ikiform.com/es/guides/lead-capture.md): Un formulario de captación de leads en tu propio sitio que te avisa por email con reply-to, avisa al chat del equipo y alimenta tu CRM, para responder mientras el lead sigue ahí.
- [Formulario de solicitud de presupuesto](https://ikiform.com/es/guides/lead-capture/quote-request.md): Un formulario de solicitud de presupuesto que recoge los briefs como enlaces compartidos en lugar de archivos, pone fecha límite a cada solicitud y evita que los leads con muchos enlaces acaben en spam.
- [Leads a HubSpot o Pipedrive](https://ikiform.com/es/guides/lead-capture/leads-to-crm.md): Convierte cada webhook firmado de Ikiform en el upsert de contactos de HubSpot o en las llamadas de personas y leads de Pipedrive, sin contactos duplicados cuando se reintenta una entrega.
- [Formulario de solicitud de consulta](https://ikiform.com/es/guides/lead-capture/consultation-request.md): Un formulario de solicitud de consulta para gestorías, abogados, coaches y clínicas que pregunta cómo y cuándo llamar, y deja los detalles sensibles para la llamada.
- [Formulario de solicitud de demo](https://ikiform.com/es/guides/lead-capture/demo-request.md): Un formulario para reservar una demo que guarda el lead y luego envía al visitante a Cal.com o Calendly con su nombre y email ya rellenados.
- [Formulario de leads en Next.js](https://ikiform.com/es/guides/lead-capture/nextjs.md): Un formulario de leads en el App Router de Next.js que valida con Zod en una server action, guarda los UTMs del primer contacto en una cookie y envía los leads cualificados a tu calendario.
