
Building IntegrityLens: Angular + AI Biometric Verification with Firebase and OpenAI (12k+ Interviews, Real‑Time, Secure)
How I architected a compliant, real‑time candidate screening platform—Angular 20+, Signals/SignalStore, Firebase, and OpenAI—with measurable, production results.
12k+ interviews, P95 verification 7.2s, zero outages—secure, real-time verification isn’t luck; it’s Signals, rules, and guardrails.Back to all posts
I’ve shipped biometric flows in airports and high-trust hiring scenarios. IntegrityLens is where those lessons meet Angular 20+, Signals, and Firebase—purpose-built for secure, real-time candidate verification at scale.
This case study walks through the challenge, the implementation (with code), and the outcomes you can measure. If you’re evaluating an Angular consultant or need to hire an Angular developer for AI + security, this is how I work.
The Challenge: Secure, Real‑Time Candidate Screening at Scale (12k+ Sessions)
Before IntegrityLens, hiring teams manually verified identity—a slow, error-prone process with inconsistent outcomes. We needed to automate liveness + face match, keep AI assist safe, and preserve a great UX. The bar: zero production outages while scaling past 10k sessions.
What made this hard
We needed a flow that works from low-end webcams to 4K cameras, on throttled networks, with instant feedback that doesn’t compromise privacy. Fail states had to be recoverable (resume later) with clear guidance and minimal support overhead.
Live camera capture on fragile devices/networks
PII and biometric data with strict retention requirements
Real-time feedback without jitter or race conditions
Multi-tenant roles (candidate, recruiter, admin) with least privilege
AI assistance without leaking PII or causing hallucinations
Relevant background
I’ve built airport kiosks for a major airline with Docker-based hardware simulation and worked on high-volume analytics for a telecom provider. Those experiences shaped how IntegrityLens handles device variability, real-time updates, and auditability.
Airport kiosk software: offline-tolerant, hardware quirks
Telematics dashboards: WebSocket updates, typed schemas
Employee tracking: access control and audit trails
Architecture: Angular 20+, Firebase, and OpenAI—A Safe Path to Real‑Time Biometrics
This stack balances speed, cost, and safety. Signals/SignalStore make the UI predictable. Firebase handles real-time and authZ. OpenAI runs behind guardrails for summaries and anomaly classification—never as a decision-maker.
Core platform choices
Angular’s Signals eliminate zone.js churn in high-frequency camera flows. Firebase gives us real-time updates and granular security rules. AI never runs in the browser—only in Functions with strict redaction and typed outputs.
Angular 20+, Signals + SignalStore for deterministic UI state
PrimeNG for accessible, production-ready components
Firebase Auth, Firestore, Storage, Cloud Functions
OpenAI API via Functions for structured summaries and risk signals
Nx monorepo + GitHub Actions for CI/CD
Data model and tenancy
Every document and file is namespaced by tenant. Roles (candidate, recruiter, admin) are enforced in rules and in the UI via a permission service and route guards.
/tenants/{tenantId}/candidates/{candidateId}/verifications/{verificationId}
Custom claims for tenant scoping and role-based access
Short-lived signed URLs for any media access
Security and compliance
Security-first meant changing defaults. If a provider requires public access, we wrap it in a Function and sign requests with tenant-scoped secrets.
PII minimization: store derived vectors, not raw where possible
At-rest encryption + retention windows per tenant policy
No public buckets; Function-only media access with HMAC signatures
Implementation Walkthrough: Signals + SignalStore Drive the Verification Flow
Here’s a trimmed version of the SignalStore that orchestrates the end-to-end verification flow.
State model
This keeps camera, network, and provider variability from leaking into the UX. Users see crisp progress and recoverable errors.
Deterministic steps: idle → capture → liveness → match → complete
Typed events and effects with exponential backoff + jitter
Feature flags for provider routing and circuit breakers
PrimeNG UI
We used PrimeNG for fast iteration and consistent accessibility. Signals ensure instant UI response without rerender storms.
Stepper, skeleton loaders, focus management, ARIA labels
Reduced-motion support and INP budgets
Retry/backoff
Backpressure prevents provider thundering herds and keeps the app responsive under load.
Exponential backoff with full jitter for flaky networks
Abort controllers for camera and fetch operations
Code: SignalStore for Verification Flow (Angular 20)
import { signal, computed, inject } from '@angular/core';
import { SignalStore, patchState } from '@ngrx/signals';
import { HttpClient } from '@angular/common/http';
import { randomJitterMs } from './util/backoff';
import { remoteConfigFlag } from './flags';
export type Step = 'idle'|'capture'|'liveness'|'match'|'complete'|'error';
interface VerificationState {
step: Step;
attempt: number;
photoUrl?: string;
livenessScore?: number;
matchScore?: number;
error?: string;
}
export class VerificationStore extends SignalStore<VerificationState> {
private http = inject(HttpClient);
private provider = remoteConfigFlag('biometrics.provider'); // 'providerA' | 'providerB'
step = signal<Step>('idle');
attempt = signal(0);
photoUrl = signal<string | undefined>(undefined);
livenessScore = signal<number | undefined>(undefined);
matchScore = signal<number | undefined>(undefined);
error = signal<string | undefined>(undefined);
canContinue = computed(() => this.step() === 'capture' ? !!this.photoUrl() : true);
async startCapture(blob: Blob) {
patchState(this, { step: 'capture', error: undefined });
const url = await this.upload(blob);
patchState(this, { photoUrl: url });
await this.runLiveness(url);
}
private async upload(blob: Blob) {
// Signed URL from Cloud Function; never expose buckets directly
const { url } = await this.http.post<{ url: string }>(`/api/signed-upload`, {}).toPromise();
await fetch(url, { method: 'PUT', body: blob });
return url.split('?')[0];
}
private async runLiveness(url: string) {
patchState(this, { step: 'liveness' });
await this.withRetry(async () => {
const res = await this.http.post<{ score: number }>(`/api/liveness`, { url, provider: this.provider() }).toPromise();
patchState(this, { livenessScore: res!.score });
});
await this.runMatch(url);
}
private async runMatch(url: string) {
patchState(this, { step: 'match' });
await this.withRetry(async () => {
const res = await this.http.post<{ score: number }>(`/api/face-match`, { url, provider: this.provider() }).toPromise();
patchState(this, { matchScore: res!.score, step: 'complete' });
});
}
private async withRetry<T>(fn: () => Promise<T>) {
for (let i = 0; i < 3; i++) {
try { return await fn(); }
catch (e: any) {
patchState(this, { attempt: this.attempt() + 1, error: e?.message ?? 'Retrying...' });
await new Promise(r => setTimeout(r, randomJitterMs(250 * Math.pow(2, i))));
}
}
patchState(this, { step: 'error', error: 'Please try again later.' });
throw new Error('Verification failed after retries');
}
}VerificationStore.ts
The store models steps, applies feature flags, and emits telemetry.
Notes
These patterns keep SSR deterministic and UI logic testable with Jasmine and Cypress.
Feature flags read from Remote Config with a cached signal
Telemetry sent via a typed event schema to Firestore and GA4
Secure Data Flow: Firestore/Storage Rules and Cloud Functions
# firestore.rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function isTenant(user, tenantId) { return request.auth.token.tenant_id == tenantId; }
function hasRole(role) { return role in request.auth.token.roles; }
match /tenants/{tenantId}/candidates/{candidateId}/verifications/{verificationId} {
allow read: if isTenant(request.auth, tenantId) && hasRole('recruiter');
allow create: if isTenant(request.auth, tenantId) && request.auth.uid == candidateId;
allow update, delete: if false; // immutable verification records
}
}
}// functions/src/biometrics.ts
import * as functions from 'firebase-functions';
import fetch from 'node-fetch';
import crypto from 'crypto';
export const faceMatch = functions.https.onCall(async (data, context) => {
const { url, provider } = data;
const tenantId = context.auth?.token.tenant_id;
if (!tenantId) throw new functions.https.HttpsError('unauthenticated', 'No tenant');
const payload = JSON.stringify({ url, tenantId });
const sig = crypto.createHmac('sha256', process.env.PROVIDER_SECRET!).update(payload).digest('hex');
const res = await fetch(`https://api.${provider}.com/face-match`, {
method: 'POST', headers: { 'x-signature': sig, 'content-type': 'application/json' }, body: payload
});
if (!res.ok) throw new functions.https.HttpsError('unavailable', 'Provider error');
const { score } = await res.json();
return { score };
});Firestore/Storage rules
Rules block lateral movement and enforce least privilege.
Tenant-scoped paths
Role-based checks with custom claims
No public reads
Biometrics Function
All provider calls occur server-side; the browser never sees provider keys.
HMAC-signed provider requests
PII redaction and structured logs
Rate limits + backoff headers
AI Assistance with Guardrails: OpenAI Structured Outputs and Risk Scoring
// functions/src/summary.ts
import OpenAI from 'openai';
import * as functions from 'firebase-functions';
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
export const summarizeInterview = functions.https.onCall(async (data, context) => {
const { transcript, riskSignals } = data; // transcript already redacted server-side
const schema = {
type: 'object',
properties: {
summary: { type: 'string' },
concerns: { type: 'array', items: { type: 'string' } },
score: { type: 'number', minimum: 0, maximum: 1 }
},
required: ['summary','score']
} as const;
const response = await client.responses.create({
model: 'gpt-4o-mini',
input: [{ role: 'system', content: 'Return JSON matching the provided schema only.' },
{ role: 'user', content: `Transcript: ${transcript}\nSignals: ${JSON.stringify(riskSignals)}` }],
response_format: { type: 'json_schema', json_schema: { name: 'InterviewSummary', schema } },
max_output_tokens: 400
});
const result = JSON.parse(response.output_text!);
return { summary: result.summary, concerns: result.concerns ?? [], score: result.score };
});Structured outputs
AI provides summaries and risk flags; humans make decisions.
Typed schemas to prevent hallucinations
Deterministic prompts and max tokens
Privacy
We never ship raw transcripts to the client; summarization runs in Functions with redaction.
Redact PII before send
No training data opt-in; store only structured results
Observability, Performance, and UX Metrics Executives Care About
Results aren’t opinions. We measured P50/P95 verification times, false positives/negatives, and abandonment by device and network. Issues surface in dashboards before support tickets do.
Telemetry pipeline
We tag each verification with a correlation ID to stitch traces across the stack.
Angular DevTools render counts for camera steps
GA4 custom events with typed parameters
Cloud Logging traces from UI → Functions → provider
Budgets and SLOs
Budgets fail the build in CI via Lighthouse and custom checks.
P95 verification < 10s, abandonment < 5%
Core Web Vitals INP under 200ms on verification page
When to Hire an Angular Developer for Biometric Verification or AI Projects
I work as a remote Angular consultant or contract Angular developer. If you need to hire an Angular developer with Fortune 100 experience across aviation, telecom, and insurance, let’s talk about your roadmap.
Signals you’re ready to bring in an Angular consultant
If this sounds familiar, it’s faster to bring in a senior Angular engineer who’s shipped this before. I can review your build and plot a safe, phased path to production.
Security reviews block launch due to unclear data flows
Race conditions around camera/liveness cause jitter or timeouts
You need typed AI outputs with strict privacy and cost controls
Multi-tenant RBAC and audit trails aren’t battle-tested
Results: Faster Verifications, Fewer False Positives, Zero Outages
These are the numbers hiring managers and directors care about: speed, accuracy, and reliability. IntegrityLens delivered on all three.
Measurable outcomes
We also saw INP well under 200ms during camera interaction, and support tickets fell sharply after we shipped resume flows and clearer failure copy.
12k+ interviews processed since launch
P95 verification time: 7.2s (P50: 3.9s)
False positives reduced 38% vs. legacy manual review
Abandonment down to 3.1% on mid-tier Android devices
0 production outages; two canary rollbacks prevented incidents
What to Build Next: Roadmap and Re‑usable Assets
For AI-heavy or device-integrated apps—kiosks, telematics dashboards, and interview platforms—these patterns repeat. They’re proven across airports, broadcast scheduling, and IoT device portals I’ve shipped.
Reusable components
We’ve packaged camera overlays and progress indicators using Signals so you can drop them into other apps. See the NG Wave component library for more.
NG Wave components for camera overlays and animated guidance
Design tokens for error states and motion preferences
Future iterations
The platform is designed for provider swaps and cost control without code churn.
Face match provider abstraction for price/perf routing
Edge media preprocessing with Web Workers and WASM
Granular data retention policies per tenant
Concise Takeaways and Next Steps
- Signals + SignalStore keep biometric flows deterministic and testable.
- Firebase provides real-time UX with enforceable security boundaries.
- AI is helpful when boxed in with typed schemas, privacy, and circuit breakers.
- Ship with guardrails: CI budgets, canaries, and feature flags.
If you need an Angular expert to integrate AI or biometrics—or to stabilize a chaotic codebase—reach out. I can review your repo this week and propose a phased plan.
Key takeaways
- Use Signals + SignalStore to orchestrate camera permissions, liveness checks, and step-by-step verification without race conditions.
- Guard PII with Firestore/Storage rules, least-privilege claims, and signed, short-lived URLs—no public buckets, ever.
- Run AI with guardrails: typed schemas, token budgets, backoff with jitter, and circuit breakers surfaced via feature flags.
- Instrument everything: verification latency P50/P95, false-positive rates, failure taxonomies, and end-to-end traces from UI to Cloud Functions.
- Design for the messy middle: offline tolerance, resume flows, and device capability detection to keep conversion high.
- Ship safely: Nx + GitHub Actions, canary releases, and CI checks for bundle budgets, Lighthouse, and e2e flows.
Implementation checklist
- Define typed event schemas for verification steps (start, capture, liveness, face-match, complete).
- Implement a SignalStore for state, retries, and feature-flagged fallbacks.
- Enforce strict Firestore/Storage rules with custom claims and per-tenant document paths.
- Move AI and biometric calls to Cloud Functions with HMAC signatures and rate limits.
- Track P95 verification time, false positives/negatives, and abandonment by device/network.
- Add Remote Config flags for rollout, kill-switches, and provider routing.
- Automate CI: unit tests (Jasmine), e2e (Cypress), Lighthouse/INP budgets, dependency audit, and canary deploys.
Questions we hear from teams
- How much does it cost to hire an Angular developer for a project like this?
- Most teams start with a fixed assessment and roadmap, then move to weekly retainers. Typical ranges are $6k–$12k for an initial audit and 4–8 weeks for implementation, depending on scope and integrations.
- How long does an Angular biometric verification build take?
- A production MVP with Signals, Firebase, and one biometric provider usually ships in 4–6 weeks. Multi-tenant RBAC, AI summaries, and observability add 2–4 weeks, with canary releases throughout.
- What does an Angular consultant handle versus in-house teams?
- I own architecture, Signals/SignalStore, Firebase rules/Functions, CI/CD, and observability. Your team focuses on domain policy and content. I also train devs to maintain the system after handoff.
- Can you integrate with our existing SSO and audit requirements?
- Yes. I’ve integrated OAuth/OIDC, SAML, and custom claims with per-tenant audit trails. We map events to your SIEM and enforce retention policies without breaking the UX.
- Do you support offline or kiosk-style verification?
- Yes. I’ve built offline-tolerant kiosk flows for a major airline. We use resume tokens, queued writes, and device capability checks to keep the experience stable even on poor networks.
Ready to level up your Angular experience?
Let AngularUX review your Signals roadmap, design system, or SSR deployment plan.
NG Wave
Angular Component Library
A comprehensive collection of 110+ animated, interactive, and customizable Angular components. Converted from React Bits with full feature parity, built with Angular Signals, GSAP animations, and Three.js for stunning visual effects.
Explore Components