# Onboarding de usuário com verificação de CPF: flow de três passos

> Aprenda a criar um fluxo de onboarding com verificação de CPF em três passos, reduzindo fricção e aumentando conversão.

**Publicado:** 04/10/2025
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/onboarding-de-usuario-com-verificacao-de-cpf-flow-de-tres-passos

---


Com a CPFHub.io, é possível criar um fluxo de onboarding em três passos que reduz de 8–10 campos para apenas 3–4 campos de preenchimento manual: o usuário informa o CPF, a API retorna nome completo, data de nascimento e gênero automaticamente, e o cadastro é concluído com o mínimo de atrito. Isso aumenta a taxa de conclusão e melhora a experiência do usuário em fintechs, e-commerce e plataformas de saúde.

## Introdução

O onboarding é o momento mais crítico da jornada do usuário. Se o processo for longo, confuso ou cheio de fricção, a taxa de abandono dispara. No contexto brasileiro, onde a verificação de CPF é requisito para diversos serviços -- fintechs, e-commerce, seguradoras, plataformas de saúde -- o desafio é integrar essa verificação de forma fluida, sem que o usuário sinta que está preenchendo um formulário burocrático.

---

## Arquitetura do fluxo de três passos

O fluxo é dividido em três etapas claras, cada uma com um objetivo específico:

### Passo 1 -- Identificação

O usuário informa apenas o CPF. A API retorna nome, data de nascimento e gênero, que são preenchidos automaticamente nos campos seguintes.

### Passo 2 -- Confirmação

O usuário confirma os dados retornados e complementa com informações adicionais como e-mail e telefone.

### Passo 3 -- Finalização

O usuário define uma senha e aceita os termos de uso. O cadastro é concluído.

Esse fluxo reduz de 8-10 campos para apenas 3-4 campos de preenchimento manual, diminuindo significativamente a fricção.

---

## Indicador de progresso

Um indicador visual de progresso é essencial para que o usuário saiba onde está no fluxo e quanto falta para concluir. Veja a implementação de um stepper simples.

```jsx
import React from 'react';

const steps = ['Identificação', 'Confirmação', 'Finalização'];

function Stepper({ currentStep }) {
 return (
 <div style={{ display: 'flex', justifyContent: 'center', gap: 16, marginBottom: 32 }}>
 {steps.map((label, index) => {
 const isActive = index === currentStep;
 const isCompleted = index < currentStep;
 return (
 <div key={label} style={{ textAlign: 'center' }}>
 <div style={{
 width: 40,
 height: 40,
 borderRadius: '50%',
 display: 'flex',
 alignItems: 'center',
 justifyContent: 'center',
 margin: '0 auto 8px',
 fontSize: '1rem',
 fontWeight: 'bold',
 background: isCompleted ? '#2ecc71' : isActive ? '#3498db' : '#ddd',
 color: isCompleted || isActive ? '#fff' : '#666'
 }}>
 {isCompleted ? '\u2713' : index + 1}
 </div>
 <span style={{
 fontSize: '0.85rem',
 color: isActive ? '#3498db' : '#666'
 }}>
 {label}
 </span>
 </div>
 );
 })}
 </div>
 );
}
```

---

## Passo 1 -- Identificação via CPF

No primeiro passo, o usuário digita apenas o CPF. Ao completar os 11 dígitos, o sistema valida localmente e, se válido, consulta a API automaticamente.

```jsx
import React, { useState, useRef } from 'react';

function StepIdentificacao({ onNext }) {
 const [cpf, setCpf] = useState('');
 const [loading, setLoading] = useState(false);
 const [erro, setErro] = useState('');
 const controllerRef = useRef(null);

 function mascararCPF(valor) {
 const d = valor.replace(/\D/g, '').slice(0, 11);
 let r = '';
 for (let i = 0; i < d.length; i++) {
 if (i === 3 || i === 6) r += '.';
 if (i === 9) r += '-';
 r += d[i];
 }
 return r;
 }

 function validarCPF(digits) {
 if (digits.length !== 11 || /^(\d)\1{10}$/.test(digits)) return false;
 let soma = 0;
 for (let i = 0; i < 9; i++) soma += parseInt(digits[i]) * (10 - i);
 let resto = (soma * 10) % 11;
 if (resto === 10) resto = 0;
 if (resto !== parseInt(digits[9])) return false;
 soma = 0;
 for (let i = 0; i < 10; i++) soma += parseInt(digits[i]) * (11 - i);
 resto = (soma * 10) % 11;
 if (resto === 10) resto = 0;
 return resto === parseInt(digits[10]);
 }

 async function handleChange(e) {
 const masked = mascararCPF(e.target.value);
 setCpf(masked);
 setErro('');

 const digits = masked.replace(/\D/g, '');
 if (digits.length === 11) {
 if (!validarCPF(digits)) {
 setErro('CPF invalido. Verifique os digitos.');
 return;
 }

 setLoading(true);
 if (controllerRef.current) controllerRef.current.abort();
 controllerRef.current = new AbortController();
 const timeoutId = setTimeout(() => controllerRef.current.abort(), 10000);

 try {
 const res = await fetch(`https://api.cpfhub.io/cpf/${digits}`, {
 headers: {
 'x-api-key': process.env.REACT_APP_CPFHUB_API_KEY,
 'Accept': 'application/json'
 },
 signal: controllerRef.current.signal
 });
 clearTimeout(timeoutId);
 const json = await res.json();

 if (json.success) {
 onNext({ cpf: digits, ...json.data });
 } else {
 setErro('CPF nao encontrado. Verifique e tente novamente.');
 }
 } catch (err) {
 clearTimeout(timeoutId);
 setErro(
 err.name === 'AbortError'
 ? 'Tempo esgotado. Tente novamente.'
 : 'Erro na consulta. Tente novamente.'
 );
 } finally {
 setLoading(false);
 }
 }
 }

 return (
 <div>
 <h2>Qual e o seu CPF?</h2>
 <p style={{ color: '#666', marginBottom: 16 }}>
 Precisamos do seu CPF para preencher seus dados automaticamente.
 </p>
 <input
 type="text"
 inputMode="numeric"
 placeholder="000.000.000-00"
 value={cpf}
 onChange={handleChange}
 maxLength={14}
 disabled={loading}
 style={{
 width: '100%', padding: '14px 16px', fontSize: '1.2rem',
 border: `2px solid ${erro ? '#e74c3c' : '#ddd'}`,
 borderRadius: 8, outline: 'none'
 }}
 />
 {loading && <p style={{ color: '#3498db', marginTop: 8 }}>Consultando...</p>}
 {erro && <p style={{ color: '#e74c3c', marginTop: 8 }}>{erro}</p>}
 </div>
 );
}
```

---

## Passo 2 -- Confirmação e complemento

Neste passo, os dados retornados pela API são exibidos pré-preenchidos. O usuário confirma as informações e adiciona e-mail e telefone.

```jsx
function StepConfirmacao({ dados, onNext, onBack }) {
 const [email, setEmail] = useState('');
 const [telefone, setTelefone] = useState('');
 const [erros, setErros] = useState({});

 function handleSubmit(e) {
 e.preventDefault();
 const newErros = {};
 if (!email.includes('@')) newErros.email = 'E-mail invalido.';
 if (telefone.replace(/\D/g, '').length < 10) newErros.telefone = 'Telefone invalido.';
 if (Object.keys(newErros).length > 0) {
 setErros(newErros);
 return;
 }
 onNext({ ...dados, email, telefone });
 }

 return (
 <form onSubmit={handleSubmit}>
 <h2>Confirme seus dados</h2>

 <div style={{ background: '#f8f9fa', padding: 16, borderRadius: 8, marginBottom: 16 }}>
 <p><strong>Nome:</strong> {dados.name}</p>
 <p><strong>Data de nascimento:</strong> {dados.birthDate}</p>
 <p><strong>Genero:</strong> {dados.gender === 'M' ? 'Masculino' : 'Feminino'}</p>
 </div>

 <label style={{ display: 'block', marginBottom: 4 }}>E-mail</label>
 <input
 type="email"
 value={email}
 onChange={(e) => setEmail(e.target.value)}
 placeholder="seu@email.com"
 style={{ width: '100%', padding: 12, marginBottom: 4, borderRadius: 8, border: '2px solid #ddd' }}
 />
 {erros.email && <p style={{ color: '#e74c3c', fontSize: '0.85rem' }}>{erros.email}</p>}

 <label style={{ display: 'block', marginBottom: 4, marginTop: 12 }}>Telefone</label>
 <input
 type="tel"
 value={telefone}
 onChange={(e) => setTelefone(e.target.value)}
 placeholder="(11) 99999-9999"
 style={{ width: '100%', padding: 12, marginBottom: 4, borderRadius: 8, border: '2px solid #ddd' }}
 />
 {erros.telefone && <p style={{ color: '#e74c3c', fontSize: '0.85rem' }}>{erros.telefone}</p>}

 <div style={{ display: 'flex', gap: 12, marginTop: 20 }}>
 <button type="button" onClick={onBack} style={{ flex: 1, padding: 12, borderRadius: 8, border: '1px solid #ddd', background: '#fff', cursor: 'pointer' }}>
 Voltar
 </button>
 <button type="submit" style={{ flex: 2, padding: 12, borderRadius: 8, border: 'none', background: '#3498db', color: '#fff', cursor: 'pointer', fontWeight: 'bold' }}>
 Continuar
 </button>
 </div>
 </form>
 );
}
```

---

## Passo 3 -- Finalização

No último passo, o usuário define uma senha e aceita os termos. Ao concluir, o cadastro é enviado ao backend.

```jsx
function StepFinalizacao({ dados, onComplete, onBack }) {
 const [senha, setSenha] = useState('');
 const [confirmaSenha, setConfirmaSenha] = useState('');
 const [aceitaTermos, setAceitaTermos] = useState(false);
 const [erro, setErro] = useState('');

 function handleSubmit(e) {
 e.preventDefault();
 if (senha.length < 8) { setErro('A senha deve ter pelo menos 8 caracteres.'); return; }
 if (senha !== confirmaSenha) { setErro('As senhas nao coincidem.'); return; }
 if (!aceitaTermos) { setErro('Voce precisa aceitar os termos de uso.'); return; }
 onComplete({ ...dados, senha });
 }

 return (
 <form onSubmit={handleSubmit}>
 <h2>Crie sua conta</h2>

 <label style={{ display: 'block', marginBottom: 4 }}>Senha</label>
 <input
 type="password"
 value={senha}
 onChange={(e) => { setSenha(e.target.value); setErro(''); }}
 placeholder="Minimo 8 caracteres"
 style={{ width: '100%', padding: 12, marginBottom: 12, borderRadius: 8, border: '2px solid #ddd' }}
 />

 <label style={{ display: 'block', marginBottom: 4 }}>Confirmar senha</label>
 <input
 type="password"
 value={confirmaSenha}
 onChange={(e) => { setConfirmaSenha(e.target.value); setErro(''); }}
 placeholder="Repita a senha"
 style={{ width: '100%', padding: 12, marginBottom: 12, borderRadius: 8, border: '2px solid #ddd' }}
 />

 <label style={{ display: 'flex', alignItems: 'center', gap: 8, cursor: 'pointer' }}>
 <input type="checkbox" checked={aceitaTermos} onChange={(e) => setAceitaTermos(e.target.checked)} />
 Li e aceito os termos de uso e a politica de privacidade.
 </label>

 {erro && <p style={{ color: '#e74c3c', marginTop: 8 }}>{erro}</p>}

 <div style={{ display: 'flex', gap: 12, marginTop: 20 }}>
 <button type="button" onClick={onBack} style={{ flex: 1, padding: 12, borderRadius: 8, border: '1px solid #ddd', background: '#fff', cursor: 'pointer' }}>
 Voltar
 </button>
 <button type="submit" style={{ flex: 2, padding: 12, borderRadius: 8, border: 'none', background: '#2ecc71', color: '#fff', cursor: 'pointer', fontWeight: 'bold' }}>
 Criar conta
 </button>
 </div>
 </form>
 );
}
```

---

## Orquestrador do fluxo

O componente principal gerencia qual passo está ativo e passa os dados entre os passos.

```jsx
function OnboardingFlow() {
 const [step, setStep] = useState(0);
 const [dados, setDados] = useState({});

 return (
 <div style={{ maxWidth: 480, margin: '40px auto', padding: 24 }}>
 <Stepper currentStep={step} />

 {step === 0 && (
 <StepIdentificacao onNext={(d) => { setDados(d); setStep(1); }} />
 )}
 {step === 1 && (
 <StepConfirmacao
 dados={dados}
 onNext={(d) => { setDados(d); setStep(2); }}
 onBack={() => setStep(0)}
 />
 )}
 {step === 2 && (
 <StepFinalizacao
 dados={dados}
 onComplete={(d) => { console.log('Cadastro completo:', d); }}
 onBack={() => setStep(1)}
 />
 )}
 </div>
 );
}
```

---

## Métricas de sucesso do onboarding

Para avaliar a eficácia do fluxo, monitore as seguintes métricas:

- **Taxa de conclusão** -- percentual de usuários que iniciam o passo 1 e completam o passo 3. Alvo: acima de 70%.
- **Tempo médio por passo** -- tempo que o usuário leva em cada etapa. O passo 1 deve ser o mais rápido (menos de 10 segundos).
- **Taxa de abandono por passo** -- identifica onde os usuários desistem. Se o abandono é alto no passo 1, pode indicar problemas com a consulta de CPF.
- **Taxa de erro de CPF** -- percentual de CPFs inválidos inseridos. Se for alto, melhore as orientações visuais.

---

## Dicas para aumentar a conversão

### Explique por que precisa do CPF

Muitos usuários hesitam em informar o CPF. Adicione uma mensagem curta explicando o motivo: "Usamos seu CPF apenas para preencher seus dados automaticamente e agilizar o cadastro."

### Ofereça alternativa

Sempre ofereça a opção de preencher os dados manualmente, caso o usuário prefira não informar o CPF nesse momento. Isso respeita a autonomia do usuário e evita abandonos.

### Garantia de segurança

Inclua selos de segurança e uma nota sobre a LGPD próximos ao campo de CPF. A API da CPFHub.io opera em conformidade com a [LGPD](https://www.planalto.gov.br/ccivil_03/_ato2015-2018/2018/lei/l13709.htm), garantindo que os dados do usuário sejam tratados com segurança e apenas para a finalidade declarada.

---

## Perguntas frequentes

### O que é necessário para implementar validação de CPF neste contexto?
A validação de CPF exige uma chamada à API com o número do documento e a chave de autenticação. A CPFHub.io retorna o status do CPF, nome do titular e data de nascimento em menos de 200ms, permitindo a verificação em tempo real durante o cadastro ou transação.

### A API CPFHub.io funciona para todos os volumes de consulta?
Sim. O plano gratuito oferece 50 consultas por mês sem cartão de crédito — ideal para testes e projetos pequenos. Para volumes maiores, o plano Pro inclui 1.000 consultas mensais por R$149. Se o limite for ultrapassado, a API não bloqueia: cobra R$0,15 por consulta adicional.

### Como garantir conformidade com a LGPD ao usar uma API de CPF?
Use o CPF apenas para a finalidade declarada ao titular, armazene apenas o necessário (não guarde o CPF cru se um token bastar), implemente controle de acesso aos logs de consulta e documente a base legal para o tratamento. A [ANPD](https://www.gov.br/anpd) orienta que dados de identificação devem ser tratados com o princípio da necessidade.

### Quanto tempo leva para integrar a API CPFHub.io?
A integração básica leva menos de 30 minutos: crie uma conta em cpfhub.io, gere a API key no painel e faça uma chamada GET para `https://api.cpfhub.io/cpf/{CPF}` com o header `x-api-key`. A documentação inclui exemplos em Python, Node.js, PHP, Java e outras linguagens.

### Leia também

- [Diferença entre validação de CPF e consulta de CPF: quando usar cada uma](https://cpfhub.io/blog/diferenca-entre-validacao-de-cpf-e-consulta-de-cpf-quando-usar-cada-uma)
- [API de CPF grátis para desenvolvedores: como começar em 5 minutos](https://cpfhub.io/blog/api-cpf-gratis-desenvolvedores-comecar-5-minutos)
- [Onboarding digital em fintechs: como validar CPF em menos de 30 segundos](https://cpfhub.io/blog/onboarding-digital-em-fintechs-como-validar-cpf-em-menos-de-30-segundos)
- [KYC no Brasil: quais setores são obrigados a validar CPF por lei](https://cpfhub.io/blog/kyc-no-brasil-quais-setores-sao-obrigados-a-validar-cpf-por-lei)

---

## Conclusão

Um fluxo de onboarding com verificação de CPF em três passos equilibra segurança, praticidade e experiência do usuário. Ao utilizar a API da CPFHub.io, o preenchimento automático de nome, data de nascimento e gênero elimina os campos mais tediosos do formulário — reduzindo o atrito e aumentando a taxa de conclusão.

Com tempo de resposta médio de aproximadamente 900ms, 99,9% de uptime e conformidade com a LGPD, a CPFHub.io é a escolha ideal para integrar verificação de CPF ao seu fluxo de onboarding.

Cadastre-se em [cpfhub.io](https://www.cpfhub.io/) — 50 consultas mensais gratuitas, sem cartão de crédito — e comece hoje mesmo.

