JavaScript Client
vitallens.js
is a JavaScript client for the VitalLens API, which leverages the same inference engine as our free iOS app VitalLens. It also includes fast implementations of several heart rate estimation methods from video such as g
, chrom
, and pos
.
You can find the source on GitHub.
- Cross-Platform Compatibility:
Usevitallens.js
in both browser environments and Node.js. - Flexible Input Support:
Process video files or live streams from a webcam (or any MediaStream). - Multiple Estimation Methods:
vitallens
: Provides heart rate, respiratory rate, pulse waveform, and respiratory waveform estimates with associated confidences. (Requires an API key - get one for free on our website)g
,chrom
,pos
: Offer faster (but less accurate) heart rate and pulse waveform estimations. (No API key required.)
- Fast Face Detection & ROI Support:
Perform rapid face detection on demand—or optionally supply a global region of interest (ROI) to speed up processing. - Event-Driven API:
Listen for real-time updates on the estimated vitals. - Pre-Built Web Component Widgets:
In addition to the core API,vitallens.js
provides ready-to-use web components. Use the unified widget (supporting both file and webcam modes) or choose the specialized file-only or webcam-only widget for streamlined integration. - TypeScript-Ready:
Written in TypeScript with complete type definitions for an enhanced developer experience.
Installation
Node.js
Install vitallens.js
via npm or yarn:
npm install vitallens
# or
yarn add vitallens
Then use it as follows:
import { VitalLens } from 'vitallens';
const vl = new VitalLens({ method: 'vitallens', apiKey: 'YOUR_API_KEY' });
// Your Node.js code here…
Browser
For browser usage, you can either bundle vitallens.js
with your project or load it directly from a CDN. In addition to the core API, vitallens.js
also provides pre-built web component widgets. We offer three variants:
- Unified Widget: Supports both file and webcam modes with mode toggles.
- File-Only Widget: For processing video files only.
- Webcam-Only Widget: For live webcam streaming only.
For example, using jsDelivr:
<!-- Latest version -->
<script src="https://cdn.jsdelivr.net/npm/vitallens/dist/vitallens.browser.js"></script>
<!-- Or pin a specific version -->
<script src="https://cdn.jsdelivr.net/npm/vitallens@0.0.3/dist/vitallens.browser.js"></script>
<!-- Use with core API -->
<script>
// vitallens.js is exposed as a global, for example as window.VitalLens.
const vl = new VitalLens({ method: 'vitallens', apiKey: 'YOUR_API_KEY' });
// Suppose myMediaStream and myVideoElement are defined:
vl.addVideoStream(myMediaStream, myVideoElement);
vl.addEventListener('vitals', (data) => console.log(data));
vl.startVideoStream();
</script>
<!-- Or use our widget -->
<vitallens-widget api-key="YOUR_API_KEY"></vitallens-widget>
<!-- Or, to use a specialized widget: -->
<!-- File-only widget -->
<vitallens-file-widget api-key="YOUR_API_KEY"></vitallens-file-widget>
<!-- Webcam-only widget -->
<vitallens-webcam-widget api-key="YOUR_API_KEY"></vitallens-webcam-widget>
Alternatively, you can use unpkg:
<script src="https://unpkg.com/vitallens/dist/vitallens.browser.js"></script>
Or Skypack if you prefer ES modules:
<script type="module">
import { VitalLens } from 'https://cdn.skypack.dev/vitallens';
// Continue as above…
</script>
Configuration Options
When creating a new VitalLens
instance, you can configure various options:
Parameter | Description | Default |
---|---|---|
method |
Inference method: 'vitallens' , 'g' , 'chrom' , or 'pos' . |
'vitallens' |
apiKey |
API key for the VitalLens API (required for method 'vitallens' ). |
null |
globalRoi |
Optional region of interest for face detection (object with { x0, y0, x1, y1 } ). |
undefined |
waveformMode |
How waveform data is returned: 'incremental' , 'windowed' , or 'complete' . |
windowed for stream; complete for file. |
requestMode |
How to communicate with the VitalLens API: 'websocket' or 'rest' . |
'rest' |
overrideFpsTarget |
Override for the target frames per second (fps) used during inference. | undefined |
fDetFs |
Frequency (in Hz) at which face detection should be performed. | 1 |
Returned Estimation Results
When Analyzing a Video Stream
When analyzing a video stream, vitallens.js
returns estimation results continuously. Each returned estimation result contains the following vital signs:
Name | Type | Based on / containing | Returned if |
---|---|---|---|
heart_rate |
Global value | Up to last 10 seconds | Face present for at least 2 seconds using vitallens , pos , chrom , or g |
ppg_waveform |
Continuous waveform | Depends on waveformMode |
Using vitallens , pos , chrom , or g |
respiratory_rate |
Global value | Up to last 30 seconds | Face present for at least 4 seconds using vitallens |
respiratory_waveform |
Continuous waveform | Depends on waveformMode |
Using vitallens |
When Analyzing a Video File
When analyzing a video file, vitallens.js
returns one estimation result for the entire file, containing:
Name | Type | Based on / containing | Returned if |
---|---|---|---|
heart_rate |
Global value | Entire video | Video is at least 2 seconds long using vitallens , pos , chrom , or g |
ppg_waveform |
Continuous waveform | Depends on waveformMode |
Using vitallens , pos , chrom , or g |
respiratory_rate |
Global value | Entire video | Video is at least 4 seconds long using vitallens |
respiratory_waveform |
Continuous waveform | Depends on waveformMode |
Using vitallens |
Returned Structure
When you process a video or a MediaStream with vitallens.js
, the library returns result objects with the following structure:
export interface VitalLensResult {
face: {
// Detected face coordinates for each frame, formatted as [x0, y0, x1, y1].
coordinates: Array<[number, number, number, number]>;
// Confidence values for the face detection per frame.
confidence: number[];
// An explanatory note regarding the face detection.
note: string;
};
vital_signs: {
// Estimated global heart rate.
heart_rate: {
value: number; // Estimated heart rate value.
unit: string; // Unit (e.g., 'bpm').
confidence: number; // Overall confidence.
note: string;
};
// Estimated global respiratory rate.
respiratory_rate?: {
value: number; // Estimated respiratory rate value.
unit: string; // Unit (e.g., 'breaths/min').
confidence: number;
note: string;
};
// Photoplethysmogram (PPG) waveform estimation.
ppg_waveform: {
data: number[]; // Waveform data (one value per processed frame).
unit: string;
confidence: number[];// Confidence per frame.
note: string;
};
// Respiratory waveform estimation.
respiratory_waveform?: {
data: number[]; // Waveform data (one value per processed frame).
unit: string;
confidence: number[];// Confidence per frame.
note: string;
};
};
// A list of timestamps (one per processed frame).
time: number[];
// The frames per second (fps) of the input video.
fps: number;
// The effective fps used for inference.
estFps: number;
// A message providing additional information about the estimation.
message: string;
}
Examples
Processing a Video File (Node.js Example)
import { VitalLens } from 'vitallens';
const options = {
method: 'vitallens', // Choose from 'vitallens', 'g', 'chrom', or 'pos'
apiKey: 'YOUR_API_KEY', // Required when using the 'vitallens' method
};
const vitallens = new VitalLens(options);
async function processVideoFile(filePath) {
try {
const result = await vitallens.processFile(filePath);
console.log('Processing complete!', result);
} catch (error) {
console.error('Error processing video:', error);
}
}
processVideoFile('./examples/sample_video_1.mp4');
Real-Time Vital Estimation (Browser Example)
Below is a minimal example that uses a webcam stream:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vitallens.js Webcam Example</title>
</head>
<body>
<video id="video" autoplay muted playsinline style="width:100%; max-width:600px;"></video>
<!-- Load vitallens.js directly from a CDN -->
<script src="https://cdn.jsdelivr.net/npm/vitallens/dist/vitallens.browser.js"></script>
<script>
// vitallens.js is available as a global (e.g., window.VitalLens)
const options = {
method: 'vitallens', // 'vitallens' requires an API key
apiKey: 'YOUR_API_KEY',
};
const vitallens = new VitalLens(options);
async function startVitals() {
try {
const video = document.getElementById('video');
const stream = await navigator.mediaDevices.getUserMedia({
video: { facingMode: 'user' },
audio: false
});
video.srcObject = stream;
// Add the stream to vitallens.js
await vitallens.addVideoStream(stream, video);
// Listen for vitals events
vitallens.addEventListener('vitals', (data) => {
console.log('Detected vitals:', data);
});
// Start processing
vitallens.startVideoStream();
} catch (error) {
console.error('Error initializing webcam:', error);
}
}
startVitals();
</script>
</body>
</html>
Web Component Widgets (Browser)
In addition to the core JavaScript API, vitallens.js
provides pre-built web component widgets for quickly integrating vital sign estimation into your web pages. There are three available widgets:
- Unified Widget:
This widget includes both file-based and real-time webcam functionality with a built-in mode toggle. Use it when you want to let users switch between processing a video file and streaming from a webcam on the same component. Example usage:
<!-- Load vitallens.js directly from a CDN -->
<script src="https://cdn.jsdelivr.net/npm/vitallens/dist/vitallens.browser.js"></script>
<!-- Unified widget: supports both file and webcam modes -->
<vitallens-widget api-key="YOUR_API_KEY"></vitallens-widget>
- File-Only Widget:
This widget is tailored for file-based processing only. It removes the mode toggle UI and displays only the file input functionality. Use it when you want to allow users to process a video file without any webcam streaming options. Example usage:
<!-- Load vitallens.js directly from a CDN -->
<script src="https://cdn.jsdelivr.net/npm/vitallens/dist/vitallens.browser.js"></script>
<!-- File-only widget -->
<vitallens-file-widget api-key="YOUR_API_KEY"></vitallens-file-widget>
- Webcam-Only Widget:
This widget is specialized for real-time webcam streaming. It hides file input controls and mode toggles, providing a streamlined interface for live vital estimation from a webcam. Example usage:
<!-- Load vitallens.js directly from a CDN -->
<script src="https://cdn.jsdelivr.net/npm/vitallens/dist/vitallens.browser.js"></script>
<!-- Webcam-only widget -->
<vitallens-webcam-widget api-key="YOUR_API_KEY"></vitallens-webcam-widget>
Securing your API Key
For security reasons, we recommend that you do not expose your API key directly in client-side code. There are two primary approaches to secure your API key:
1. Run Everything on your Server
If you are building a server-side application using Node.js, your API key remains securely on your server. Simply call the API directly from your backend code without exposing your credentials.
2. Use a Proxy Server for Client-Side Code
If you need to use vitallens.js
in a browser, you can set up a proxy server. The proxy server receives requests from the client, attaches your API key (stored securely on the server), and forwards the request to the VitalLens API. This way, the API key is never exposed to the client.
Our client library supports this by accepting a proxyUrl
option. For example:
import { VitalLens } from 'vitallens';
const vl = new VitalLens({
method: 'vitallens',
proxyUrl: 'https://your-proxy-server.com/api' // URL to your deployed proxy server
});
Or when using one of our widgets:
<vitallens-widget proxy-url="https://your-proxy-server.com/api"></vitallens-widget>
Sample Proxy Server Implementation
Below is a simple Node.js/Express proxy server implementation that you can use as a starting point:
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const app = express();
const PORT = process.env.PORT || 3000;
// Securely store your API key in an environment variable
const API_KEY = process.env.VITALLENS_API_KEY;
const VITALLENS_ENDPOINT = 'https://api.rouast.com/vitallens-v3/file';
app.use(bodyParser.json({ limit: '10mb' }));
// Enable CORS for your allowed domain.
app.use(cors({
origin: 'http://example.com', // Your allowed domain
methods: ['GET', 'POST', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization']
}));
app.post('/', async (req, res) => {
try {
const response = await fetch(VITALLENS_ENDPOINT, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': API_KEY,
},
body: JSON.stringify(req.body),
});
const data = await response.text();
res.status(response.status).send(data);
} catch (error) {
console.error('Proxy error:', error);
res.status(500).send('Internal server error');
}
});
app.listen(PORT, () => {
console.log(`Proxy server listening on port ${PORT}`);
});
You can deploy this proxy server on any Node.js hosting platform (such as Heroku, Vercel, or your own server) and then set the URL as the proxyUrl
in your VitalLens client configuration.
Development
Building the Library
To build the project from source, run:
npm run build
This compiles the TypeScript source and bundles the output for Node (both ESM and CommonJS) and the browser.
Running Tests
Execute the test suite with:
npm run test
For environment-specific tests, you can use:
npm run test:browser
npm run test:node
Linting
Lint the code using:
npm run lint
License
This project is licensed under the MIT License.