Hay una diferencia brutal entre un SaaS que la gente usa y uno que la gente quiere usar. Los dos pueden resolver el mismo problema, pero el segundo tiene un churn del 3% mensual y el primero del 12%. La diferencia casi nunca es funcionalidad — es experiencia.
En EnviaIT diseñamos y construimos productos SaaS para clientes que necesitan retener usuarios en mercados competitivos. Después de varios proyectos (incluido Nudato, nuestra plataforma de gestión de eventos), hemos destilado los principios que realmente mueven métricas.
Onboarding: los primeros 5 minutos definen todo
El 40-60% de los usuarios que se registran en un SaaS nunca vuelven después de la primera sesión. Eso no es un problema de marketing — es un problema de diseño.
Un buen onboarding no es un tour de 15 pasos con tooltips. Es llevar al usuario a su primer momento de valor lo más rápido posible.
El patrón que funciona
Registro → Pregunta contextual (1-2) → Setup mínimo → Valor inmediato
En Nudato, reducimos el onboarding de organizadores de eventos de 8 pasos a 3:
- Nombre del evento y fecha — lo mínimo para crear algo
- Importar agenda (CSV o manual) — el usuario ve su evento tomando forma
- Invitar al primer asistente — momento de valor: "esto funciona"
Todo lo demás (branding, configuración de notificaciones, integraciones) se presenta después, cuando el usuario ya ha invertido emocionalmente en el producto.
La regla es simple: si puedes posponer un paso sin romper la experiencia core, posponlo. Cada campo extra en el onboarding es una oportunidad para que el usuario cierre la pestaña.
Indicadores de progreso que motivan
Los checklists de onboarding funcionan cuando están bien diseñados:
| Elemento | Buena práctica | Error común | |----------|---------------|-------------| | Progreso visual | Barra que empieza en 20% (nunca en 0%) | Mostrar 0/10 completado | | Tareas | 3-5 acciones concretas | Lista de 12 configuraciones | | Recompensa | Confetti o badge al completar | Nada — el checklist simplemente desaparece | | Persistencia | Visible pero no bloqueante | Modal que impide usar el producto |
Arquitectura de información: dónde poner cada cosa
La navegación de un SaaS es su esqueleto. Si está mal estructurada, da igual lo bonitas que sean las pantallas — el usuario se pierde.
El modelo mental del usuario, no el tuyo
El error más común es organizar la navegación según la estructura del código o la base de datos. El usuario no piensa en "entidades" — piensa en tareas.
❌ Navegación por entidades:
Dashboard | Eventos | Asistentes | Salas | Speakers | Configuración
✅ Navegación por flujo de trabajo:
Mi Evento | Agenda | Personas | Comunicación | Configuración
En el segundo caso, "Personas" agrupa asistentes, speakers e invitados — porque desde la perspectiva del organizador, todas son "personas en mi evento". La estructura técnica es irrelevante para la UX.
Profundidad vs amplitud
Para SaaS con muchas funcionalidades, aplica la regla de 7±2: no más de 7 elementos en el primer nivel de navegación. Usa agrupación y navegación secundaria para el resto.
// Navegación principal: máximo 7 items
const mainNav = [
{ label: 'Dashboard', icon: HomeIcon },
{ label: 'Proyectos', icon: FolderIcon },
{ label: 'Equipo', icon: UsersIcon },
{ label: 'Informes', icon: ChartIcon },
{ label: 'Configuración', icon: GearIcon },
];
// Navegación secundaria dentro de cada sección
const projectSubNav = [
'Resumen', 'Tareas', 'Archivos', 'Integraciones'
];
Progressive disclosure: mostrar solo lo necesario
Este principio es fundamental y sin embargo se viola constantemente. Progressive disclosure significa mostrar información y opciones solo cuando el usuario las necesita.
Niveles de complejidad
Diseñamos cada pantalla con tres niveles:
- Vista rápida — La información esencial que el 80% de los usuarios necesita el 80% del tiempo
- Vista detallada — Datos adicionales accesibles con un clic
- Vista avanzada — Configuración experta, accesible pero nunca prominente
// Ejemplo: formulario de crear evento
function CreateEventForm() {
const [showAdvanced, setShowAdvanced] = useState(false);
return (
<form>
{/* Nivel 1: siempre visible */}
<Input label="Nombre del evento" required />
<DatePicker label="Fecha" required />
<Select label="Tipo" options={eventTypes} />
{/* Nivel 2: toggle explícito */}
<Collapsible
trigger="Opciones avanzadas"
open={showAdvanced}
onToggle={setShowAdvanced}
>
<Input label="Capacidad máxima" />
<Select label="Zona horaria" />
<Toggle label="Requiere aprobación" />
<Input label="URL personalizada" />
</Collapsible>
</form>
);
}
El resultado: la mayoría de usuarios crean un evento en 30 segundos. Los power users tienen acceso a todo sin que la interfaz se sienta abrumadora.
Estados que nadie diseña (y todos ven)
Los diseñadores suelen enfocarse en el happy path: la pantalla con datos, el formulario completado, la lista llena. Pero los usuarios pasan una cantidad sorprendente de tiempo en estados que nadie diseñó.
Loading states
Un spinner genérico dice "espera". Un skeleton screen dice "ya casi está tu contenido". La diferencia es percepción de velocidad.
// ❌ Spinner genérico
function EventList() {
if (loading) return <Spinner />;
return <List items={events} />;
}
// ✅ Skeleton que anticipa el contenido
function EventList() {
if (loading) {
return (
<div className="space-y-4">
{[1, 2, 3].map((i) => (
<div key={i} className="animate-pulse">
<div className="h-6 bg-gray-200 rounded w-3/4 mb-2" />
<div className="h-4 bg-gray-100 rounded w-1/2" />
</div>
))}
</div>
);
}
return <List items={events} />;
}
Empty states
Un empty state es una oportunidad de activación, no un callejón sin salida.
❌ "No hay eventos"
✅ "Aún no tienes eventos. Crea tu primer evento en menos de un minuto."
[Crear evento →]
En Nudato, los empty states incluyen:
- Título explicativo que no culpa al usuario
- Ilustración contextual (no genérica)
- CTA primario que inicia la acción más obvia
- Enlace secundario a documentación si el concepto es nuevo
Error handling UX
Los errores son inevitables. Lo que importa es cómo los comunicas.
Principios que seguimos:
- Lenguaje humano, no códigos de error. "No pudimos guardar los cambios. Revisa tu conexión e inténtalo de nuevo" en lugar de "Error 500: Internal Server Error"
- Contexto específico. Si un campo es inválido, señala exactamente cuál y por qué
- Acción clara. Cada mensaje de error incluye qué puede hacer el usuario para resolverlo
- Recuperación sin pérdida de datos. Si un formulario falla al enviar, los datos deben seguir ahí cuando se reintente
// Patrón de error con recuperación
function SaveButton({ onSave, formData }) {
const [error, setError] = useState(null);
const [retrying, setRetrying] = useState(false);
const handleSave = async () => {
try {
setError(null);
await onSave(formData);
} catch (err) {
setError({
message: 'No pudimos guardar los cambios.',
action: 'Revisa tu conexión e inténtalo de nuevo.',
canRetry: true,
});
}
};
return (
<>
<Button onClick={handleSave} loading={retrying}>
Guardar
</Button>
{error && (
<ErrorBanner
message={error.message}
action={error.action}
onRetry={error.canRetry ? handleSave : undefined}
/>
)}
</>
);
}
Accesibilidad: no es opcional
La accesibilidad no es un nice-to-have ni un requisito legal que cumplir a regañadientes. Es buen diseño. Un producto accesible es un producto más usable para todos.
Lo mínimo que implementamos en cada proyecto
- Navegación por teclado completa. Cada acción alcanzable con Tab, Enter y Escape
- Contraste de color WCAG AA. Ratio mínimo de 4.5:1 para texto normal, 3:1 para texto grande
- Labels en formularios. Siempre
<label>asociado al input, nunca solo placeholder - Roles ARIA donde el HTML semántico no es suficiente
- Focus visible. Los outlines de focus no se eliminan — se diseñan bonitos
// Un botón accesible no requiere esfuerzo extra —
// requiere no eliminar lo que el navegador ya da
<button
onClick={handleAction}
aria-label="Eliminar evento Conferencia Tech 2025"
className="focus:outline-none focus:ring-2 focus:ring-blue-500
focus:ring-offset-2 rounded-md"
>
<TrashIcon aria-hidden="true" />
</button>
Testing de accesibilidad
Usamos una combinación de herramientas automatizadas y testing manual:
- axe-core integrado en los tests para detectar violaciones WCAG automáticamente
- Lighthouse en CI para medir la puntuación de accesibilidad en cada deploy
- Testing manual con lector de pantalla (VoiceOver) en las pantallas principales antes de cada release
Design system: consistencia a escala
Cuando un SaaS crece, la inconsistencia visual se convierte en deuda de diseño. Un botón tiene 4 variantes diferentes en 4 pantallas. Los espaciados no siguen ningún patrón. Los colores se definen inline.
Nuestro approach con design tokens
Todo empieza con tokens — valores atómicos que definen el lenguaje visual:
/* tokens.css */
:root {
/* Colores semánticos, no visuales */
--color-primary: #2563eb;
--color-primary-hover: #1d4ed8;
--color-danger: #dc2626;
--color-success: #16a34a;
--color-text-primary: #1e293b;
--color-text-secondary: #64748b;
--color-bg-primary: #ffffff;
--color-bg-secondary: #f8fafc;
/* Espaciado con escala consistente */
--space-xs: 0.25rem; /* 4px */
--space-sm: 0.5rem; /* 8px */
--space-md: 1rem; /* 16px */
--space-lg: 1.5rem; /* 24px */
--space-xl: 2rem; /* 32px */
--space-2xl: 3rem; /* 48px */
/* Tipografía */
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.125rem;
--font-size-xl: 1.25rem;
--font-size-2xl: 1.5rem;
}
Los componentes se construyen sobre estos tokens, nunca con valores hardcodeados. El resultado: cambiar el color primario en toda la aplicación es editar una sola línea.
Métricas que importan
Diseñar sin medir es decorar. Las dos métricas que más correlacionan con la calidad de UX en un SaaS son activación y retención.
Tasa de activación
Definición: porcentaje de usuarios que completan la acción clave dentro de los primeros X días.
En Nudato, la acción clave es "crear un evento con al menos 1 sesión en la agenda". Medimos:
- Activación día 1: 34% → 52% (después de rediseñar el onboarding)
- Activación día 7: 41% → 63%
Retención
Definición: porcentaje de usuarios que vuelven al producto en un periodo determinado.
| Periodo | Antes del rediseño | Después | |---------|-------------------|---------| | Día 1 | 28% | 45% | | Día 7 | 18% | 31% | | Día 30 | 9% | 22% |
Ese salto del 9% al 22% en retención a 30 días representó un impacto directo en MRR. No añadimos ninguna feature nueva — solo mejoramos cómo se presentaban las existentes.
Cómo medimos
Usamos una combinación de:
- Mixpanel para funnel de activación y eventos de usuario
- Hotjar para grabaciones de sesión y heatmaps en pantallas clave
- Encuestas in-app (NPS y CSAT) con frecuencia trimestral
- Entrevistas cualitativas mensuales con 3-5 usuarios activos
Los datos cuantitativos te dicen qué está pasando. Las entrevistas te dicen por qué. Necesitas ambos.
El principio que lo une todo
Si tuviéramos que reducir nuestra filosofía de UX a una sola frase sería esta: reduce la fricción entre la intención del usuario y el resultado. Cada clic extra, cada campo innecesario, cada pantalla confusa es fricción. Y la fricción mata retención.
No se trata de hacer las cosas bonitas (aunque ayuda). Se trata de hacer las cosas obvias. Cuando un usuario puede completar su tarea sin pensar en la herramienta, has hecho bien tu trabajo.
¿Tu producto SaaS tiene problemas de retención? Hablemos — te ayudamos a identificar las fricciones y diseñar soluciones que muevan métricas.