# Como integrar validação de CPF em aplicações Remix com loaders

> Aprenda a integrar a API de consulta de CPF da CPFHub.io em aplicações Remix usando loaders e actions para validação server-side.

**Publicado:** 10/04/2026
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/como-integrar-validacao-de-cpf-em-aplicacoes-remix-com-loaders

---


Para integrar validação de CPF em aplicações Remix, use um módulo `.server.ts` para centralizar a chamada à API da CPFHub.io com a chave de autenticação no header `x-api-key`, depois exponha os dados via `loader` (consulta por URL) ou via `action` (formulário POST). A chave nunca chega ao navegador, e o log de cada consulta fica disponível para auditoria no servidor.

## 1. Pré-requisitos

* **Remix** (v2+) configurado com `npx create-remix@latest`.

* A chave de API da [**CPFHub.io**](https://www.cpfhub.io/)

* Node.js 18+ (para suporte nativo a fetch).

---

## 2. Configure a variável de ambiente

Crie o arquivo `.env` na raiz do projeto:

```
CPFHUB_API_KEY=SUA_CHAVE_DE_API
```

---

## 3. Crie o serviço de consulta

Crie um módulo utilitário para centralizar a chamada à API:

```typescript
// app/services/cpfhub.server.ts
export interface CpfData {
 cpf: string;
 name: string;
 nameUpper: string;
 gender: string;
 birthDate: string;
 day: number;
 month: number;
 year: number;
}

export interface CpfResponse {
 success: boolean;
 data: CpfData;
}

export async function consultarCpf(cpf: string): Promise<CpfResponse> {
 const cpfLimpo = cpf.replace(/\D/g, '');

 if (cpfLimpo.length !== 11) {
 throw new Error('CPF deve conter 11 dígitos');
 }

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

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

 clearTimeout(timeoutId);

 if (!response.ok) {
 if (response.status === 401) throw new Error('Chave de API inválida');
 throw new Error(`Erro HTTP ${response.status}`);
 }

 return await response.json();
 } catch (error) {
 clearTimeout(timeoutId);
 throw error;
 }
}
```

O sufixo `.server.ts` garante que esse código nunca será enviado ao navegador.

---

## 4. Validação via loader (consulta por URL)

Crie uma rota que recebe o CPF via parâmetro de URL e retorna os dados validados:

```typescript
// app/routes/cpf.$cpf.tsx
import { json, type LoaderFunctionArgs } from '@remix-run/node';
import { useLoaderData } from '@remix-run/react';
import { consultarCpf } from '~/services/cpfhub.server';

export async function loader({ params }: LoaderFunctionArgs) {
 const cpf = params.cpf;

 if (!cpf) {
 throw new Response('CPF não informado', { status: 400 });
 }

 try {
 const resultado = await consultarCpf(cpf);
 return json(resultado);
 } catch (error) {
 throw new Response(
 error instanceof Error ? error.message : 'Erro na consulta',
 { status: 502 }
 );
 }
}

export default function CpfPage() {
 const resultado = useLoaderData<typeof loader>();

 return (
 <div>
 <h2>Resultado da validação</h2>
 {resultado.success ? (
 <dl>
 <dt>CPF</dt>
 <dd>{resultado.data.cpf}</dd>
 <dt>Nome</dt>
 <dd>{resultado.data.name}</dd>
 <dt>Gênero</dt>
 <dd>{resultado.data.gender === 'M' ? 'Masculino' : 'Feminino'}</dd>
 <dt>Data de nascimento</dt>
 <dd>{resultado.data.birthDate}</dd>
 </dl>
 ) : (
 <p>CPF não encontrado.</p>
 )}
 </div>
 );
}
```

Acesse `http://localhost:3000/cpf/12345678900` para testar.

---

## 5. Validação via action (formulário)

Para cenários com formulário de entrada, use uma **action**:

```typescript
// app/routes/validar-cpf.tsx
import { json, type ActionFunctionArgs } from '@remix-run/node';
import { Form, useActionData } from '@remix-run/react';
import { consultarCpf, type CpfResponse } from '~/services/cpfhub.server';

interface ActionData {
 resultado?: CpfResponse;
 error?: string;
}

export async function action({ request }: ActionFunctionArgs) {
 const formData = await request.formData();
 const cpf = formData.get('cpf') as string;

 if (!cpf) {
 return json<ActionData>({ error: 'CPF é obrigatório' }, { status: 400 });
 }

 try {
 const resultado = await consultarCpf(cpf);
 return json<ActionData>({ resultado });
 } catch (error) {
 return json<ActionData>({
 error: error instanceof Error ? error.message : 'Erro na consulta'
 }, { status: 502 });
 }
}

export default function ValidarCpfPage() {
 const data = useActionData<typeof action>();

 return (
 <div>
 <h2>Validar CPF</h2>

 <Form method="post">
 <label htmlFor="cpf">CPF:</label>
 <input
 type="text"
 id="cpf"
 name="cpf"
 placeholder="Digite o CPF"
 maxLength={14}
 required
 />
 <button type="submit">Validar</button>
 </Form>

 {data?.error && <p style={{ color: 'red' }}>{data.error}</p>}

 {data?.resultado?.success && (
 <dl>
 <dt>Nome</dt>
 <dd>{data.resultado.data.name}</dd>
 <dt>CPF</dt>
 <dd>{data.resultado.data.cpf}</dd>
 <dt>Data de nascimento</dt>
 <dd>{data.resultado.data.birthDate}</dd>
 </dl>
 )}
 </div>
 );
}
```

---

## 6. Exemplo de resposta da API

A API da [**CPFHub.io**](https://www.cpfhub.io/) retorna um JSON estruturado com os dados do titular conforme registrado na Receita Federal:

```json
{
 "success": true,
 "data": {
 "cpf": "12345678900",
 "name": "João da Silva",
 "nameUpper": "JOÃO DA SILVA",
 "gender": "M",
 "birthDate": "15/06/1990",
 "day": 15,
 "month": 6,
 "year": 1990
 }
}
```

---

## 7. Tratamento de erros com ErrorBoundary

O Remix permite tratar erros de loader e action com ErrorBoundary:

```typescript
// Adicione no mesmo arquivo da rota
export function ErrorBoundary() {
 return (
 <div>
 <h2>Erro na validação</h2>
 <p>Não foi possível consultar o CPF. Tente novamente em alguns instantes.</p>
 </div>
 );
}
```

---

## 8. Boas práticas

* **Sufixo .server.ts** — Use para módulos que contêm a chave de API, garantindo que o código nunca chegue ao cliente.

* **Timeout** — O serviço usa `AbortController` com 5 segundos de timeout para evitar loaders travados. A latência média da API é de ~900ms; dimensione o timeout com margem.

* **Validação local** — Valide o formato do CPF (11 dígitos) antes de chamar a API para economizar consultas.

* **ErrorBoundary** — Implemente ErrorBoundary em todas as rotas para exibir mensagens amigáveis ao usuário.

* **Cota e excedente** — O plano gratuito da CPFHub.io inclui 50 consultas por mês. Ao ultrapassar o limite, a API não bloqueia: cada consulta extra custa R$ 0,15. Para volumes maiores, o plano Pro oferece 1.000 consultas/mês por R$ 149.

---

## Perguntas frequentes

### Como o Remix mantém a chave de API segura no servidor?

O sufixo `.server.ts` faz o Remix excluir automaticamente esse módulo do bundle do cliente durante o build. Isso garante que `process.env.CPFHUB_API_KEY` e a lógica de chamada à API jamais cheguem ao navegador. Qualquer tentativa de importar um módulo `.server.ts` em código de cliente resulta em erro de build antes do deploy.

### Qual a diferença entre usar loader e action para validar CPF no Remix?

O `loader` é executado em requisições GET e é ideal quando o CPF vem como parâmetro de URL — por exemplo, em rotas de perfil ou verificação de cadastro. A `action` é executada em submissões de formulário (POST) e é a abordagem certa quando o usuário digita o CPF em um campo. Ambos rodam exclusivamente no servidor, portanto a chave de API nunca fica exposta.

### Quanto tempo a API leva para responder e como isso afeta o loader?

A API da CPFHub.io tem latência média de ~900ms. O loader do Remix aguarda a resolução da promessa antes de renderizar a página, então configure um timeout razoável — o exemplo acima usa 5 segundos via `AbortController`. Para não penalizar a UX em consultas lentas, considere usar `defer` do Remix para carregar os dados de CPF em paralelo com o restante da página.

### Como garantir conformidade com a LGPD ao usar a API de CPF no Remix?

Use o CPF apenas para a finalidade declarada ao titular, armazene apenas o necessário nos logs do servidor e implemente controle de acesso a esses registros. A [ANPD](https://www.gov.br/anpd) orienta que dados de identificação devem ser tratados com o princípio da necessidade. No Remix, evite serializar dados de CPF no `loader` além do estritamente necessário para a view — o que não é enviado ao cliente não pode ser exposto.

### 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)
- [Boas práticas para consumir APIs de CPF de forma segura](https://cpfhub.io/blog/boas-praticas-consumir-apis-cpf-segura)
- [Autenticação em APIs REST: como garantir segurança na consulta de CPF](https://cpfhub.io/blog/autenticacao-apis-rest-seguranca-consulta-cpf)
- [Como consumir API de CPF em TypeScript com tipagem segura](https://cpfhub.io/blog/como-consumir-api-de-cpf-em-typescript-com-tipagem-segura)

---

## Conclusão

O Remix é uma escolha sólida para integrar APIs de validação como a [**CPFHub.io**](https://www.cpfhub.io/) porque o modelo loader/action garante que a chave de API e a lógica sensível nunca abandonem o servidor. Com o módulo `.server.ts`, o timeout via `AbortController` e o `ErrorBoundary` configurado, você tem uma integração robusta pronta para produção em menos de uma hora.

Para começar agora, crie sua conta gratuita em [cpfhub.io](https://www.cpfhub.io/), gere a API key no painel e faça a primeira consulta. O plano gratuito inclui 50 consultas por mês sem cartão de crédito — suficiente para validar a integração completa antes de decidir por um plano pago.

