Guías

Guías19 min de lectura

Cómo crear una lista de espera para un nuevo SaaS

Crea una lista de espera previa al lanzamiento en tu propia landing page: el formulario, el antispam, los duplicados, los emails de confirmación y una exportación limpia el día del lanzamiento.

Preet SutharFundador, Ikiform

Pon un formulario HTML sencillo en tu landing page que envíe el email del visitante a un backend de formularios, así no necesitas un servidor antes del lanzamiento. Reenvía cada registro por webhook a la herramienta de email con la que vas a lanzar y deja que esa herramienta mande la confirmación. El día del lanzamiento, exporta la lista como CSV, quita los duplicados por email y envía un único email de lanzamiento.

Una lista de espera es la prueba más barata de una idea de SaaS. Si desconocidos dejan su email por algo que todavía no existe, tienes un motivo para construirlo y una lista de personas a las que avisar cuando salga. Esta guía crea una en tu propia landing page, sin base de datos ni servidor, y la deja lista para el día del lanzamiento.

Cómo funciona una lista de espera

Toda lista de espera tiene las mismas tres partes: un formulario en tu página, un lugar que guarda cada registro y la herramienta desde la que enviarás emails a la lista. Aquí, el formulario envía a Ikiform. Ikiform revisa el envío en busca de spam, lo guarda, te avisa por email y manda un webhook firmado. Un pequeño relay o una herramienta de automatización pasa la dirección a tu herramienta de email.

Cómo viaja un registro en la lista de espera desde tu landing page hasta tu herramienta de emaillanding pagetu formulario,cualquier sitioIkiformfiltra spam,guarda elregistropanelbuscar, filtrar,exportar CSVemail deavisopara ti, no parael registradowebhookfirmadosubmission.createdherramientade emailconfirma yenvía al lanzarenvíorelayCómo viaja un registro en la lista de espera desde tu landing page hasta tu herramienta de emaillandingpagetu formulario,cualquiersitioIkiformfiltra spam,guarda elregistropanelbuscar, filtrar,exportar CSVemail de avisopara ti, no para elregistradowebhook firmadosubmission.createdherramienta deemailconfirma y envía allanzarenvíorelay
  1. Un visitante escribe su email en tu landing page y el formulario lo envía a tu endpoint de Ikiform.
  2. Ikiform comprueba el honeypot, la puntuación de spam y el límite de frecuencia, y luego guarda el registro.
  3. El registro aparece en el panel, donde puedes buscarlo y exportar la lista como CSV.
  4. Ikiform te envía un email a ti y a tu equipo. Nunca escribe a la persona que se registró.
  5. Ikiform envía un webhook submission.created firmado.
  6. Un relay o una herramienta de automatización añade la dirección a tu herramienta de email, que envía la confirmación y, más adelante, el email de lanzamiento.
La herramienta de email es opcional el primer día. Puedes recoger registros durante semanas e importar un CSV después; el webhook mantiene ambos sincronizados desde el principio.

Cuatro formas de gestionar una lista de espera

No hay una única herramienta correcta. La tabla compara las cuatro configuraciones habituales según en qué destacan y qué te cuestan más adelante.

EnfoqueDestaca enContrapartidas
Un SaaS de listas de espera, como LaunchList o WaitlisterEnlaces de referidos, rankings y posición en la fila, listos para usar. Una página alojada si todavía no tienes sitio.Tu lista vive en otro producto. El widget tiene su estilo salvo que pagues o lo rediseñes. El precio suele crecer con los registros.
Un formulario incrustado de un constructor, como Typeform o TallyFlujos pulidos de una pregunta por pantalla, sin nada de código.Un iframe que no encaja con tu página y carga sus propios scripts. La marca, los límites de respuestas y los webhooks dependen del plan.
Tu propia base de datos y ruta de APIControl total sobre los datos y sobre cualquier lógica, como códigos de referido.Tienes que construir el antispam, los límites de frecuencia, las notificaciones y la exportación, y necesitas un servidor aunque la landing page sea estática.
Un backend de formularios, como IkiformTu propio HTML en cualquier sitio. Filtro de spam, almacenamiento, avisos por email, webhooks firmados y exportación CSV sin servidor.Sin ranking de referidos y sin emails para la persona que se registra. Eso lo pone tu herramienta de email.

Elige un SaaS de listas de espera si toda tu estrategia son los referidos. Elige un backend de formularios si quieres que el formulario se vea como el resto de tu sitio, que la lista sea portable y enviar los emails desde la herramienta que vas a usar después del lanzamiento de todos modos. El resto de esta guía usa el backend de formularios.

El formulario

Para empezar, pide un email y nada más. Cada campo extra te cuesta registros, y puedes hacer preguntas más adelante, por email, a quienes ya dijeron que sí. Elige tu stack abajo; la elección se aplica a todos los ejemplos de código de estas guías.

Pega el formulario donde deba aparecer el registro. Envía de la forma clásica y redirige, así que funciona sin nada de JavaScript.

index.html
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
  <label for="email">Email</label>
  <input id="email" name="email" type="email" placeholder="you@company.com" autocomplete="email" required />
  <input type="hidden" name="ref" value="homepage" />
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button>Join the waitlist</button>
</form>

Para que los visitantes se queden en la página, añade este script después del formulario. Envía con fetch, cambia el formulario por la línea de agradecimiento y muestra los errores de campo del servidor.

waitlist.js
const form = document.querySelector('form[action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx"]');
const status = document.createElement("p");
status.setAttribute("role", "alert");
form.append(status);

const labels = {
  email: "Email",
};

form.addEventListener("submit", async (event) => {
  event.preventDefault();
  const button = form.querySelector("button");
  button.disabled = true;
  status.textContent = "";
  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.replaceWith("You're on the list. We'll email you at launch.");
      return;
    }
    const fields = Object.entries(result.error.fields ?? {});
    status.textContent = fields.length
      ? fields.map(([id, messages]) => `${labels[id] ?? id}: ${messages[0]}`).join(" ")
      : result.error.message;
  } catch {
    status.textContent = "Couldn't reach the server. Try again.";
  }
  button.disabled = false;
});

¿Quieres profundizar con HTML? Lee Cómo añadir un formulario de lista de espera en HTML puro a cualquier landing page.

  • El endpoint es la URL de tu formulario. Sustituye frm_xxxxxxxxxxxxxxxx por el id del panel.
  • name="email" es el id del campo. Déjalo como email: Ikiform lo usa como dirección de respuesta de los emails de notificación y lo compara con los dominios de email desechables.
  • El input oculto _gotcha es el honeypot. Las personas nunca lo ven. Los bots que rellenan todos los inputs se marcan solos como spam, y las versiones de servidor lo reenvían sin tocarlo.
  • El input oculto ref registra de dónde vino el registro. Cambia su valor por página o por campaña.
  • Con una definición de campos en la pestaña Fields, un input que no aparece en ella se rechaza con 422 y un error unknown_field, así que incluye ref además de email, como abajo.
  • Un envío HTML normal redirige el navegador tras el éxito. Configura Redirect after submit en los ajustes del formulario con tu propia página de agradecimiento, o Ikiform mostrará la suya alojada.
Campos
{
  "version": 1,
  "title": "Waitlist",
  "fields": [
    { "id": "email", "type": "email", "label": "Email", "required": true, "placeholder": "you@company.com" },
    { "id": "ref", "type": "text", "label": "Source", "validation": { "max_length": 40 } }
  ]
}
Las versiones de servidor envían con una clave secreta, así que Ikiform se salta Allowed domains y su verificación humana. Todos los envíos llegan entonces desde 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 versiones de servidor reenvían la cabecera Origin del navegador, porque Ikiform detecta con ella las pruebas gratuitas desde localhost y el fetch propio de un servidor no envía ninguna.

Las guías por framework de la documentación profundizan más: Next.js, Astro, SvelteKit, Nuxt, React, Vue y HTML. El SDK envuelve la petición del navegador como submit(), y la plantilla de formulario de lista de espera genera la versión de cuatro campos.

Campos que vale la pena pedir

El email es el único campo que necesitas. Si quieres ordenar la lista antes del lanzamiento, añade como mucho dos más. Prueba abajo la versión de cuatro campos: ejecuta el validador de Ikiform en tu navegador y muestra lo que se guardaría, o el 422 que recibirías.

Vista previa

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

Los campos de la plantilla de lista de espera más ref, que tu página rellena con un input oculto en vez de una casilla visible. Pégalo en la pestaña Fields del formulario e Ikiform lo aplicará en el servidor.
CampoPor qué lo pediríasTen en cuenta
emailLa lista en síObligatorio. Usa type="email" para que los móviles muestren el teclado adecuado
nameUn email de lanzamiento personalOpcional. Basta con el nombre de pila
roleInvitar primero a fundadores, o escribir un email distinto a los ingenierosUn select mantiene las respuestas limpias para filtrar
sourceSaber qué canal funciona antes de invertir en élEl texto libre es sincero pero desordenado. Un input oculto ref es más limpio, mira abajo
refContar registros por página o campaña sin preguntarUn input oculto. text opcional con max_length 40

Para saber de dónde vienen los registros sin preguntar, añade un input oculto por página o por campaña. Los nombres que empiezan con _ son instrucciones para Ikiform y nunca se guardan, así que usa un nombre normal como ref:

Inputs ocultos
<input type="hidden" name="ref" value="homepage" />
<input type="hidden" name="_redirect" value="https://example.com/thanks" />

Cada envío también registra el origen y el referrer de la página, así que puedes ver de qué página vino un registro incluso sin ref. El input _redirect lleva el navegador a tu propia página de agradecimiento; solo funciona con una URL https: en uno de los Allowed domains del formulario.

Si vas a enviar algo más que noticias del lanzamiento, como un newsletter, añade una casilla de consentimiento obligatoria con la promesa exacta como etiqueta. Ikiform guarda true con la fecha y hora del envío, lo que registra cuándo aceptó la persona. La plantilla de newsletter incluye una.

Mantén los bots fuera de la lista

Un formulario público con un campo de email atrae bots en cuestión de días. Los registros falsos inflan tus números y, peor aún, tu email de lanzamiento cae en trampas de spam que dañan tu reputación como remitente. Ikiform aplica cuatro capas de defensa; las dos primeras están activas sin configurar nada.

DefensaQué frenaConfiguración
HoneypotBots simples que rellenan todos los inputsEl input oculto _gotcha del formulario de arriba
Puntuación de spamDirecciones desechables (+2), repeticiones idénticas (+3), enlaces y frases de spam conocidas. Con 5, el registro 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
Verificación humanaBots que usan un navegador realPon Spam check en Ikiform. Usa Cloudflare Turnstile sin claves que gestionar

El spam se guarda con una respuesta de éxito normal, así que un bot no aprende nada. No envía email ni webhook y no cuenta para tu uso. Revisa el filtro Spam del panel una vez por semana durante el primer mes; si un registro real acaba ahí, márcalo como no spam y su webhook saldrá en ese momento.

Añade también tu dominio en Allowed domains. Los envíos desde otros sitios se marcan entonces como spam, o se rechazan con 403 origin_not_allowed si eliges Reject. Con la verificación humana activa, el formulario HTML no necesita cambios. La versión con fetch debe pedir antes un token con challenge() de @ikiform/sdk; la documentación antispam muestra las cuatro líneas.

Los envíos del lanzamiento llegan en ráfagas. Si publicas la página en un sitio grande, el límite de 300 por minuto de todo el formulario puede saltar antes que el de cualquier visitante. Súbelo con un límite de frecuencia Custom el día anterior. Toda una oficina o un congreso comparten una IP, así que Relaxed, 20 por minuto por visitante, encaja en esos días.

La misma persona, dos veces

La gente se vuelve a registrar desde otra pestaña, desde un segundo dispositivo o una semana después porque se le olvidó. Ikiform guarda cada envío aceptado y no fusiona ni rechaza repeticiones por email. Esto es lo que pasa con una repetición:

CasoResultado
El mismo email, con otros campos o más de 24 horas despuésUn segundo envío normal
Los mismos campos otra vez dentro de 24 horas+3 a la puntuación de spam, por debajo de 5, así que un segundo envío normal
Una repetición idéntica desde un dominio de email desechable+3 y +2, que llegan a 5: se guarda como spam

Así que cuenta con algunos duplicados y quítalos donde acabe la lista. Hay tres sitios donde hacerlo, de menos a más esfuerzo:

  1. En la herramienta de email. La mayoría de las herramientas de email identifican los contactos por dirección, así que añadir la misma dirección dos veces actualiza un contacto en lugar de crear dos.
  2. Al exportar. Quita los emails duplicados del CSV antes de importarlo en cualquier sitio. Abajo tienes dos formas.
  3. En tu relay. Pasa la dirección a minúsculas y quítale los espacios, y luego insértala con una restricción de unicidad o un upsert, para que una repetición no haga nada.

¿Quieres que un doble clic no cree dos filas en absoluto? Envía una clave de idempotencia por carga de página con la versión fetch. Eso frena las repeticiones accidentales; no impide que una persona se registre dos veces a propósito.

Confirmar los registros

Ikiform no envía emails a la persona que rellena el formulario. Los emails de notificación van solo 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. Es intencionado: la herramienta que envía tu email de lanzamiento también debería enviar la confirmación, para que las bajas y los rebotes se registren en un solo lugar.

Dos formas de conectar Ikiform con ella:

  • Sin código. Añade un endpoint de webhook que apunte a una herramienta de automatización y usa su acción para tu herramienta de email. Consulta Zapier, Make o n8n.
  • Un pequeño relay. Un route handler en cualquier host de Node verifica la firma y llama a la API de tu herramienta de email. El ejemplo de abajo es una ruta de Next.js; el mismo código funciona en un Cloudflare Worker.
app/api/waitlist/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 email = String(event.data.fields.email ?? "").trim().toLowerCase();
    if (!email) return new Response(null, { status: 204 });
    const response = await fetch(process.env.LIST_API_URL!, {
      method: "POST",
      headers: {
        authorization: `Bearer ${process.env.LIST_API_KEY}`,
        "content-type": "application/json",
      },
      body: JSON.stringify({
        email,
        name: event.data.fields.name ?? null,
        tags: ["waitlist", String(event.data.fields.role ?? "unknown")],
      }),
    });
    if (response.status === 409) return new Response(null, { status: 204 });
    if (!response.ok) return new Response(`List 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 la marca de tiempo, así que nadie más puede añadir direcciones a través de esta URL.
  • Cambia el fetch por la llamada para añadir contactos de tu herramienta de email. La mayoría piden un email y una lista o etiqueta, y envían su propio email de confirmación cuando el doble opt-in está activo en esa herramienta.
  • Responder 204 le dice a Ikiform que la entrega tuvo éxito. Un 502 hace que Ikiform reintente, con el mismo webhook-id, así que una caída breve de tu herramienta de email no hace perder registros.

Añade el endpoint en Webhooks en el panel y copia su secreto whsec_ en IKIFORM_WEBHOOK_SECRET. Un espacio de trabajo puede tener 3 endpoints. La documentación de webhooks cubre los reintentos y el payload, y tu propio servidor tiene una versión que guarda cada entrega una sola vez.

El día del lanzamiento

Una lista de espera desde el primer registro hasta el día del lanzamientopáginapublicadael formularioenvía a Ikiformcada semanacompártela, leelos registrosuna semanaantesexporta,deduplica,segmentadía dellanzamientoun email a lalistasemanasUna lista de espera desde el primer registro hasta el día del lanzamientopágina publicadael formulario envía a Ikiformcada semanacompártela, lee los registrosuna semana antesexporta, deduplica, segmentadía del lanzamientoun email a la listasemanas
  1. La página se publica con el formulario enviando a Ikiform.
  2. Cada semana, comparte la página y lee los nuevos registros y sus respuestas.
  3. Una semana antes del lanzamiento, exporta la lista como CSV, quita los duplicados y divídela por rol.
  4. El día del lanzamiento, envía un email a la lista desde tu herramienta de email.
La mayor parte del trabajo es la exportación una semana antes. El email de lanzamiento en sí es breve.

Exporta la lista

Abre Submissions en el panel, elige el formulario de la lista de espera, pon el estado en Received y el rango de fechas en All time, y luego elige Export CSV. Las columnas son id, created_at, form y status, y después una columna por campo. El archivo es UTF-8 con BOM, así que los acentos sobreviven a Excel. Una exportación tiene como máximo 100.000 filas; por encima de eso, pagina con la API REST.

Para quitar duplicados en Google Sheets, importa el CSV y usa esta fórmula en una hoja vacía, con el email en la columna E:

Google Sheets
=SORTN(A2:F, 9^9, 2, LOWER(TRIM(E2:E)), TRUE)

Conserva una fila por dirección, sin distinguir mayúsculas ni espacios, ordenada por email. O ejecuta esto con Node en la carpeta que contiene la exportación. Conserva la primera fila de cada dirección y supone que no hay comas dentro de los valores, lo que se cumple en un formulario que solo pide el email:

dedupe.mjs
import { readFileSync, writeFileSync } from "node:fs";

const [header = "", ...rows] = readFileSync("submissions.csv", "utf8").replace(/^\uFEFF/, "").trim().split(/\r?\n/);
const columns = header.split(",");
const emailAt = columns.indexOf("email");
const seen = new Set();
const unique = rows.filter((row) => {
  const email = row.split(",")[emailAt]?.trim().toLowerCase();
  if (!email || seen.has(email)) return false;
  seen.add(email);
  return true;
});

writeFileSync("waitlist.csv", [header, ...unique].join("\n"));
console.log(`${rows.length} rows, ${unique.length} unique emails`);

Envía el email de lanzamiento

Envíalo desde tu herramienta de email, no desde tu bandeja de entrada personal. Una bandeja personal que escribe a cientos de direcciones a la vez parece spam para los proveedores de correo, y querrás gestionar las bajas desde el momento en que envíes. Que sea breve:

Email de lanzamiento
Subject: Acme is live. You're in.

Hi Ada,

You joined the Acme waitlist in the spring. Today it's open.

Sign in here: https://acme.example/start

You get the first 30 days free because you waited.
Reply to this email if anything breaks. It comes to me.

Ada, founder of Acme
  • Di qué está disponible y enlaza directamente a la página de registro o de inicio de sesión.
  • Premia la espera, por ejemplo con una prueba más larga o un descuento, y dilo una sola vez.
  • Envíalo desde una persona. Las respuestas son el mejor feedback temprano que vas a recibir.
  • Envía primeras líneas distintas a fundadores e ingenieros si recogiste role. Para eso sirve recogerlo.
Si estuviste meses recogiendo registros sin confirmar las direcciones, envía primero a una pequeña parte y vigila la tasa de rebote. Una lista llena de erratas y direcciones muertas daña el dominio desde el que enviarás los emails del producto.

Elige tu caso

Los pasos de arriba funcionan en cualquier sitio. Estas páginas cubren lo que cambia para un lanzamiento o un creador de sitios concreto.

Comprueba que funciona

Repasa esto antes de compartir la página. 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 pasar a producción, elige Pro desde 6 $/mes por 500 envíos, o paga una sola 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 sitio.
  2. Rellena el formulario en tu página y envíalo. Llegarás a tu página de agradecimiento, o a la alojada por Ikiform.
  3. Abre Submissions en el panel. El nuevo envío está ahí con todos los campos que mandaste.
  4. Revisa la bandeja de entrada de cada destinatario de las notificaciones. Cada uno recibe un email con los campos, y Reply responde a quien envió el formulario cuando este tiene un campo email.
  5. Si añadiste un webhook, abre el endpoint en Webhooks. La entrega muestra succeeded con la respuesta de tu servidor.
  6. Envía con el honeypot relleno, _gotcha=bot. Sigue recibiendo una respuesta de éxito, pero el envío se guarda como spam y no manda email ni webhook.
  7. ¿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.
  8. Regístrate dos veces con la misma dirección y confirma que tu herramienta de email sigue mostrando un solo contacto.

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 los Allowed domains del formulario. Añádelo, y también localhost para las pruebas locales. Los subdominios de un dominio de la lista están permitidos.
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.
403 challenge_requiredLa verificación antispam del formulario está en Ikiform y un envío con fetch no llevaba token. Consigue uno con challenge(formId) de @ikiform/sdk antes de cada envío, o desactiva la verificación.
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 con el filtro Spam para ver los motivos y márcalo como no spam para que se envíen su email y sus webhooks.
El navegador llega a la página de agradecimiento de Ikiform en vez de a la tuya_redirect se ignora salvo que su dominio esté en Allowed domains y sea una URL https:. Añade el dominio, o configura Redirect after submit en los ajustes del formulario.
El mismo email aparece dos vecesEs lo esperado. Ikiform no deduplica por email. Quita las repeticiones al exportar, o haz un upsert por email en tu relay o tu herramienta de email.
Los registros llegan a Ikiform pero no a la herramienta de emailAbre el endpoint en Webhooks y lee el registro de entregas. Un 400 significa que el secreto es incorrecto; un 502 con el estado de tu herramienta significa que la herramienta rechazó el contacto.
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.