# Como implementar debounce em campos de CPF que consultam API em tempo real

> Aprenda a implementar debounce em campos de CPF que consultam API em tempo real. Evite requisições excessivas e melhore a experiência do usuário.

**Publicado:** 18/04/2025
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/como-implementar-debounce-em-campos-de-cpf-que-consultam-api-em-tempo-real

---


Implementar debounce em campos de CPF que consultam API em tempo real significa atrasar a requisição até o usuário parar de digitar, evitando disparar dezenas de chamadas desnecessárias a cada tecla. Com um delay de 500–600ms e validação sintática no front-end, é possível reduzir o consumo de créditos da API em até 90% sem prejudicar a experiência do usuário.

## Introdução

Formulários que consultam uma API de CPF em tempo real — enquanto o usuário digita — oferecem uma experiência dinâmica e ágil. No entanto, sem o uso de debounce, cada tecla pressionada pode disparar uma requisição à API, resultando em dezenas de chamadas desnecessárias que consomem créditos e sobrecarregam o servidor. Este guia mostra como implementar debounce em JavaScript puro e React, com a consulta sendo feita no backend.

## O que é debounce

Debounce é uma técnica que atrasa a execução de uma função até que um período de inatividade tenha passado. Em vez de executar a função a cada evento (como cada tecla digitada), o debounce aguarda o usuário parar de digitar por um intervalo definido antes de executar a ação.

### Sem debounce

Quando o usuário digita o CPF "12345678900", o campo dispara 11 requisições:

```
Digitou "1" -> Requisição 1
Digitou "12" -> Requisição 2
Digitou "123" -> Requisição 3
...
Digitou "12345678900" -> Requisição 11
```

Resultado: 10 requisições desperdiçadas, apenas a última é útil.

### Com debounce (500ms)

O campo aguarda 500ms após a última tecla antes de disparar a requisição:

```
Digitou "1" -> Aguarda 500ms...
Digitou "12" -> Reinicia timer, aguarda 500ms...
Digitou "123" -> Reinicia timer, aguarda 500ms...
...
Digitou "12345678900" -> Aguarda 500ms... -> Requisição 1 (única)
```

Resultado: 1 requisição, economia de 10 créditos.

## Implementação em JavaScript puro

### Função de debounce

```javascript
function debounce(fn, delay) {
 let timerId = null;

 return function (...args) {
 if (timerId) {
 clearTimeout(timerId);
 }

 timerId = setTimeout(() => {
 fn.apply(this, args);
 timerId = null;
 }, delay);
 };
}
```

### Aplicando ao campo de CPF

```javascript
const campoCPF = document.getElementById('cpf-input');
const resultadoDiv = document.getElementById('resultado');

async function consultarCPFNoBackend(cpf) {
 // A consulta à API deve ser feita pelo backend
 const controller = new AbortController();
 const timeoutId = setTimeout(() => controller.abort(), 10000);

 try {
 const response = await fetch(`/api/consultar-cpf?cpf=${cpf}`, {
 signal: controller.signal
 });

 clearTimeout(timeoutId);
 const dados = await response.json();

 if (dados.success) {
 resultadoDiv.textContent = `Nome: ${dados.data.name}`;
 resultadoDiv.className = 'sucesso';
 } else {
 resultadoDiv.textContent = 'CPF não encontrado.';
 resultadoDiv.className = 'erro';
 }
 } catch (error) {
 clearTimeout(timeoutId);
 resultadoDiv.textContent = 'Erro ao consultar CPF.';
 resultadoDiv.className = 'erro';
 }
}

function validarEConsultar(event) {
 const cpf = event.target.value.replace(/\D/g, '');

 if (cpf.length < 11) {
 resultadoDiv.textContent = '';
 return;
 }

 if (cpf.length === 11) {
 consultarCPFNoBackend(cpf);
 }
}

// Debounce de 600ms
campoCPF.addEventListener('input', debounce(validarEConsultar, 600));
```

### Endpoint no backend (Express)

```javascript
const express = require('express');
const app = express();

app.get('/api/consultar-cpf', async (req, res) => {
 const cpf = req.query.cpf;

 if (!cpf || cpf.length !== 11) {
 return res.status(400).json({ error: 'CPF inválido' });
 }

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

 try {
 const response = await fetch(
 `https://api.cpfhub.io/cpf/${cpf}`,
 {
 headers: {
 'x-api-key': process.env.CPFHUB_API_KEY,
 'Accept': 'application/json'
 },
 signal: controller.signal
 }
 );

 clearTimeout(timeoutId);
 const dados = await response.json();
 res.json(dados);

 } catch (error) {
 clearTimeout(timeoutId);
 res.status(500).json({ error: 'Falha na consulta' });
 }
});

app.listen(3000);
```

## Implementação em React

```javascript
import { useState, useCallback, useRef } from 'react';

function useDebounce(fn, delay) {
 const timerRef = useRef(null);

 return useCallback((...args) => {
 if (timerRef.current) {
 clearTimeout(timerRef.current);
 }

 timerRef.current = setTimeout(() => {
 fn(...args);
 }, delay);
 }, [fn, delay]);
}

function CampoCPF() {
 const [cpf, setCpf] = useState('');
 const [resultado, setResultado] = useState(null);
 const [carregando, setCarregando] = useState(false);

 const consultarCPF = useCallback(async (valor) => {
 const cpfLimpo = valor.replace(/\D/g, '');
 if (cpfLimpo.length !== 11) {
 setResultado(null);
 return;
 }

 setCarregando(true);

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

 const response = await fetch(
 `/api/consultar-cpf?cpf=${cpfLimpo}`,
 { signal: controller.signal }
 );

 clearTimeout(timeoutId);
 const dados = await response.json();
 setResultado(dados);
 } catch (error) {
 setResultado({ error: 'Falha na consulta' });
 } finally {
 setCarregando(false);
 }
 }, []);

 const consultarComDebounce = useDebounce(consultarCPF, 600);

 const handleChange = (e) => {
 const valor = e.target.value;
 setCpf(valor);
 consultarComDebounce(valor);
 };

 return (
 <div>
 <input
 type="text"
 value={cpf}
 onChange={handleChange}
 placeholder="Digite o CPF"
 maxLength={14}
 />
 {carregando && <p>Consultando...</p>}
 {resultado?.success && <p>Nome: {resultado.data.name}</p>}
 {resultado?.error && <p>Erro: {resultado.error}</p>}
 </div>
 );
}
```

## Escolhendo o delay ideal

O delay do debounce deve equilibrar responsividade com economia de requisições:

| Delay | Comportamento | Quando usar |
| --- | --- | --- |
| 300ms | Muito responsivo, mais requisições | Campos com autocomplete |
| 500-600ms | Equilíbrio ideal | Campos de CPF (recomendado) |
| 1000ms | Menos responsivo, menos requisições | Processos batch ou de baixa urgência |

Para campos de CPF, 500-600ms é o valor recomendado. O usuário digita os 11 dígitos em aproximadamente 3-5 segundos, e o debounce disparará a consulta logo após ele terminar de digitar.

## Combinando debounce com validação sintática

Antes de enviar a requisição ao backend, valide o CPF sintaticamente no front-end para evitar chamadas desnecessárias:

```javascript
function validarCPFSintatico(cpf) {
 cpf = cpf.replace(/\D/g, '');
 if (cpf.length !== 11) return false;
 if (/^(\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]);
}

const consultarComDebounce = debounce((valor) => {
 const cpfLimpo = valor.replace(/\D/g, '');

 if (cpfLimpo.length !== 11) return;

 // Validar formato antes de consultar
 if (!validarCPFSintatico(cpfLimpo)) {
 resultadoDiv.textContent = 'CPF com formato inválido.';
 return;
 }

 consultarCPFNoBackend(cpfLimpo);
}, 600);
```

## Boas práticas

* **Sempre consulte a API pelo backend** -- Nunca exponha a chave de API no front-end. O debounce controla o momento da chamada, mas a requisição deve partir do servidor.

* **Mostre indicador de carregamento** -- Enquanto a consulta está em andamento, exiba um spinner ou texto "Consultando..." para que o usuário saiba que algo está acontecendo.

* **Cancele requisições anteriores** -- Se o usuário digitar um novo CPF antes da resposta chegar, cancele a requisição anterior usando AbortController.

* **Valide sintaticamente no front-end** -- Rejeite CPFs com formato inválido antes de enviar ao backend.

* **Use máscara de input** -- Formate o campo como XXX.XXX.XXX-XX para facilitar a digitação e prevenir erros.

## Perguntas frequentes

### Qual o delay de debounce ideal para campos de CPF?

Para campos de CPF, o intervalo de 500–600ms é o equilíbrio ideal entre responsividade e economia de requisições. O usuário leva em média 3–5 segundos para digitar 11 dígitos, então o debounce dispara naturalmente logo após ele concluir. Valores abaixo de 300ms aumentam o consumo de créditos; acima de 1.000ms deixam o formulário lento.

### A API CPFHub.io bloqueia quando o limite do plano é atingido?

Não. A CPFHub.io nunca retorna HTTP 429 nem bloqueia requisições. Ao ultrapassar o limite do plano, cada consulta extra é cobrada a R$0,15. O plano gratuito oferece 50 consultas/mês sem cartão de crédito; o plano Pro inclui 1.000 consultas por R$149/mês com excedente a 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.

### Devo validar o CPF sintaticamente antes de chamar a API?

Sim, sempre. A validação sintática no front-end — verificação dos dígitos verificadores pelo algoritmo da Receita Federal — descarta CPFs inválidos antes mesmo de chegar ao backend, economizando requisições e melhorando a UX com feedback imediato ao usuário.

### Leia também

- [Como validar CPF no frontend com React e API REST](https://cpfhub.io/blog/como-validar-cpf-no-frontend-com-react-e-api-rest)
- [Como implementar validação de CPF em tempo real sem prejudicar a performance](https://cpfhub.io/blog/como-implementar-validacao-de-cpf-em-tempo-real-sem-prejudicar-a-performance)
- [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)
- [Guia de headers HTTP obrigatórios para consumir API de CPF corretamente](https://cpfhub.io/blog/guia-de-headers-http-obrigatorios-para-consumir-api-de-cpf-corretamente)

---

## Conclusão

O debounce é uma técnica simples mas essencial para campos de CPF que consultam API em tempo real. Ao aguardar o usuário terminar de digitar antes de disparar a requisição, ele economiza créditos de API e mantém a experiência fluida. Combinado com validação sintática no front-end e consulta no backend, o resultado é uma integração eficiente e segura.

Cadastre-se em [cpfhub.io](https://www.cpfhub.io/) — 50 consultas mensais gratuitas, sem cartão de crédito — e implemente debounce em seus formulários de CPF em menos de 30 minutos.

