17 nov 2025·8 min de lectura

Máquina de estados para onboarding: evita registros a medio terminar

Aprende cómo una máquina de estados de onboarding evita cuentas a medio crear, maneja recargas y retrasos de email, y mantiene a los usuarios avanzando.

Máquina de estados para onboarding: evita registros a medio terminar

Por qué los usuarios se quedan a mitad del onboarding

Las “cuentas con onboarding a medio acabar” ocurren cuando tu flujo de registro crea un usuario, pero la persona nunca llega a un estado final utilizable. Pueden ver un spinner para siempre, aterrizar en una pantalla de “verifica tu email” que nunca se actualiza, o volver al paso uno cada vez que inician sesión.

La mayoría de los flujos fallan porque asumen que el onboarding es una lista de tareas lineal de una sola vez. Los usuarios reales refrescan cuando algo va lento, pulsan atrás, abren el mismo enlace en el móvil después de empezar en un portátil, o vuelven mañana tras expirar la sesión.

Los desencadenantes comunes parecen simples, pero son costosos:

  • Un fallo de red provoca que un paso falle después de crear la cuenta.
  • La verificación por email llega tarde, o el usuario pulsa un enlace viejo de verificación.
  • Un timeout desconecta al usuario a mitad de paso y la app pierde la pista.
  • Varias pestañas envían el mismo paso dos veces y dejan datos en un estado extraño.
  • Un refresco repite una acción no reintentable (como cobrar una tarjeta o crear un equipo).

El impacto aparece rápido en soporte: “No puedo iniciar sesión”, “dice verificado pero sigue bloqueado”, o “me vuelve a pedir la contraseña otra vez”. Pero la pérdida mayor es silenciosa: mucha gente no contacta con soporte. Simplemente se va.

La promesa central de una máquina de estados para onboarding es simple: pase lo que pase, el usuario siempre puede reanudar con seguridad. Si un paso falla, la app sabe exactamente dónde está, qué puede hacer a continuación y qué aún no está permitido.

Máquinas de estados en lenguaje sencillo

Un estado es solo una etiqueta clara de dónde está un usuario en el registro. No es una sensación ni el nombre de una página. Piensa: account created, email not verified, profile incomplete, payment pending, onboarded.

Una lista lineal asume que la gente avanza una vez y en orden. En la vida real, alguien refresca durante el pago, abre el email de verificación una hora después, pulsa atrás o lo intenta desde una segunda pestaña. Con una checklist, el sistema a menudo no sabe si continuar, reiniciar o bloquear.

Una máquina de estados de onboarding es un pequeño conjunto de reglas que responde dos preguntas cada vez:

  • ¿En qué estado está este usuario?
  • Desde ese estado, ¿qué movimientos están permitidos (avanzar, reintentar o retroceder)?

En lugar de adivinar por la “pantalla actual”, guardas el estado en el registro del usuario y lo actualizas solo cuando un paso realmente tiene éxito. Si un paso falla, el estado no cambia. Si el usuario reintenta, ejecutas el mismo paso de forma segura. Si vuelve más tarde, miras el estado almacenado y lo envías al siguiente paso válido.

Mantenlo simple. Empieza con los pocos estados que realmente cambian lo que el usuario debería ver a continuación. Evita crear un estado por cada clic de botón.

Ejemplo: un usuario crea una cuenta y espera la verificación por email. Refresca la página y luego intenta iniciar sesión desde otro dispositivo. Si su estado es email_unverified, tu enrutamiento siempre puede enviarlo a “reenviar verificación” y nunca a “completar perfil” hasta que la verificación esté hecha. Una regla así evita muchos registros atascados.

Elige los estados que importan

Una máquina de estados funciona mejor cuando registras momentos que cambian lo que el usuario puede hacer después. Si registras cada clic, creas ruido y casos límite. Si registras muy poco, no puedes reanudar con fiabilidad.

Una regla práctica: crea un estado cuando has (1) escrito algo importante en la base de datos, (2) desencadenado algo fuera de tu app (como enviar un email), o (3) la siguiente pantalla debería ser distinta si el usuario refresca.

La mayoría de los flujos de registro pueden cubrirse con un pequeño conjunto de estados como:

  • started (cuenta creada)
  • email_sent (email de verificación solicitado)
  • verified (email verificado)
  • profile_done (campos de perfil requeridos completados)
  • completed (onboarding finalizado)

No todos los estados deben bloquear al usuario. Decide cuáles son necesarios para avanzar y cuáles son opcionales. La verificación por email puede ser obligatoria por seguridad, mientras que añadir una foto de perfil puede ser opcional.

Después decide qué debe mostrar la app para cada estado. Aquí es donde muchas cuentas atascadas se rescatan.

Si un usuario llega con state = email_sent, no muestres un error genérico ni reinicies el registro. Muestra una pantalla clara de “Revisa tu bandeja” con un botón de reenviar, opción para cambiar el email y una nota breve sobre posibles demoras.

Si state = verified pero el perfil está incompleto, llévalo directo al formulario de perfil y carga lo que ya guardaste.

Define las transiciones permitidas

Una máquina de estados solo ayuda si eres estricto sobre lo que puede ocurrir a continuación. Escribe un mapa simple: para cada estado, enumera los pocos estados a los que el usuario puede pasar. Mantenlo predecible.

Piensa en términos de movimientos, no de pantallas. Una pantalla puede cambiar sin que cambie el estado. Un estado debería cambiar solo cuando tienes prueba de que un paso tuvo éxito.

Reglas que funcionan bien para la mayoría de flujos:

  • Dale a cada estado 1 a 3 estados siguientes permitidos.
  • Añade movimientos de reingreso seguros que no cambien el estado, como “abrir la app de nuevo” o “refrescar la página”.
  • Define estados terminales temprano, como completed (hecho) y disabled (bloqueado por fraude, contracargos, problemas de política).
  • Trata la “espera” como un estado real, por ejemplo email_verification_pending, no como una pantalla temporal.
  • Decide qué pasa ante un movimiento inválido (saltarse pasos, pestaña vieja envía, doble clic). Usualmente: ignora la petición, muestra un mensaje claro y encamina al usuario al paso correcto.

Ejemplo: un usuario se registra, queda en email_verification_pending y luego cierra el navegador. Dos días después pulsa el enlace de verificación. Tus reglas deberían permitir email_verification_pending -> email_verified, y luego moverlo al siguiente paso. No debería permitir email_verification_pending -> completed solo porque se llamó a un endpoint de “finish”.

Paso a paso: implementa un flujo de onboarding reanudable

Un flujo reanudable hace una promesa: no importa dónde abandone el usuario (refresco, pago fallido, email lento), la app siempre puede decidir qué mostrar a continuación.

Empieza guardando una única fuente de verdad para el progreso. Añade un campo onboarding_state en el registro del usuario, o crea un registro de onboarding separado si necesitas historial, reintentos o múltiples intentos.

Después, centraliza la lógica de enrutamiento. Escribe una función que reciba al usuario (y cualquier registro de onboarding) y devuelva la siguiente pantalla, como "verify_email" o "create_workspace". Esa función es el corazón de tu máquina de estados de onboarding.

Trata cada paso como “completo solo si tuvo éxito”. Si un usuario envía un formulario de perfil, valida y guarda primero, y solo entonces avanza el estado. Si algo falla, deja el estado donde estaba para que el usuario pueda reintentar.

Lista compacta de implementación:

  • Persiste el estado en la base de datos (no solo en el navegador)
  • Usa una función única “decide next step” en todas partes
  • Avanza el estado solo después de que el paso realmente tenga éxito
  • En cada carga de la app, enruta según el estado actual
  • Mantén un pequeño registro de auditoría de cambios de estado

Ese registro de auditoría importa más de lo que se espera. Cuando soporte recibe “Verifiqué mi email pero sigo bloqueado”, el log debe mostrar si la verificación fue recibida y en qué estado está la cuenta.

Ejemplo: Sam se registra en móvil, solicita verificación por email y luego abre la app en escritorio. Si tu app siempre llama a la misma función de decisión al cargar, Sam aterriza en “Verificado? Sí. Siguiente: crear workspace”, en lugar de una página muerta o un bucle.

Maneja refrescos, botón atrás y múltiples pestañas

Fix onboarding loops
We repair broken signup logic, email verification, and routing loops in AI-built apps.

Trata el onboarding como algo que se puede interrumpir en cualquier momento. La gente refresca cuando algo parece atascado, pulsa atrás cuando se pone nerviosa y abre dos pestañas cuando un código no aparece. Si tu flujo solo funciona en un viaje perfecto de una sola pestaña, crearás cuentas atascadas.

Una regla segura: cualquier página puede recargarse en cualquier momento. En cada carga, pregunta al servidor dónde está el usuario en la máquina de estados de onboarding y renderiza el paso que corresponda a ese estado. No asumas que la última URL es la verdad. Las URLs son navegación; el estado es la fuente de verdad.

Evita mantener el progreso crítico solo en el navegador (localStorage, flags en memoria, una variable de estado de React). Eso se pierde con un refresco, en modo privado o al cambiar de dispositivo. Guarda el progreso en el backend con marcas de tiempo y trata el almacenamiento cliente como comodidad.

Las pestañas múltiples crean problemas de “envío doble”. Si dos pestañas intentan completar el mismo paso, la segunda no debería romper la cuenta. Responde con “ya completado” y enruta hacia adelante.

Algunas decisiones de UI también reducen el pánico:

  • Pon un punto claro de “Continuar onboarding” en tu app después del login.
  • Muestra en qué paso están y qué sigue.
  • Si un paso está pendiente, explica por qué y qué lo resuelve.
  • Ofrece “Reiniciar onboarding” solo si puedes hacerlo con seguridad sin pérdida de datos.

Retrasos en la verificación por email sin callejones sin salida

La verificación por email es lenta por naturaleza. Los mensajes se retrasan, van a spam o llegan después de que alguien cerró la pestaña. Si tu flujo asume que la verificación es instantánea, acabarás con registros que nunca se recuperan.

En una máquina de estados, trata la verificación como trabajo asíncrono. Un patrón limpio es separar “enviamos un email” de “la dirección está verificada”. Mantén un estado como email_sent (o awaiting_email_verification) y un email_verified = true/false separado. Así, el usuario puede refrescar, volver mañana o cambiar de dispositivo sin caer en un callejón sin salida.

En la pantalla de espera, ofrece acciones seguras que no reinicien el progreso ni creen duplicados:

  • Reenviar el email de verificación (con limitación de frecuencia, mismo usuario, mismo estado)
  • Volver a comprobar el estado de verificación
  • Cambiar la dirección de email (con confirmación y nuevo envío)
  • Usar otro método de inicio de sesión (solo si lo soportas y tras confirmar identidad)

También maneja el caso de “email equivocado” con orientación clara. Una línea como “¿Usaste la dirección equivocada? Actualízala aquí y te enviaremos un nuevo enlace.” evita muchos tickets.

Escenario: Sam se registra en móvil y luego va a un portátil para terminar la configuración. El email de verificación llega tarde y Sam lo pulsa en el teléfono. Si tu app almacena un estado pendiente y comprueba email_verified en la siguiente carga de página, Sam puede continuar en el portátil de inmediato. Sin cuenta nueva y sin bucle al paso uno.

Haz los pasos reintentables e idempotentes

Enforce state on the server
We diagnose state, transitions, and backend rules so the UI can’t guess wrong.

La gente hace doble clic. Los teléfonos pierden conexión. Los navegadores reintentan peticiones. Si tu onboarding asume que cada paso se ejecuta exactamente una vez, acabarás con cuentas en un estado intermedio.

Reintentable significa que un paso puede intentarse de nuevo tras una falla. Idempotente significa que ejecutarlo dos veces da el mismo resultado que ejecutarlo una vez. Quieres ambos.

Un ejemplo simple es “Crear workspace”. Si un usuario pulsa dos veces o la petición expira y la app reintenta, no deberías acabar con dos workspaces, dos perfiles de facturación o un usuario que no puede continuar porque la segunda petición falló.

Un patrón práctico es una clave de idempotencia. Cuando el cliente inicia una acción (como crear un workspace), genera una clave única para esa acción y la envía con la petición. En el servidor, guarda la clave con el registro resultante. Si vuelve a aparecer la misma clave, devuelve el resultado ya creado en lugar de crear un duplicado.

Reglas que previenen la mayoría de cuentas atascadas:

  • Trata cada acción de “create” como “crear o devolver existente”, indexada por un token de idempotencia.
  • Pon restricciones de unicidad en la base de datos (por ejemplo, un workspace por usuario durante onboarding).
  • Avanza al siguiente estado solo después de que la base de datos esté consistente.
  • Si algo falla a mitad de paso, registra una razón de fallo clara y deja al usuario en el estado anterior seguro.
  • Haz la UI segura también (deshabilita botones durante peticiones), pero no confíes solo en eso.

Un bug común es actualizar primero el estado de onboarding y luego intentar crear los datos. Si la segunda parte falla, el usuario parece “por delante” del paso pero faltan registros.

Errores comunes que crean cuentas atascadas

La mayoría de bugs de onboarding atascado no son sofisticados. Ocurren cuando tu app registra progreso demasiado pronto o confía más en el navegador que en el servidor.

Una trampa común es marcar un paso como completo antes de que realmente lo sea. Por ejemplo, establecer payment_complete cuando se carga la página de checkout, no cuando el proveedor de pagos confirma el éxito. Si la pestaña se refresca o el callback falla, el usuario queda en un estado que no puede satisfacer.

Otra causa frecuente es confiar en estado del cliente (localStorage, flags en memoria, un índice de pasos en React) para decidir qué sigue. Los usuarios abren una pestaña nueva, borran almacenamiento o cambian de dispositivo y tu flujo pierde el hilo. En una máquina de estados, el servidor debe ser la fuente de verdad y la UI debe reflejarlo.

Errores que crean cuentas a medio completar:

  • Progreso codificado en URLs (como /onboarding/step-3) en lugar de un estado en servidor que el backend haga cumplir.
  • Crear un nuevo registro de usuario en cada intento de verificación fallido, lo que lleva a duplicados y confusión de “cuenta equivocada”.
  • Manejo débil de retrasos en verificación por email: la app asume que el email se clicará de inmediato y bloquea todas las demás acciones.
  • No hay camino de reintento seguro: re-enviar crea un segundo workspace, una segunda suscripción o un perfil roto.
  • No hay una vía de escape: cuando algo falla, el usuario no tiene una forma clara de pedir ayuda o reiniciar.

Ejemplo: Sam se registra, solicita verificación por email y luego refresca mientras espera. El frontend avanza un contador de pasos y asume que Sam está verificado, pero el backend aún requiere verificación. Sam queda redirigido en círculos.

Controles rápidos antes de lanzar

Antes de publicar, prueba el flujo como se comporta la gente real: refrescan, cambian de dispositivo, pulsan atrás y esperan horas por el email. Si tu máquina de estados maneja eso sin confusión, evitarás la mayoría de cuentas atascadas.

Para cada estado, confirma:

  • Un estado se corresponde con una pantalla (o mensaje) clara y una acción siguiente clara.
  • Refrescar mantiene el mismo progreso y muestra el mismo “qué sigue”.
  • Reintentar el mismo paso dos veces no crea duplicados (cuentas, orgs, pagos, invitaciones).
  • La verificación puede reenviarse, volverse a comprobar y completarse más tarde sin reiniciar el registro.
  • Soporte puede ver el estado actual y las transiciones recientes (marcas de tiempo y errores).

Luego haz tres pruebas intencionales en un navegador real:

  1. Abre el mismo paso en dos pestañas, complétalo en la Pestaña A y luego recarga la Pestaña B. La Pestaña B debe ponerse al día con seguridad.

  2. Apaga Internet a mitad de paso, envía y luego vuelve a intentarlo al reconectar. Debes obtener el mismo resultado de éxito o un error claro con un reintento seguro.

  3. Retrasa la verificación: solicita el email, espera 10 minutos, pulsa el enlace y vuelve a la app. Debes aterrizar en el lugar correcto, no en una página en blanco o un bucle de “comenzar de nuevo”.

Ejemplo: rescate realista de un onboarding atascado

Stop stuck signups fast
We’ll pinpoint why users get stuck and what to change first.

Maya se registra para una prueba SaaS en una tarde ocupada. Crea una cuenta, ve “Revisa tu email para verificar”, y cierra la pestaña.

Al día siguiente el email de verificación finalmente llega. Ella lo pulsa, pero su sesión original ha expirado. En un flujo frágil, eso es un callejón sin salida: la app no sabe si es nueva, verificada o medio creada.

Con una máquina de estados, la app consulta el estado actual de Maya y reanuda desde ahí. El clic de verificación marca su cuenta como verificada incluso si está desconectada, y luego la lleva al siguiente paso requerido.

Unos minutos más tarde, Maya abre la app en dos pestañas. En una pestaña completa su perfil; en la otra sigue viendo “Completa tu perfil”. Cuando guarda en la primera pestaña, el estado de la cuenta avanza una sola vez. La segunda pestaña se refresca y ve el nuevo estado en lugar de sobrescribir nada.

La experiencia de Maya se mantiene consistente:

  • Se registra: ve “Verifica tu email” con una opción segura de “Reenviar”.
  • Pulsa un email tardío: la verificación tiene éxito y se le solicita iniciar sesión.
  • Inicia sesión: aterriza en “Completa tu perfil”, no en la página principal.
  • Usa dos pestañas: la pestaña rezagada se pone al día con “Ya completado” y avanza.

Soporte también ve una historia clara: estado actual, marca de tiempo del último paso completado y el último error (si lo hay). Esa es la diferencia entre arreglar un problema en minutos o adivinar durante horas.

Siguientes pasos: mapea tu flujo y resuélvelo rápido

Si la gente puede registrarse pero no terminar de forma fiable, trata el onboarding como una característica de producto, no como un conjunto de pantallas. Una máquina de estados simple te da una sola fuente de verdad sobre dónde está un usuario y qué puede hacer a continuación.

Empieza en papel. Anota cada paso que espera tu app (crear cuenta, verificar email, aceptar términos, crear workspace, añadir pago, invitar al equipo). Luego agrúpalos en 5 a 8 estados claros que describan progreso, no páginas. Los estados deben mantenerse estables aunque la UI cambie.

Un plan rápido que suele dar rédito:

  • Define tus estados y tu estado final (por ejemplo: SignedUp, EmailPending, Verified, ProfileComplete, Active).
  • Registra cada cambio de estado (quién, de, a, cuándo y por qué).
  • Mide abandonos por estado, no por página.
  • Añade una regla central “route by state” para que refrescos y enlaces profundos aterricen correctamente.
  • Elige un paso frágil (a menudo la verificación por email o el pago) y hazlo reanudable primero.

Un hábito pequeño que evita mucho dolor: cuando algo falla, no dejes al usuario en “desconocido”. Devuélvelos a un estado conocido con una acción clara, incluso si esa acción es “reintentar” o “revisa tu email más tarde”.

Si heredaste una app generada por IA donde el registro funciona en demos pero se rompe con reintentos reales, emails demorados y cambio de pestañas, FixMyMess (fixmymess.ai) se centra en diagnosticar y reparar esos flujos: persistencia de estado, comprobaciones de transiciones y la lógica backend que evita que los usuarios queden varados a mitad del onboarding.

Preguntas Frecuentes

What is an onboarding state machine, and why would I use one?

Una máquina de estados hace que el onboarding sea reanudable. En lugar de adivinar el progreso por la página actual, guardas un claro onboarding_state en el usuario y solo lo avanzas cuando un paso realmente se completa, de modo que las recargas, reintentos y cambios de dispositivo no queden atrapados en bucles.

How many onboarding states should I start with?

Empieza con los pocos estados que cambian lo que el usuario puede hacer a continuación. La mayoría de productos pueden cubrir el registro con unas 5–8 estados, como “account created”, “email unverified”, “profile incomplete” y “completed”. Si creas un estado por cada clic, añadirás casos límite sin mejorar la recuperación.

Where should I store onboarding progress—frontend or backend?

Pérsiste el progreso en el backend, normalmente como un campo onboarding_state en el registro del usuario. Usa el almacenamiento del navegador solo como conveniencia, porque desaparece al recargar, en modo privado, al cambiar de dispositivo o en uso multi-tab.

Can users safely resume onboarding after closing the tab or switching devices?

Sí — si centralizas el enrutamiento. En cada carga de la app tras el login, llama a una función “decide next step” que lea el estado guardado y envíe al usuario a la pantalla correcta, aunque reabra la app mañana o en otro dispositivo.

How do I prevent email verification delays from causing dead ends?

Trata la verificación como trabajo asíncrono. Mantén un estado de espera como email_sent y un flag separado email_verified, luego muestra una pantalla de “revisa tu bandeja” que se pueda actualizar con seguridad y que soporte reenviar o cambiar el email sin reiniciar la cuenta.

How do I avoid double-submits creating duplicates when users open multiple tabs?

Haz que las acciones críticas sean idempotentes. Usa una clave de idempotencia para operaciones “create” (crear workspace, iniciar facturación) y aplica unicidad en la base de datos para que un segundo envío devuelva el resultado existente en lugar de crear duplicados o errores.

What should happen if someone tries to skip steps or submits an old form?

No avances el estado hasta tener prueba de que el paso fue exitoso, y rechaza o ignora movimientos inválidos. Si un usuario intenta saltarse pasos, muestra un mensaje claro y encamínalo al siguiente paso correcto según el estado guardado.

Do I really need an onboarding audit log?

Mantén un pequeño rastro de auditoría de cambios de estado con marcas de tiempo y razones de fallo. Convierte “Estoy verificado pero sigo bloqueado” de un juego de adivinanzas a una comprobación rápida de qué evento ocurrió y en qué estado está la cuenta.

What are the fastest tests to run before shipping this?

Prueba el flujo como se comporta la gente real: recarga a mitad de paso, abre dos pestañas y completa en una, cambia de dispositivo y demora la verificación por email. El objetivo es que cada recarga enruté a una acción válida y que los reintentos no corrompan datos.

How do I fix a signup flow that was built by an AI tool and gets users stuck?

Busca contadores de pasos gestionados por el frontend, progreso codificado en URLs y actualizaciones de estado que ocurran antes de que la escritura en la base de datos o la confirmación externa hayan tenido éxito. El código generado rápido suele “funcionar” en demos pero fallar con reintentos, timeouts y callbacks asíncronos; arreglarlo suele implicar mover la lógica de decisión y el estado al servidor y hacer los pasos idempotentes.