npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@neofaceid/web-sdk

v2.6.0

Published

NeoFaceId Web SDK for facial authentication

Readme

NeoFace ID SDK Web

SDK JavaScript/TypeScript (React) para autenticação, cadastro e verificação facial em aplicações web, publicado no npm como @neofaceid/web-sdk.

Veja o CHANGELOG.md para o histórico de versões.

Índice

Instalação

npm install @neofaceid/web-sdk

react e react-dom são peerDependencies (^18.0.0 || ^19.0.0) — o projeto consumidor precisa já ter as duas instaladas.

Requisitos do consumer

Antes de usar qualquer fluxo do SDK, confirme os itens abaixo no projeto que vai consumi-lo:

  1. HTTPS. O SDK acessa a câmera via getUserMedia, que exige contexto seguro. localhost funciona em desenvolvimento; produção precisa de HTTPS (recomendado configurar HSTS no servidor).

  2. O detector facial (@vladmandic/face-api, fork mantido do face-api.js) já vem embutido no @neofaceid/web-sdk, rodando sobre o TF.js 4.x que o SDK instala como dependência (não precisa instalar nada) — mas os pesos do modelo (weights) não são publicados no bundle e precisam ser auto-hospedados pelo consumer. O SDK carrega os modelos em runtime via faceapi.nets.<rede>.loadFromUri('/models'), ou seja, relativos à própria origem do seu app. Baixe os arquivos abaixo do repositório oficial de pesos do face-api.js (o fork usa os mesmos arquivos) e sirva-os em public/models/ (ou equivalente do seu bundler) para que fiquem acessíveis em /models/*:

    • tiny_face_detector_model-weights_manifest.json + tiny_face_detector_model-shard1
    • face_landmark_68_model-weights_manifest.json + face_landmark_68_model-shard1

    Sem esses arquivos em /models, qualquer fluxo que dependa de detecção facial local (blink detection do liveness, biometricDetection) falha ao carregar o modelo. Se o manifest não for encontrado (404), o console mostra um console.error acionável, com os 4 arquivos e o destino:

    [NeoFace ID SDK] Modelos de detecção facial não encontrados em /models/.
    Copie os 4 arquivos abaixo para public/models/ (ou equivalente do seu bundler):
      - tiny_face_detector_model-weights_manifest.json
      - tiny_face_detector_model-shard1
      - face_landmark_68_model-weights_manifest.json
      - face_landmark_68_model-shard1
    Fonte: https://github.com/vladmandic/face-api/tree/master/model
    Sem esses arquivos em /models, o fluxo de detecção facial falhará silenciosamente.
  3. Ícone/logo do SDK não precisa de asset externo. Desde a 1.29.0 a marca é renderizada via SVG inline (src/assets/brand.ts) — não há mais PNG para hospedar.

  4. applicationToken válido, obtido no painel administrativo do NeoFace ID.

  5. Ambiente correto configurado via init — veja Início rápido. O default (sem init) é sandbox.

Início rápido

import { init } from '@neofaceid/web-sdk';

init({
  environment: 'sandbox', // 'development' | 'sandbox' | 'production'
  applicationToken: 'seu-token-de-aplicacao',
  appName: 'Minha Aplicação', // exibido no topo dos modais
  consent: {
    purpose: 'authentication',
    legalBasis: 'fraud_prevention', // 'consent' | 'legal_obligation' | 'fraud_prevention'
    privacyPolicyUrl: 'https://minha-app.com/privacidade',
    retentionDays: 0,
  },
});

Mapeamento de environment → URL base (src/config.ts):

| environment | URL base | | -------------- | ------------------------------------ | | development | http://localhost:8000 | | sandbox | https://sandbox-core.neofaceid.com | | production | https://core.neofaceid.com.br |

Use baseUrl em vez de environment para apontar para uma URL customizada (tem precedência sobre environment). Outras opções de init — tema visual do integrador:

init({
  accent: '#0059C4', // cor do botão primário; contraste < 4.5 vs branco = fallback + warn
  radius: 16, // 8 | 16 | 24, fallback 16 se fora da lista
  theme: 'auto', // 'light' | 'dark' | 'auto' (respeita prefers-color-scheme)
  locale: 'pt-BR',
});

Getters correspondentes: getBaseUrl(), getEnvironment(), getApplicationToken(), getConsent(), isInitialized(), getConfig(), getAppName(), getAccent(), getRadius(), getTheme(), getLocale(), getResolvedThemeMode(), e o mapa ENVIRONMENT_URLS.

LGPD e consentimento

Todo fluxo que abre a câmera (start, startBiometricRegistration, startLivenessCapture, startFaceLogin, startHandLogin, startAutoLogin, startOnboarding, startDocumentCapture, authorizeOperation, authorize) chama internamente requestConsent({ appName, flow }) antes de qualquer getUserMedia(). Se o titular recusar, o callback de erro recebe NeoFaceError com ErrorType.CONSENT_DENIED e a câmera nunca é aberta.

Configure a base legal uma vez em init({ consent }) (ver Início rápido) — omitir gera console.warn e usa defaults conservadores (fraud_prevention, sem URL de política, retenção indefinida). Também é possível chamar requestConsent diretamente para UI customizada:

import { requestConsent, DEFAULT_CONSENT_INFO } from '@neofaceid/web-sdk';

const accepted = await requestConsent({
  ...DEFAULT_CONSENT_INFO,
  appName: 'Minha Aplicação',
  flow: 'registration', // 'verification' (imagem descartada) | 'registration' (guarda vetor matemático)
});

Toda decisão de consentimento pode ser auditada — veja Trilha de consentimento.

Fluxos principais

Login facial (startFaceLogin)

Overlay minimalista estilo Face ID (não mostra a câmera na tela).

import { startFaceLogin } from '@neofaceid/web-sdk';

await startFaceLogin({
  applicationToken: 'seu-token-de-aplicacao',
  appName: 'Minha Aplicação',
  onSuccess: result => console.log('Login ok:', result),
  onError: err => console.error(err.type, err.getFriendlyMessage()),
  onAttemptError: (err, attempt) => analytics.track('biometric_attempt_failed', { attempt, type: err.type }),
  onCancel: () => console.log('Usuário cancelou'),
  onFallbackRequest: () => {
    /* opcional — default já abre EmailPasswordModal */
  },
});

onError × onAttemptError (BiometricLoginOptions, NEO-563): onError é chamado quando o fluxo guiado termina — usuário cancelou, escolheu email/senha, ou erro fora do loop de tentativas (ex.: CONSENT_DENIED antes da câmera abrir). Já onAttemptError (opcional) é chamado a cada tentativa individual que falha dentro do loop (401, 429, rosto não detectado, etc.), antes de o FallbackPrompt interno aparecer — útil para registrar cada falha no seu próprio sistema de monitoramento sem esperar o fluxo encerrar.

Login por mão / automático (startHandLogin, startAutoLogin)

Mesma assinatura de startFaceLogin (BiometricLoginOptions); startAutoLogin detecta rosto ou mão automaticamente.

import { startHandLogin, startAutoLogin } from '@neofaceid/web-sdk';

await startHandLogin({ applicationToken, onSuccess, onError });
await startAutoLogin({ applicationToken, onSuccess, onError });

Cadastro biométrico (startBiometricRegistration)

import { startBiometricRegistration } from '@neofaceid/web-sdk';

startBiometricRegistration(
  {
    name: 'Maria Silva',
    birth_date: '1990-05-20',
    cpf: '12345678900',
    email: '[email protected]',
    password: 'senha-forte',
  },
  'seu-token-de-aplicacao',
  {
    onSuccess: result => console.log('Cadastro concluído:', result.person_id),
    onError: err => console.error(err.type, err.message),
  },
  { appName: 'Minha Aplicação' }
);

Captura de liveness (startLivenessCapture)

Só a captura de fotos com prova de vida, sem cadastro — útil quando o consumer já tem seu próprio pipeline de reconhecimento.

import { startLivenessCapture } from '@neofaceid/web-sdk';

startLivenessCapture(
  'seu-token-de-aplicacao',
  {
    onSuccess: (photos: Blob[]) => console.log(`${photos.length} fotos capturadas`),
    onError: err => console.error(err.type, err.message),
    onCancel: () => console.log('Usuário fechou o modal'),
  },
  { appName: 'Minha Aplicação' }
);

Onboarding completo (startOnboarding)

Orquestra: validação do link → consentimento → captura de rosto e documento → conclusão no backend.

import { startOnboarding } from '@neofaceid/web-sdk';

await startOnboarding({
  applicationToken: 'seu-token-de-aplicacao',
  onboardingToken: 'token-do-link-de-onboarding',
  appName: 'Minha Aplicação',
  onSuccess: result => console.log('Onboarding concluído:', result.person_id),
  onError: err => console.error(err.type, err.message),
  onCancel: () => console.log('Usuário cancelou'),
});

Captura de documento (startDocumentCapture)

import { startDocumentCapture } from '@neofaceid/web-sdk';

const result = await startDocumentCapture({
  appName: 'Minha Aplicação',
  preSelectedDocument: 'CNH', // 'RG' | 'CNH' | 'CPF' — pula a tela de seleção
  useBackCamera: true,
});

if (result.success) {
  console.log('Frente:', result.frontImage);
  console.log('Verso:', result.backImage); // null se o documento não tem verso
}

Autorização por biometria (authorize / authorizeOperation)

authorize é a API atual (protocolo Focus Frame, orquestra runLivenessChallenge — o servidor decide a sequência de gestos e a aprovação final):

import { authorize } from '@neofaceid/web-sdk';

await authorize({
  applicationToken: 'seu-token-de-aplicacao',
  subject: '12345678900', // CPF, e-mail ou id opaco do titular
  appName: 'Minha Aplicação',
  amount: 1250, // exibido como "R$ 1.250,00"
  challenges: 2, // 0-3, teto sugerido; servidor decide a sequência real
  onChallengeStart: (gesture, index, total) => console.log(gesture, index, total),
  onSuccess: collectResult => {
    // envie collectResult.capturedGestures ao seu próprio endpoint de recognition
  },
  onError: err => console.error(err.type, err.message),
  onCancel: () => console.log('Usuário cancelou'),
});

authorizeOperation é a variante legada, mais baixo nível (captura 4 fotos com gestos fixos e chama recognizeByPurpose('AUTHORIZATION') diretamente):

import { authorizeOperation } from '@neofaceid/web-sdk';

const result = await authorizeOperation('seu-token-de-aplicacao', '12345678900', {
  appName: 'Minha Aplicação',
  onProgress: (step, total, instruction) => console.log(instruction, step, total),
  onPhotoTaken: (n, blob) => console.log('Foto', n, blob),
});

Prova de vida, captura de frames e operações avulsas

Operações que não abrem um fluxo start* completo. Até a 1.x viviam na classe NeoFaceID; desde a 2.0.0 são funções, como o resto do SDK — ver a tabela de migração no CHANGELOG.

import {
  proofOfLife,
  captureFaceFrames,
  recognizeByPurpose,
  registerDocumentByImage,
} from '@neofaceid/web-sdk';

// Prova de vida: grava vídeo curto, envia ao core e acompanha até o resultado.
// `applicationToken` pode ser omitido se já foi passado a init().
const proof = await proofOfLife({
  applicationToken: 'seu-token-de-aplicacao',
  videoDurationMs: 3000,
  onRecordingProgress: progress => console.log(`Gravando: ${progress}%`),
  onTaskStatusChange: (status, progress) => console.log(status, progress),
});
// Reprovar na prova é desfecho, não exceção: confira `success` e `isLive`.
if (proof.success && proof.isLive) {
  console.log('Liveness score:', proof.livenessScore);
  console.log('Dados da pessoa:', proof.personalData);
}

// Login com assinatura (integrações externas que já geram HMAC)
const [frame] = await captureFaceFrames({ numFrames: 1, livenessCheck: false });
const login = await recognizeByPurpose(
  frame,
  'seu-token-de-aplicacao',
  'LOGIN',
  0.8, // limiar de confiança
  signatureFromBackend, // HMAC-SHA256 hex, mínimo 64 caracteres
  { email: '[email protected]', cpf: '12345678900', sessionId: 'session-uuid' }
);

// Registro de documento para pessoa já cadastrada
const docResult = await registerDocumentByImage(personId, userJwtToken);
console.log('Task ID:', docResult.taskId);

Tratamento de erros

Toda falha do SDK (nos fluxos novos) é uma instância de NeoFaceError, com error.type (ErrorType) e error.getFriendlyMessage() para exibir ao usuário final sem termos técnicos:

import { NeoFaceError, ErrorType } from '@neofaceid/web-sdk';

function onError(err: NeoFaceError) {
  if (err.type === ErrorType.CONSENT_DENIED) {
    // usuário recusou o consentimento — não abriu câmera
  }
  alert(err.getFriendlyMessage());
}

Desde a 1.41.0, start, startBiometricRegistration e startLivenessCapture também usam onError(err: NeoFaceError) — antes usavam onError(code: string, message: string). Veja o CHANGELOG.md (breaking change) se seu código ainda depende da assinatura antiga.

| ErrorType | Quando ocorre | | ----------------------- | --------------------------------------------------------------- | | NETWORK | Erro de conexão com o servidor | | INVALID_TOKEN | applicationToken inválido ou expirado | | RECOGNITION_FAILED | Falha no reconhecimento facial | | LOGIN_FAILED | Falha no login biométrico | | VALIDATION_ERROR | Dados inválidos ou rosto não detectado corretamente | | API_ERROR | Erro genérico de API (400/500) | | PERSON_NOT_FOUND | Pessoa não encontrada na base | | INITIALIZATION_ERROR | Falha ao inicializar um fluxo | | CAMERA_ERROR | Erro genérico de câmera | | NO_CAMERA | Câmera não disponível ou permissão negada | | CAPTURE_ERROR | Falha durante a captura de imagem/vídeo | | NOT_FOUND | Recurso não encontrado | | UNKNOWN | Erro não categorizado | | CONSENT_DENIED | Titular recusou o consentimento LGPD | | LIVENESS_BLINK_MISSING| Piscada real (EAR) não detectada na janela de liveness (3s) |

Componentes React exportados

Para quem prefere montar a própria árvore React em vez de usar as funções start* (que já cuidam de criar/desmontar o container):

import {
  FaceCaptureModal,
  BiometricRegistrationModal,
  ConsentModal,
  EmailPasswordModal,
  ForgotPasswordModal,
  BiometricStatusOverlay,
  FallbackPrompt,
  DocumentCaptureModal,
} from '@neofaceid/web-sdk';

Todos recebem accessToken/applicationToken, onSuccess/onError e onClose conforme o fluxo — consulte a assinatura de cada start* correspondente acima para as props equivalentes.

Sessão de captura e desafio de liveness (baixo nível)

Usado internamente por authorize/authorizeOperation, mas exportado para quem monta o próprio orquestrador de liveness:

import {
  openCaptureSession,
  requestLivenessChallenge,
  runLivenessChallenge,
} from '@neofaceid/web-sdk';

const session = await openCaptureSession({
  applicationToken: 'seu-token-de-aplicacao',
  purpose: 'authorization', // 'login' | 'onboarding' | 'authorization' | 'identification' | 'liveness'
});

const challenge = await requestLivenessChallenge({
  applicationToken: 'seu-token-de-aplicacao',
  sessionId: session.session_id,
});

// Ou o fluxo completo (session → challenge → coleta via callback → retorno):
const collected = await runLivenessChallenge({
  applicationToken: 'seu-token-de-aplicacao',
  purpose: 'login',
  collectFramesForGesture: async (gesture, index, total) => {
    // capture o(s) frame(s) correspondente(s) ao gesto e retorne os Blobs
    return [] as Blob[];
  },
});

Trilha de consentimento (auditoria LGPD)

import { recordConsent, getConsentTrail, clearConsentTrail } from '@neofaceid/web-sdk';

// Grava no localStorage apenas hash(userAgent+purpose+timestamp), timestamp,
// finalidade, base legal e versão do SDK — zero PII. Usa por padrão o
// `consent` configurado em `init()`; pode ser sobrescrito pontualmente:
await recordConsent({ purpose: 'authentication', legalBasis: 'fraud_prevention' });

const trail = getConsentTrail(); // ConsentRecord[] — histórico local (máx. 100, FIFO)
clearConsentTrail(); // limpa o histórico (ex.: logout)

API de baixo nível (api.ts)

Funções que os fluxos start* já usam por baixo dos panos, expostas para integrações que precisam de controle fino sobre a chamada HTTP:

import {
  validateToken,
  validateOnboardingToken,
  recognize,
  recognizeBiometric,
  simpleIdentification,
  recognizeByPurpose,
  loginWithBiometric,
  loginWithEmail,
  registerPersonWithoutFace,
  registerPersonWithBiometric,
  registerBiometric,
  identifyPerson,
  identifyPersonAsync,
  checkUserExistence,
  requestPasswordReset,
  confirmPasswordReset,
  completeOnboarding,
  completeOnboardingWithData,
} from '@neofaceid/web-sdk';

await validateToken('seu-token-de-aplicacao'); // boolean
await validateOnboardingToken('seu-token-de-aplicacao', 'token-do-onboarding'); // boolean

await recognize(faceBlob, 'seu-token-de-aplicacao');
await recognizeBiometric(faceBlob, 'seu-token-de-aplicacao', /* livenessCheck */ true, 0.8);
await simpleIdentification('CPF', '12345678900', 'seu-token-de-aplicacao');
await recognizeByPurpose(faceBlob, 'seu-token-de-aplicacao', 'LOGIN', 0.8);

await loginWithBiometric(faceBlob, 'seu-token-de-aplicacao');
await loginWithEmail('[email protected]', 'senha', 'seu-token-de-aplicacao');

await registerPersonWithoutFace(
  { name: 'Maria Silva', birth_date: '1990-05-20', cpf: '12345678900', email: '[email protected]', password: 'senha-forte' },
  'seu-token-de-aplicacao'
);
await registerPersonWithBiometric(
  { name: 'Maria Silva', birth_date: '1990-05-20', cpf: '12345678900', email: '[email protected]', password: 'senha-forte' },
  [faceBlob1, faceBlob2],
  'seu-token-de-aplicacao'
);
await registerBiometric(personId, faceBlob, 'seu-token-de-aplicacao');

await identifyPerson(faceBlob, 'seu-token-de-aplicacao');
await identifyPersonAsync(faceBlob, 'seu-token-de-aplicacao', { maxRetries: 5, interval: 1000 });
await checkUserExistence({ email: '[email protected]' }); // ou { cpf }

await requestPasswordReset('[email protected]', 'seu-token-de-aplicacao');
await confirmPasswordReset('token-do-email', 'nova-senha');

await completeOnboarding('seu-token-de-aplicacao', 'token-do-onboarding', faceBlob, documentBlob);
await completeOnboardingWithData(
  'seu-token-de-aplicacao',
  'token-do-onboarding',
  { name: 'Maria Silva', cpf: '12345678900' },
  [faceBlob1, faceBlob2],
  documentBlob
);

Utilitário de performance para pré-carregar os modelos de detecção facial antes do primeiro uso (evita o delay do primeiro loadFromUri acontecer durante a interação do usuário):

import { preloadFaceDetectionModels } from '@neofaceid/web-sdk';

preloadFaceDetectionModels(); // dispara o carregamento de /models em background

Versão do SDK

import { VERSION, RELEASE_DATE } from '@neofaceid/web-sdk';

console.log(`NeoFace ID SDK ${VERSION} (${RELEASE_DATE})`);

Histórico completo em CHANGELOG.md.

Compatibilidade

Navegadores suportados

  • Chrome 60+
  • Firefox 55+
  • Safari 11+
  • Edge 79+

Responsividade

O SDK é totalmente responsivo. Em dispositivos móveis, os modais ocupam a tela inteira.

Licença

MIT