Facial authentication tutorial

Add Facial Authentication to Your Website with FACEIO

Add passwordless face enrollment and login to an existing website or web app with fio.js. FACEIO handles the browser interaction while your backend keeps control of accounts, sessions, recovery, and authorization.

PixLab 10 min read
Existing login flow
const faceio = new faceIO("app-public-id");

await faceio.enroll({
  locale: "auto"
});

const user = await faceio.authenticate({
  locale: "auto"
});
Enroll
Authenticate
Create Session

Updated developer experience

A Clearer Route from Existing Login Page to Face Login

FACEIO launched its updated website in October 2026 with revised developer documentation, localized pages, and clearer product guidance. This tutorial focuses on the core facial authentication framework: adding enrollment and returning-user authentication to a website or web application you already operate.

The first browser integration is deliberately small. Load fio.js, initialize it with your application Public ID, call enroll() or authenticate(), and pass the result into your existing backend flow. A production rollout still needs server-side authorization, session management, consent, recovery, and deletion controls.

What You Will Build

Optional face enrollment

An authenticated account holder chooses to set up face login and completes the FACEIO enrollment flow.

Returning-user face login

A previously enrolled user starts facial authentication from the existing sign-in page.

Backend account mapping

Your server associates the returned Facial ID with an account and keeps the final authorization decision.

Production controls

Domain restrictions, liveness settings, PIN policy, consent, fallback access, and usable error messages.

How FACEIO Fits an Existing Authentication Flow

1Your pageUser selects face enrollment or face login.
2FACEIO Widgetfio.js guides the browser interaction.
3Authentication resultThe Promise resolves with a Facial ID and related data.
4Your backendValidates account state and issues the normal session.
Keep authorization on the server. A browser result should not grant access by itself. Your backend must decide whether the mapped account is active, whether the event is valid for the requested action, and which permissions the resulting session receives.

Before You Start

  • 1Create a FACEIO application from the FACEIO Console and copy its Public ID.
  • 2Choose the recognition engine and review the application's security, region, privacy, and widget settings.
  • 3Identify the existing backend routes that create sessions, map authentication identifiers to accounts, and handle account recovery.
  • 4Prepare a clear enrollment notice, user consent step, alternative access method, and Facial ID deletion path before enrolling production users.

The Public ID initializes the browser widget and is expected to appear in frontend code. REST API keys, recognition-engine credentials, AWS credentials, webhook secrets, and other private values must remain on your server.

Step 1

Add fio.js to the Login Page

Place the FACEIO modal container and CDN script before the closing </body> tag. Load fio.js directly from the FACEIO CDN rather than self-hosting it so your integration receives current fixes and features.

<button type="button" id="face-enroll">Set up face login</button>
<button type="button" id="face-sign-in">Sign in with your face</button>
<p id="auth-message" role="status"></p>

<div id="faceio-modal"></div>
<script src="https://cdn.faceio.net/fio.js"></script>
<script src="/js/face-auth.js" defer></script>

Initialize the library in face-auth.js with the Public ID shown in the FACEIO Application Manager:

const faceio = new faceIO("app-public-id");

For the complete setup sequence, follow the official FACEIO Getting Started guide. Its quick setup is useful for the first browser integration; production work continues with the backend and security steps below.

Step 2

Enroll an Existing Account

Call enroll() only after the user is signed in to the account being linked and has chosen to enable facial authentication. This example lets the existing authenticated server session identify the account. If you use the optional payload, keep it to an opaque reference and never place passwords, tokens, or unnecessary personal data there because the payload is returned during later authentication.

async function enrollUser() {
  try {
    const userInfo = await faceio.enroll({
      locale: "auto"
    });

    await registerFacialId({
      facialId: userInfo.facialId
    });
  } catch (error) {
    if (typeof error === "number") {
      showFaceioError(error);
      return;
    }
    showApplicationError(error);
  }
}

document
  .querySelector("#face-enroll")
  .addEventListener("click", enrollUser);

The backend route in this example belongs to your application:

async function registerFacialId(enrollment) {
  const response = await fetch("/api/auth/faceio/enrollment", {
    method: "POST",
    credentials: "same-origin",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(enrollment)
  });

  if (!response.ok) {
    throw new Error("The account could not be linked.");
  }
}
Production note: Treat the browser POST as a request, not proof. Confirm the enrollment through your trusted backend design, such as a validated FACEIO webhook, before permanently changing account state.

Step 3

Authenticate a Returning User

Call authenticate() from the sign-in page. On success, FACEIO returns the same Facial ID assigned during enrollment and the payload previously associated with that user. Send only the values your backend needs and let the server create the normal application session.

async function authenticateUser() {
  try {
    const userData = await faceio.authenticate({
      locale: "auto"
    });

    const response = await fetch("/api/auth/faceio/session", {
      method: "POST",
      credentials: "same-origin",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ facialId: userData.facialId })
    });

    if (!response.ok) {
      throw new Error("The application session was not created.");
    }

    const result = await response.json();
    window.location.assign(result.redirectTo || "/app");
  } catch (error) {
    if (typeof error === "number") {
      showFaceioError(error);
      return;
    }
    showApplicationError(error);
  }
}

document
  .querySelector("#face-sign-in")
  .addEventListener("click", authenticateUser);

The route names are examples. Use your application's existing session framework, secure cookie settings, rate limits, account checks, and redirect rules. The FACEIO Integration Guide documents the full method parameters and return values.

Step 4

Keep Account and Session Control in Your Backend

FACEIO adds a facial authentication step to your product; it does not replace the surrounding account system. A practical backend integration should:

  • Map each Facial ID to one account in your own database.
  • Validate FACEIO webhook events before changing enrollment or authentication state.
  • Check whether the account is active, suspended, deleted, or subject to step-up verification.
  • Issue the same secure application session used by other approved login methods.
  • Provide account recovery and an alternative login path when a camera is unavailable or the user cannot use face authentication.
  • Remove the Facial ID mapping when the user disables face login or closes the account.

Use the official webhook documentation to synchronize events and the REST API reference for server-side management and deletion workflows.

Step 5

Handle Camera, Recognition, and Origin Errors

Both primary methods reject with a numeric fioErrCode. Translate common errors into clear next steps instead of displaying raw constants to users.

function showFaceioError(errorCode) {
  const messages = {
    [fioErrCode.PERMISSION_REFUSED]:
      "Allow camera access in your browser, then try again.",
    [fioErrCode.NO_FACES_DETECTED]:
      "Keep one face clearly visible in the frame and try again.",
    [fioErrCode.UNRECOGNIZED_FACE]:
      "We could not match an enrolled account. Use another sign-in method.",
    [fioErrCode.MANY_FACES]:
      "Make sure only one person is visible to the camera.",
    [fioErrCode.FORBIDDEN_ORIGIN]:
      "Face login is not enabled for this website address.",
    [fioErrCode.TIMEOUT]:
      "The request timed out. Check your connection and try again."
  };

  const message = messages[errorCode] || "Face login could not be completed.";
  document.querySelector("#auth-message").textContent = message;
}

function showApplicationError() {
  document.querySelector("#auth-message").textContent =
    "The application could not complete sign-in. Try another login method.";
}

Also prevent double-clicks while a flow is active, preserve a non-camera login option, and avoid exposing detailed anti-spoofing or account-state information that could help an attacker.

Production Security and Privacy Checklist

Restrict allowed domains

Limit widget initialization to the website origins that should use your Public ID.

Review liveness and PIN policy

Choose controls that match the risk of login, recovery, administration, or payment actions.

Ask before enrollment

Explain the purpose and request the required consent when the user chooses face authentication.

Document deletion

Give users a way to disable face login and remove the associated Facial ID and biometric data where applicable.

Keep secrets server-side

Never expose REST API keys, webhook secrets, AWS keys, or recognition-engine credentials in browser code.

Keep a fallback path

Offer an accessible alternative for users who cannot or do not want to use face authentication.

FACEIO states that its service, widget, fio.js, REST API, and Console do not store, handle, or access biometric hashes; the recognition engine selected by the application owner creates and manages them. Review the current security best practices, privacy best practices, and Facial ID reference for the responsibilities that apply to your deployment.

Use FACEIO with Your Existing Frontend Stack

fio.js can be called from a traditional HTML page or a browser-rendered component in React, Vue, Angular, Next.js, and similar frameworks. You do not need to rebuild the rest of the application around FACEIO.

  • Initialize faceIO only in browser code after the library and DOM are available.
  • Keep a single instance for the page and prevent duplicate enrollment or authentication calls.
  • Call the widget from the same buttons and routes your users already understand.
  • Send the result into the same backend session layer used by the rest of the product.

Localization and Accessible Fallbacks

Set locale: "auto" to let the widget use the browser language, or pass a supported locale explicitly. The FACEIO widget supports more than 70 languages, while the updated documentation website is available in English, Brazilian Portuguese, Mexican Spanish, Indonesian, and Japanese.

Test the complete flow with the browsers, devices, keyboards, screen readers, and assistive technologies your audience uses. FACEIO provides visual and audio guidance, but your application should still offer an alternative authentication method and a clear support path.

Continue with the Updated FACEIO Documentation

FAQ

FACEIO Facial Authentication Questions

How do I add facial authentication to an existing website?

Create an application in FACEIO Console, add fio.js to the relevant page, initialize faceIO with the application's Public ID, and call enroll() for registration or authenticate() for returning users. Connect the returned Facial ID to your existing backend account and session workflow.

Does FACEIO replace my website's backend authentication system?

No. FACEIO handles browser-based facial enrollment and authentication. Your backend remains responsible for mapping Facial IDs to accounts, validating the result, issuing sessions, enforcing authorization, providing account recovery, and managing deletion.

Which FACEIO methods are required for face login?

Use enroll() to register a new user and authenticate() to recognize a previously enrolled user. Both methods return Promises and reject with fioErrCode values that your interface should handle.

Can FACEIO work with React, Vue, Angular, or Next.js?

Yes. fio.js is loaded in the browser and can be called from Vanilla JavaScript or common web frameworks. Initialize it in browser-only code and connect the result to the application's existing server-side session flow.

Does FACEIO store biometric hashes?

FACEIO states that its service, widget, JavaScript library, REST API, and Console do not store, handle, or access biometric hashes. The recognition engine selected by the application owner creates and manages the biometric hash. Application owners remain responsible for consent, account mapping, retention, and deletion controls.

Is facial authentication the same as identity verification?

No. Facial authentication recognizes a user previously enrolled in the same FACEIO application. It does not by itself verify a person's legal identity, validate an identity document, or replace the application's authorization and risk controls.

Add face login

Create Your FACEIO Application

Open FACEIO Console, create an application, copy its Public ID, and use the updated Getting Started guide to connect the first enrollment and authentication flow to your website.