Skip to content

Node.js Examples

Complete Node.js examples for server-side integration with Moveris API (v2).

In plain terms

Use Node.js to process video frames on your server and call the Moveris API. Ideal for backend proxies (your frontend sends frames to your server, which adds the API key and forwards to Moveris) or for batch processing uploaded videos.

Node.js 18+

These examples use native fetch (available in Node.js 18+) and sharp for image processing.

Model selection

Examples use the v1 flow (model in body). For v2 resolution, add X-Model-Version: latest header and frame_count in the body. See Model Versioning & Frames.

Basic Example

const fs = require('fs');
const sharp = require('sharp');
const { randomUUID } = require('crypto');

const API_KEY = process.env.MOVERIS_API_KEY;
const BASE_URL = 'https://api.moveris.com';

async function checkLiveness(imagePaths) {
  const frames = await Promise.all(
    imagePaths.map(async (path, index) => {
      const buffer = await sharp(path)
        .resize(640, 480, { fit: 'cover' })
        .png()
        .toBuffer();

      return {
        index,
        timestamp_ms: index * 100,
        pixels: buffer.toString('base64')
      };
    })
  );

  const response = await fetch(`${BASE_URL}/api/v1/fast-check`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': API_KEY,
      // v2 flow (optional): 'X-Model-Version': 'latest'
    },
    body: JSON.stringify({
      session_id: randomUUID(),
      source: 'live',
      // v1 flow:
      model: 'mixed-10-v2',
      // v2 flow (alternative):
      // frame_count: 10,
      frames
    })
  });

  const body = await response.json();
  if (!body.success) {
    throw new Error(body.message || `HTTP ${response.status}`);
  }
  return body.data;
}

// Usage (10 frames for mixed-10-v2)
const result = await checkLiveness([
  'frame0.png', 'frame1.png', 'frame2.png',
  'frame3.png', 'frame4.png', 'frame5.png',
  'frame6.png', 'frame7.png', 'frame8.png', 'frame9.png'
]);
console.log(`Verdict: ${result.verdict}, Score: ${result.score}`);
import sharp from 'sharp';
import { randomUUID } from 'crypto';
import { readdir } from 'fs/promises';
import { join } from 'path';

const API_KEY = process.env.MOVERIS_API_KEY;
const BASE_URL = 'https://api.moveris.com';

async function checkLiveness(frameDir: string): Promise<LivenessResult> {
  const files = await readdir(frameDir);
  const imageFiles = files
    .filter(f => /\.(png|jpg|jpeg)$/i.test(f))
    .sort()
    .slice(0, 10);

  const frames = await Promise.all(
    imageFiles.map(async (file, index) => {
      const buffer = await sharp(join(frameDir, file))
        .resize(640, 480, { fit: 'cover' })
        .png()
        .toBuffer();

      return {
        index,
        timestamp_ms: index * 100,
        pixels: buffer.toString('base64')
      };
    })
  );

  const response = await fetch(`${BASE_URL}/api/v1/fast-check`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': API_KEY!,
      // v2 flow (optional): 'X-Model-Version': 'latest'
    },
    body: JSON.stringify({
      session_id: randomUUID(),
      source: 'live',
      // v1 flow:
      model: 'mixed-10-v2',
      // v2 flow (alternative):
      // frame_count: 10,
      frames
    })
  });

  const body = await response.json();
  if (!body.success) {
    throw new Error(body.message || `HTTP ${response.status}`);
  }
  return body.data as LivenessResult;
}

interface LivenessResult {
  verdict: 'live' | 'fake';
  real_score: number;
  score: number;
  session_id: string;
  processing_ms: number;
}

// Usage
const result = await checkLiveness('./frames');
console.log(`Verdict: ${result.verdict}, Score: ${result.score}`);

Express.js API Endpoint

A complete Express.js endpoint that accepts frame uploads from your frontend and proxies requests to the Moveris API.

import express from 'express';
import multer from 'multer';
import sharp from 'sharp';
import { randomUUID } from 'crypto';

const app = express();
const upload = multer({ storage: multer.memoryStorage() });

const API_KEY = process.env.MOVERIS_API_KEY;
const BASE_URL = 'https://api.moveris.com';

// POST /api/liveness - accepts image files (count must match model; 10 for mixed-10-v2, 30 for mixed-30-v2)
const REQUIRED_FRAMES = 10;  // for mixed-10-v2; use getModels() for dynamic model selection
app.post('/api/liveness', upload.array('frames', 30), async (req, res) => {
  try {
    const files = req.files as Express.Multer.File[];

    if (!files || files.length < REQUIRED_FRAMES) {
      return res.status(400).json({
        error: `Frames required: ${REQUIRED_FRAMES} for mixed-10-v2`,
        required: REQUIRED_FRAMES,
        received: files?.length ?? 0
      });
    }

    const frames = await Promise.all(
      files.map(async (file, index) => {
        const buffer = await sharp(file.buffer)
          .resize(640, 480, { fit: 'cover' })
          .png()
          .toBuffer();

        return {
          index,
          timestamp_ms: index * 100,
          pixels: buffer.toString('base64')
        };
      })
    );

    const response = await fetch(`${BASE_URL}/api/v1/fast-check`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-API-Key': API_KEY!
      },
      body: JSON.stringify({
        session_id: randomUUID(),
        source: 'live',
        model: 'mixed-10-v2',
        frames
      })
    });

    const body = await response.json();
    if (!body.success) {
      return res.status(response.status).json(body);
    }

    res.json(body);
  } catch (error) {
    console.error('Liveness check failed:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Installation

npm install sharp
npm install express multer sharp @types/express @types/multer

Tips

  • Store your API key in environment variables (MOVERIS_API_KEY)
  • Use sharp for efficient image resizing and format conversion
  • Validate frame count matches model (e.g. 10 for mixed-10-v2, 30 for mixed-30-v2) before calling the API
  • Handle errors gracefully — parse JSON and check success on the envelope (see Errors)
  • For production, add rate limiting and request validation to your Express endpoints