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.

Redação CPFHub.io
Redação CPFHub.io
··11 min de leitura
Onboarding de usuário com verificação de CPF: flow de três 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.

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.

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.

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.

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.

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, 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 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.


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 — 50 consultas mensais gratuitas, sem cartão de crédito — e comece hoje mesmo.

CPFHub.io

Pronto para integrar a API?

50 consultas gratuitas para testar agora. Sem cartão de crédito. Acesso imediato à documentação.

Redação CPFHub.io

Sobre a redação

Redação CPFHub.io

Time editorial especializado em APIs de CPF, identidade digital e compliance no mercado brasileiro. Produzimos guias técnicos, análises regulatórias e tutoriais sobre LGPD e KYC para desenvolvedores e líderes de produto.

WhatsAppFale conosco via WhatsApp