Lista de espera para un nuevo SaaS

Lista de espera para un nuevo SaaS9 min de lectura

Cómo crear una página de lista de espera para una app móvil antes de lanzarla en la App Store

Una lista de espera previa al lanzamiento para una app de iOS o Android que pregunta qué teléfono se usa, lleva a los testers de iPhone a TestFlight y llena una prueba cerrada de Play.

Preet SutharFundador, Ikiform

Pon un formulario de lista de espera en la landing page de tu app que pregunte qué teléfono usa la persona y si quiere probar antes. Mete a los testers de iPhone en un grupo de TestFlight con un webhook y la API de App Store Connect, y carga a los testers de Android en una prueba cerrada de Google Play desde una exportación. El día del lanzamiento, envía a cada grupo por email el enlace a su tienda.

Antes de que una app esté en una tienda, no hay botón de instalar al que enviar a la gente. Una lista de espera en tu propia landing page mantiene su interés hasta que lo haya, y cumple una segunda función que las tiendas no cubren: encuentra los testers que necesitas antes del lanzamiento.

Qué cambia en una app móvil

  • Dos tiendas, dos listas. El email de lanzamiento enlaza a la App Store o a Google Play, y las invitaciones de prueba pasan por TestFlight o por una prueba cerrada de Play. Necesitas saber la plataforma de cada persona para enviar la correcta.
  • Los testers tienen que coincidir con la cuenta de la tienda. TestFlight envía una invitación por email a cualquier dirección. Una prueba cerrada de Play solo deja entrar a las cuentas de Google de su lista, así que un tester de Android que se registra con una dirección del trabajo no puede instalar la build.
  • Google Play puede exigir testers antes del lanzamiento. Las cuentas de desarrollador personales creadas después del 13 de noviembre de 2023 deben hacer una prueba cerrada con al menos 12 testers que sigan inscritos 14 días seguidos antes de poder publicar en producción. Una lista de espera es de donde salen esos 12.
  • Las tiendas tienen sus propias herramientas previas al lanzamiento. Vale la pena usarlas junto a una lista de espera, no en su lugar. Mira la comparación de abajo.
ItemPedidos anticipados de la App Store o prerregistro de PlayTu propia lista de espera
Necesita ficha en la tiendaSí, aprobada y listaNo. Funciona desde el primer día de la landing page
Qué obtienesUn recuento, y una notificación de la tienda o una descarga automática al publicarEl email, la plataforma y las respuestas de cada persona
Puede invitar testersNoSí, por email a TestFlight o a una prueba cerrada de Play
LímitesEl prerregistro de Play sigue desactivado en las cuentas personales nuevas hasta que se cumple el requisito de pruebasEl email de lanzamiento lo envías tú

Campos para una lista de espera de una app

Pregunta primero por la plataforma, porque cambia lo que significa el campo de email. El modelo de teléfono es opcional y te dice en qué dispositivos probar. La casilla de la beta separa a quienes quieren probar de quienes quieren el email de lanzamiento.

Vista previa

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

En Android, usa la cuenta de Google con la que inicias sesión en Google Play.

¿Qué teléfono usas?
El radio platform es obligatorio, así que cada registro cae en una lista con la que puedes actuar. Pega la definición en la pestaña Fields del formulario.

El formulario

El formulario funciona como HTML sencillo en cualquier landing page. El script hace dos cosas pequeñas: preselecciona la plataforma según el navegador del visitante y muestra la indicación sobre la cuenta de Google solo a los usuarios de Android.

index.html
<form id="app-waitlist" action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
  <fieldset>
    <legend>Which phone do you use?</legend>
    <label><input type="radio" name="platform" value="iphone" required> iPhone</label>
    <label><input type="radio" name="platform" value="android"> Android</label>
  </fieldset>

  <label for="email">Email</label>
  <input id="email" name="email" type="email" autocomplete="email" inputmode="email" required>
  <p id="email-hint" hidden>Use the Google account you sign in to Google Play with.</p>

  <label for="first_name">First name</label>
  <input id="first_name" name="first_name" autocomplete="given-name" maxlength="60">

  <label for="device">Phone model</label>
  <input id="device" name="device" maxlength="80" placeholder="iPhone 15, Pixel 8">

  <label><input type="checkbox" name="beta" value="true"> Invite me to test the app before launch</label>
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden>
  <button>Join the waitlist</button>
</form>

<script>
  const form = document.getElementById("app-waitlist");
  const agent = navigator.userAgent;
  const guess = /iPhone|iPad/.test(agent) ? "iphone" : /Android/.test(agent) ? "android" : null;
  if (guess) form.querySelector(`[name="platform"][value="${guess}"]`).checked = true;
  const hint = () => {
    document.getElementById("email-hint").hidden = form.platform.value !== "android";
  };
  form.addEventListener("change", hint);
  hint();
</script>
  • La suposición solo preselecciona un radio. La gente puede cambiarlo, y sin el script no hay nada seleccionado, así que required les obliga a elegir.
  • inputmode="email" y autocomplete="email" importan aquí más que en ningún otro sitio: la mayoría de los visitantes de la landing page de una app están en un teléfono.
  • Configura Redirect after submit con una página de agradecimiento que explique qué pasa después en cada plataforma. Para una versión del formulario con un framework, consulta la guía principal y añade estos campos.

Lleva a los testers a cada tienda

Cómo llegan los testers de iPhone y Android a la beta de cada tiendaiPhoneAndroidregistroplatform =iphone y beta= truerelay dewebhookverifica lafirmaAPI deApp StoreConnectañade un betatesterinvitacióndeTestFlightla envíaAppleregistroplatform =android ybeta = trueexportaciónCSVfiltrar porplataformaPlayConsolelista deemails de lapruebaenlace deinscripciónlo envías túfirmadosemanalCómo llegan los testers de iPhone y Android a la beta de cada tiendaiPhoneAndroidregistroplatform = iphone y beta = truerelay de webhookverifica la firmaAPI de App Store Connectañade un beta testerinvitación de TestFlightla envía Appleregistroplatform = android y beta = trueexportación CSVfiltrar por plataformaPlay Consolelista de emails de la pruebaenlace de inscripciónlo envías túfirmadosemanal
  1. Un usuario de iPhone que marca la casilla de la beta dispara un webhook firmado.
  2. Tu relay lo verifica y llama a la API de App Store Connect para añadir la dirección a un grupo de TestFlight.
  3. Apple envía por email la invitación de TestFlight cuando el grupo tiene una build disponible.
  4. Los testers de Android se recogen igual, y luego se exportan como CSV y se filtran por plataforma.
  5. Pegas las cuentas de Google en la lista de emails de la prueba cerrada en Play Console.
  6. Les envías el enlace de inscripción de la prueba desde tu herramienta de email.
Apple tiene una API para testers; las pruebas cerradas de Google Play se gestionan en Play Console o con Google Groups, así que la parte de Android es una exportación semanal.

iPhone: añade testers a TestFlight

En App Store Connect, crea un grupo de pruebas externas y una clave de API en Users and Access › Integrations, con el rol App Manager o Admin. Luego añade un relay que escuche el webhook submission.created de Ikiform. Este es un route handler de Next.js y usa jose para firmar el token de Apple; funciona en cualquier servidor que tenga fetch.

app/api/testflight/route.ts
import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";
import { importPKCS8, SignJWT } from "jose";

async function appStoreToken() {
  const key = await importPKCS8(process.env.ASC_PRIVATE_KEY!, "ES256");
  return new SignJWT({})
    .setProtectedHeader({ alg: "ES256", kid: process.env.ASC_KEY_ID!, typ: "JWT" })
    .setIssuer(process.env.ASC_ISSUER_ID!)
    .setAudience("appstoreconnect-v1")
    .setIssuedAt()
    .setExpirationTime("15m")
    .sign(key);
}

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, first_name, platform, beta } = event.data.fields;
    if (platform !== "iphone" || beta !== true) return new Response(null, { status: 204 });

    const response = await fetch("https://api.appstoreconnect.apple.com/v1/betaTesters", {
      method: "POST",
      headers: { authorization: `Bearer ${await appStoreToken()}`, "content-type": "application/json" },
      body: JSON.stringify({
        data: {
          type: "betaTesters",
          attributes: { email: String(email), firstName: first_name ? String(first_name) : undefined },
          relationships: { betaGroups: { data: [{ type: "betaGroups", id: process.env.ASC_BETA_GROUP_ID! }] } },
        },
      }),
    });
    if (response.ok || response.status === 409) return new Response(null, { status: 204 });
    return new Response(`App Store Connect answered ${response.status}`, { status: 502 });
  } catch (error) {
    if (error instanceof WebhookVerificationError) return new Response(error.reason, { status: 400 });
    throw error;
  }
}
  • ASC_PRIVATE_KEY es el contenido del archivo .p8 que te da Apple, saltos de línea incluidos. ASC_KEY_ID y ASC_ISSUER_ID están en la misma página.
  • Los tokens de Apple pueden durar como máximo 20 minutos, así que el relay firma uno nuevo por cada entrega.
  • Un 409 significa que Apple rechazó el cambio por un conflicto, a menudo porque la dirección ya es tester. El relay lo da por hecho, así que si un tester nunca recibe la invitación, revisa el grupo en App Store Connect. Cualquier otro fallo responde 502, así que Ikiform reintenta la entrega.
  • TestFlight permite hasta 10.000 testers externos por app. La primera build que das a un grupo externo pasa por Beta App Review, y cada build caduca a los 90 días.

Añade la URL del relay en Webhooks en Ikiform y copia el secreto whsec_ en IKIFORM_WEBHOOK_SECRET. Un espacio de trabajo puede tener 3 endpoints, así que esto puede funcionar junto a un relay que alimenta tu herramienta de email.

Android: llena una prueba cerrada

La API de publicación de Google Play gestiona los testers de las pruebas cerradas mediante Google Groups, no con direcciones sueltas, así que esta parte es una exportación semanal. Exporta la lista con Export CSV, fíltrala en una hoja de cálculo por platform = android y beta = true, y añade los emails a la lista de emails de la prueba cerrada en Test and release › Testing › Closed testing › Manage track › Testers en Play Console. Luego envía a esas personas el enlace de inscripción de la prueba desde tu herramienta de email.

Si estás cumpliendo el requisito de 12 testers, invita a más de 12. Quienes se dan de baja o nunca se inscriben no cuentan, y los 14 días necesitan 12 testers inscritos todo el tiempo.

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. TestFlight envía su propia invitación, así que los testers de iPhone sabrán de Apple. Los testers de Android solo sabrán de ti.

El día del lanzamiento

Exporta toda la lista y divídela por platform. Envía a cada mitad un email con un solo enlace a la tienda. Quien eligió iPhone no necesita el enlace de Play, y un único email con dos insignias pierde toques en una pantalla pequeña. Si recogiste device, compara tus informes de fallos con los modelos que indicó la gente antes de enviar.

Comprueba que funciona

  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. Abre la página en un teléfono. La plataforma correcta está preseleccionada, y en Android aparece la indicación sobre la cuenta de Google.
  3. Envía como tester de iPhone. El envío muestra platform como iphone y beta como true.
  4. Abre el endpoint del relay en Webhooks. La entrega muestra succeeded y la dirección aparece en tu grupo de TestFlight.
  5. Envía como tester de Android, exporta el CSV y confirma que la fila aparece al filtrar con platform en android.
  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.

Problemas habituales

ProblemaQué hacer
Las entregas del relay fallan con 502 y Apple respondió 401El token es incorrecto: revisa el id de la clave, el id del emisor y que la clave privada conservó sus saltos de línea en la variable de entorno.
Se añadió un tester pero no recibió el email de TestFlightEl grupo aún no tiene build, o la primera build sigue en Beta App Review. Las invitaciones salen cuando hay una build disponible para el grupo.
Un tester de Android no puede abrir el enlace de inscripciónLa dirección de la lista no es la cuenta de Google con la que inició sesión en el teléfono. Pídele que se vuelva a registrar con esa cuenta.
422 validation_failedEl envío no coincide con la definición de campos del formulario. error.fields indica cada campo y el motivo. Haz coincidir el name del input con el id del campo.
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.

Preguntas

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