# Métricas de UX para monitorar em fluxos de verificação de CPF

> Descubra quais métricas de UX monitorar em fluxos de verificação de CPF para identificar problemas e otimizar a experiência do usuário.

**Publicado:** 21/03/2026
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/metricas-de-ux-para-monitorar-em-fluxos-de-verificacao-de-cpf

---


As métricas mais críticas para monitorar em fluxos de verificação de CPF são: taxa de conclusão (meta: acima de 80%), taxa de erro na validação (meta: abaixo de 10%), tempo médio de preenchimento (meta: menos de 10 segundos) e taxa de abandono após o campo CPF (meta: abaixo de 20%). Quando a taxa de erro ultrapassa 15%, o problema quase sempre está na interface — não no usuário. Sem métricas instrumentadas, não há como distinguir atrito de desistência nem priorizar o que realmente impacta conversão.

---

## As cinco categorias de métricas

As métricas de UX para fluxos de CPF se organizam em cinco categorias:

### 1. Eficácia

O usuário consegue completar a tarefa? Métricas: taxa de conclusão, taxa de erro.

### 2. Eficiência

Quanto esforço o usuário precisa? Métricas: tempo de preenchimento, número de tentativas.

### 3. Satisfação

O usuário teve uma boa experiência? Métricas: NPS, taxa de abandono, feedback qualitativo.

### 4. Performance técnica

O sistema respondeu adequadamente? Métricas: tempo de resposta da API, taxa de timeout.

### 5. Acessibilidade

Todos os usuários conseguem usar? Métricas: taxa de conclusão por dispositivo, uso de teclado vs. mouse.

---

## Implementando coleta de métricas

Vamos criar um sistema leve de coleta de métricas que não impacta a performance da aplicação.

```javascript
class CPFMetrics {
 constructor() {
 this.sessao = this.gerarId();
 this.eventos = [];
 this.timestamps = {};
 }

 gerarId() {
 return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
 }

 marcarInicio(evento) {
 this.timestamps[evento] = performance.now();
 this.registrar(`${evento}_inicio`);
 }

 marcarFim(evento, dados = {}) {
 const inicio = this.timestamps[evento];
 const duracao = inicio ? Math.round(performance.now() - inicio) : null;
 this.registrar(`${evento}_fim`, { ...dados, duracao_ms: duracao });
 delete this.timestamps[evento];
 }

 registrar(tipo, dados = {}) {
 this.eventos.push({
 sessao: this.sessao,
 tipo,
 dados,
 timestamp: new Date().toISOString(),
 dispositivo: this.getDispositivo(),
 viewport: `${window.innerWidth}x${window.innerHeight}`
 });
 }

 getDispositivo() {
 const largura = window.innerWidth;
 if (largura < 768) return 'mobile';
 if (largura < 1024) return 'tablet';
 return 'desktop';
 }

 async enviar() {
 if (this.eventos.length === 0) return;

 const eventosPendentes = [...this.eventos];
 this.eventos = [];

 // Usar sendBeacon para nao bloquear o navegador
 if (navigator.sendBeacon) {
 navigator.sendBeacon(
 '/api/analytics/cpf-metrics',
 JSON.stringify(eventosPendentes)
 );
 } else {
 const controller = new AbortController();
 const timeoutId = setTimeout(() => controller.abort(), 5000);

 try {
 await fetch('/api/analytics/cpf-metrics', {
 method: 'POST',
 headers: { 'Content-Type': 'application/json' },
 body: JSON.stringify(eventosPendentes),
 signal: controller.signal
 });
 clearTimeout(timeoutId);
 } catch (err) {
 clearTimeout(timeoutId);
 // Re-adicionar eventos que falharam
 this.eventos = [...eventosPendentes, ...this.eventos];
 }
 }
 }
}

const metrics = new CPFMetrics();
```

---

## Métrica 1 -- Tempo de preenchimento do campo

O tempo que o usuário leva desde o primeiro toque no campo até completar os 11 dígitos.

```javascript
const cpfInput = document.getElementById('cpf');

cpfInput.addEventListener('focus', () => {
 metrics.marcarInicio('preenchimento_cpf');
});

cpfInput.addEventListener('input', () => {
 const digits = cpfInput.value.replace(/\D/g, '');

 if (digits.length === 11) {
 metrics.marcarFim('preenchimento_cpf', {
 metodo: 'digitacao',
 valido: validarCPF(digits)
 });
 }
});

cpfInput.addEventListener('paste', () => {
 metrics.registrar('cpf_colado');
});
```

**Referências:**
- Menor que 5 segundos: excelente.
- Entre 5 e 15 segundos: aceitável.
- Acima de 15 segundos: possível problema de UX.

---

## Métrica 2 -- Taxa de erro na validação

O percentual de tentativas com CPF inválido revela se a interface está guiando o usuário adequadamente.

```javascript
let tentativasCPF = 0;
let errosCPF = 0;

function validarEMonitorar(digits) {
 tentativasCPF++;

 if (digits.length !== 11) {
 errosCPF++;
 metrics.registrar('cpf_erro', { tipo: 'incompleto', digitos: digits.length });
 return false;
 }

 if (/^(\d)\1{10}$/.test(digits)) {
 errosCPF++;
 metrics.registrar('cpf_erro', { tipo: 'todos_iguais' });
 return false;
 }

 const valido = validarCPF(digits);
 if (!valido) {
 errosCPF++;
 metrics.registrar('cpf_erro', { tipo: 'digito_verificador' });
 } else {
 metrics.registrar('cpf_valido', {
 tentativas_ate_sucesso: tentativasCPF,
 taxa_erro: Math.round((errosCPF / tentativasCPF) * 100)
 });
 }

 return valido;
}

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

---

## Métrica 3 -- Tempo de resposta da API

O tempo entre o envio da requisição e o recebimento da resposta é essencial para avaliar a performance percebida.

```javascript
async function consultarCPFComMetricas(digits) {
 metrics.marcarInicio('api_consulta');

 const controller = new AbortController();
 const timeoutId = setTimeout(() => controller.abort(), 10000);

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

 metrics.marcarFim('api_consulta', {
 status: res.status,
 sucesso: json.success,
 encontrado: json.success && json.data ? true : false
 });

 return json;
 } catch (err) {
 clearTimeout(timeoutId);
 metrics.marcarFim('api_consulta', {
 erro: true,
 tipo_erro: err.name === 'AbortError' ? 'timeout' : 'rede'
 });
 throw err;
 }
}
```

---

## Métrica 4 -- Taxa de abandono

Monitore quando o usuário abandona o fluxo em cada etapa.

```javascript
// Detectar abandono: o usuario focou no campo de CPF mas saiu da pagina
// sem completar a verificacao
let cpfFoiFocado = false;
let cpfFoiVerificado = false;

cpfInput.addEventListener('focus', () => {
 cpfFoiFocado = true;
});

// Marcar como verificado quando a API retornar sucesso
function marcarVerificado() {
 cpfFoiVerificado = true;
 metrics.registrar('cpf_verificacao_completa');
}

// Detectar saida da pagina
window.addEventListener('beforeunload', () => {
 if (cpfFoiFocado && !cpfFoiVerificado) {
 const digits = cpfInput.value.replace(/\D/g, '');
 metrics.registrar('cpf_abandono', {
 digitos_preenchidos: digits.length,
 etapa: digits.length === 0 ? 'nao_iniciou'
 : digits.length < 11 ? 'incompleto'
 : 'completo_mas_nao_verificou'
 });
 }
 metrics.enviar();
});

// Detectar abandono do campo (focus em outro campo)
cpfInput.addEventListener('blur', () => {
 const digits = cpfInput.value.replace(/\D/g, '');
 if (digits.length > 0 && digits.length < 11) {
 metrics.registrar('cpf_blur_incompleto', {
 digitos_preenchidos: digits.length
 });
 }
});
```

---

## Métrica 5 -- Métricas por dispositivo

A mesma interface pode ter performance muito diferente em mobile vs. desktop. Segmentar as métricas por dispositivo revela problemas específicos.

```javascript
function coletarMetricasDispositivo() {
 const info = {
 dispositivo: metrics.getDispositivo(),
 viewport: `${window.innerWidth}x${window.innerHeight}`,
 touch: 'ontouchstart' in window,
 userAgent: navigator.userAgent,
 conexao: navigator.connection
 ? {
 tipo: navigator.connection.effectiveType,
 downlink: navigator.connection.downlink,
 rtt: navigator.connection.rtt
 }
 : null
 };

 metrics.registrar('dispositivo_info', info);
}

// Coletar ao carregar a pagina
window.addEventListener('load', coletarMetricasDispositivo);
```

---

## Dashboard de métricas

Para visualizar as métricas coletadas, crie um endpoint de agregação no backend e um dashboard simples.

```javascript
// Exemplo de agregação no backend (Node.js)
function agregarMetricas(eventos) {
 const metricas = {
 total_sessoes: new Set(eventos.map(e => e.sessao)).size,
 total_verificacoes: eventos.filter(e => e.tipo === 'cpf_verificacao_completa').length,
 total_abandonos: eventos.filter(e => e.tipo === 'cpf_abandono').length,
 taxa_conclusao: 0,
 tempo_medio_preenchimento: 0,
 tempo_medio_api: 0,
 taxa_erro: 0,
 erros_por_tipo: {},
 por_dispositivo: {}
 };

 // Taxa de conclusao
 const sessoes = metricas.total_sessoes;
 if (sessoes > 0) {
 metricas.taxa_conclusao = Math.round(
 (metricas.total_verificacoes / sessoes) * 100
 );
 }

 // Tempo medio de preenchimento
 const preenchimentos = eventos
 .filter(e => e.tipo === 'preenchimento_cpf_fim' && e.dados.duracao_ms)
 .map(e => e.dados.duracao_ms);
 if (preenchimentos.length > 0) {
 metricas.tempo_medio_preenchimento = Math.round(
 preenchimentos.reduce((a, b) => a + b, 0) / preenchimentos.length
 );
 }

 // Tempo medio da API
 const apiCalls = eventos
 .filter(e => e.tipo === 'api_consulta_fim' && e.dados.duracao_ms && !e.dados.erro)
 .map(e => e.dados.duracao_ms);
 if (apiCalls.length > 0) {
 metricas.tempo_medio_api = Math.round(
 apiCalls.reduce((a, b) => a + b, 0) / apiCalls.length
 );
 }

 // Taxa de erro
 const totalTentativas = eventos.filter(e =>
 e.tipo === 'cpf_erro' || e.tipo === 'cpf_valido'
 ).length;
 const totalErros = eventos.filter(e => e.tipo === 'cpf_erro').length;
 if (totalTentativas > 0) {
 metricas.taxa_erro = Math.round((totalErros / totalTentativas) * 100);
 }

 // Erros por tipo
 eventos
 .filter(e => e.tipo === 'cpf_erro')
 .forEach(e => {
 const tipo = e.dados.tipo || 'desconhecido';
 metricas.erros_por_tipo[tipo] = (metricas.erros_por_tipo[tipo] || 0) + 1;
 });

 return metricas;
}
```

---

## Alertas e thresholds

Configure alertas automáticos quando as métricas ultrapassarem thresholds críticos.

| Métrica | Threshold de alerta | Ação sugerida |
|---|---|---|
| Taxa de conclusão | Abaixo de 60% | Revisar UX do campo de CPF |
| Tempo de preenchimento | Acima de 20s | Verificar máscara e teclado |
| Tempo da API | Acima de 3s (p95) | Verificar rede e infraestrutura |
| Taxa de erro | Acima de 20% | Melhorar mensagens de orientação |
| Taxa de abandono | Acima de 40% | Simplificar o fluxo |
| Taxa de timeout | Acima de 2% | Aumentar timeout ou verificar conectividade |

---

## Testes A/B com métricas

As métricas coletadas são a base para testes A/B. Por exemplo, para testar se a validação automática (ao completar 11 dígitos) converte melhor do que a validação no blur:

```javascript
function getVariante() {
 // Distribuir 50/50 entre variantes
 const stored = localStorage.getItem('cpf_variante');
 if (stored) return stored;
 const variante = Math.random() < 0.5 ? 'auto' : 'blur';
 localStorage.setItem('cpf_variante', variante);
 return variante;
}

const variante = getVariante();
metrics.registrar('ab_test', { variante });

if (variante === 'auto') {
 // Validar ao completar 11 digitos
 cpfInput.addEventListener('input', () => {
 const digits = cpfInput.value.replace(/\D/g, '');
 if (digits.length === 11) validarEConsultar(digits);
 });
} else {
 // Validar no blur
 cpfInput.addEventListener('blur', () => {
 const digits = cpfInput.value.replace(/\D/g, '');
 if (digits.length === 11) validarEConsultar(digits);
 });
}
```

Após duas semanas de coleta, compare a taxa de conclusão e o tempo médio entre as variantes para decidir qual implementar permanentemente. O [Google's HEART framework](https://research.google/pubs/measuring-the-user-experience-on-a-large-scale-user-research-on-google-maps/) — Happiness, Engagement, Adoption, Retention, Task Success — é uma referência consagrada para estruturar métricas de UX em fluxos de formulário.

---

## Perguntas frequentes

### Qual taxa de conclusão é considerada boa em fluxos de verificação de CPF?
Acima de 80% é o alvo para fluxos de CPF bem projetados. Taxas entre 60% e 80% indicam atrito que vale investigar — geralmente erros de máscara, mensagens pouco claras ou posicionamento inadequado do campo. Abaixo de 60%, o fluxo está bloqueando usuários legítimos e requer revisão urgente de UX.

### Como identificar se o abandono ocorre por problema de UX ou por desistência do usuário?
Cruze a métrica de abandono com o número de dígitos preenchidos no momento da saída. Se a maioria sai com 0 dígitos, o abandono é intencional. Se sai com 3–8 dígitos, há frustração no preenchimento — geralmente máscara conflitante com o teclado do celular. Se sai com 11 dígitos sem concluir, o problema está na etapa de validação ou no feedback de erro.

### Com qual frequência devo revisar as métricas de UX do fluxo de CPF?
Monitore em tempo real os alertas de threshold (taxa de erro, tempo de API, taxa de abandono). Faça revisão semanal das tendências e análise mensal comparando com períodos anteriores. Qualquer deploy novo que altere o campo de CPF ou a integração com a API deve ser acompanhado de monitoramento intensivo nas primeiras 48 horas.

### Como segmentar as métricas para identificar problemas específicos em mobile?
Use a propriedade `dispositivo` registrada em cada evento para filtrar os dados. Compare taxa de conclusão, tempo de preenchimento e taxa de erro separadamente para mobile, tablet e desktop. Em geral, fluxos com CPF têm performance 15–30% pior em mobile — se a diferença for maior, revise o tamanho do campo, o tipo de teclado ativado (`inputmode="numeric"`) e o comportamento da máscara em telas pequenas.

### Leia também

- [Como pedir CPF no checkout sem espantar o cliente](https://cpfhub.io/blog/como-pedir-cpf-no-checkout-sem-espantar-o-cliente)
- [SLA de API de CPF: níveis de disponibilidade](https://cpfhub.io/blog/sla-api-cpf-niveis-disponibilidade)
- [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)
- [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)

---

## Conclusão

Monitorar métricas de UX em fluxos de verificação de CPF transforma suposições em decisões baseadas em dados. As cinco categorias -- eficácia, eficiência, satisfação, performance técnica e acessibilidade -- cobrem todos os aspectos da experiência e revelam problemas que testes manuais não conseguem identificar. Um campo de CPF com taxa de erro de 20% parece funcional no QA, mas está silenciosamente bloqueando um em cada cinco usuários reais.

A API da [**CPFHub.io**](https://www.cpfhub.io/) responde em ~300ms, o que significa que ela dificilmente será o gargalo das suas métricas de tempo de API — o problema, quando existe, costuma estar na lógica de frontend ou na infraestrutura do servidor intermediário. Comece a coletar métricas hoje, defina seus thresholds e revise semanalmente. Crie sua conta gratuita em [cpfhub.io](https://www.cpfhub.io/) e valide CPFs com 50 consultas mensais sem cartão de crédito.

