Introduction

Real-time facial expression and emotion analysis, on device. The Affectiva Vision SDK detects and tracks human faces in video frames and images, and estimates facial expressions, emotions, head pose, and image quality β€” with all processing running locally on the CPU. No cloud connection, no GPU, and no external model files.

What the SDK provides

  • Face detection and tracking β€” finds faces in each frame and assigns a stable identifier per face so metrics can be followed over time.
  • Facial expressions β€” 20+ facial-action metrics (smile, brow raise, eye closure, blink and blink rate, yawn, attention, speaking, …).
  • Emotions β€” estimates of joy, anger, sadness, surprise, fear, disgust, contempt and neutrality, along with composite measures such as valence and engagement.
  • Measurements β€” head pose (pitch, yaw, roll, in degrees) and interocular distance (in pixels).
  • Face points β€” pixel coordinates of key landmarks (outer eye corners, nose tip, chin tip) and a per-face bounding box.
  • Image quality β€” a brightness metric for verifying capture conditions.

Metrics overview

Metrics are delivered per tracked face, per processed frame. The table below is a summary β€” the Metrics guide explains every individual metric in detail: what it represents, the facial actions behind it, its value range, and how to interpret it. Identifier spellings per platform are in the API reference.

FamilyExamplesValue rangeEnabled by
Expressionssmile, brow furrow, eye closure, blink, yawn, attention, speaking, pain0–100 (degree of expression). Event-like metrics (BLINK, YAWN) report 0 or 100; BLINK_RATE is blinks/minute; PAIN is a continuous 0–100 scoreFeature::EXPRESSIONS
Emotionsjoy, anger, sadness, surprise, valence, engagement, neutral0–100, except VALENCE variants: βˆ’100 (negative) to +100 (positive)Feature::EMOTIONS
Measurementspitch, yaw, roll, interocular distancedegrees (0/0/0 = facing camera); pixels for interocular distancealways delivered with tracked faces
Face pointsouter eye corners, nose tip, chin tip, bounding boxpixel coordinatesalways delivered with tracked faces
Qualitybrightness0–100always delivered with tracked faces
Face confidenceFace::getConfidence()0–100 (confidence in the presence of the face)always delivered with tracked faces

How it works

Your application owns the camera or video source. Each captured image is wrapped in a Frame (raw pixels + timestamp) and pushed to a Detector. The detector runs the embedded neural networks and delivers results through your listener as a map of tracked Face objects.

Your application
camera / video / image source

β†’

Frame
pixels, color format, rotation, timestamp (ms)

β†’

Detector
FrameDetector (async)
SyncFrameDetector (sync)

β†’

FaceListener
map<FaceId, Face> per processed frame

The same five-step flow applies on every platform:

  1. Construct a detector β€” SyncFrameDetector to process every frame on your thread, or FrameDetector for asynchronous, real-time processing that may drop frames to keep up.
  2. Enable the features you need (EXPRESSIONS, EMOTIONS). Enabling only what you use saves CPU.
  3. Register your listener to receive results.
  4. Start the detector with your license key.
  5. Process frames with strictly increasing timestamps; read metrics in your listener callback. Stop the detector when finished.

The same flow in every language

#include <SyncFrameDetector.h>
#include <FaceListener.h>
using namespace affdex::vision;
SyncFrameDetector detector;                                  // 1. construct
detector.enable({Feature::EXPRESSIONS, Feature::EMOTIONS});  // 2. enable
MyListener listener;                                         //    your FaceListener subclass
detector.setFaceListener(&listener);                         // 3. listen
detector.start("YOUR-LICENSE-KEY");                          // 4. start
Frame frame(0, 640, 480, pixels, Frame::ColorFormat::BGR);
detector.process(frame);                                     // 5. process
detector.stop();
import affvisionpy as af
detector = af.SyncFrameDetector()                            # 1. construct
detector.enable_features({af.Feature.expressions,            # 2. enable
                          af.Feature.emotions})
listener = Listener()                                        #    your af.FaceListener subclass
detector.set_face_listener(listener)                         # 3. listen
detector.start("YOUR-LICENSE-KEY")                           # 4. start
frame = af.Frame(0, 640, 480, pixels,
                 af.Frame.ColorFormat.bgr, af.Frame.Rotation.upright)
detector.process(frame)                                      # 5. process
detector.stop()
FrameDetector detector = new FrameDetector(context);         // 1. construct
detector.enable(Arrays.asList(Feature.EXPRESSIONS,           // 2. enable
                              Feature.EMOTIONS));
detector.setImageListener(resultsListener);                  // 3. listen (results on Android)
detector.start(licenseKey);                                  // 4. start
Frame frame = new Frame(640, 480, nv21,
        Frame.ColorFormat.YUV_NV21, timestampMs);
detector.process(frame);                                     // 5. process
detector.stop();
detector.dispose();                                          //    release native resources

Supported platforms

PlatformArchitectureToolchainPackageLanguage APIs
Ubuntu 24.04x86_64GCC 13shared library (.so) + headers; Python wheelC++17, Python 3.12
Windows 10 / 11x64Visual Studio 2022 (MSVC).dll / .lib + headers; Python wheelC++17, Python 3.13
Android 8.0+ (API 26)arm64-v8aNDK 24 / ClangAAR (com.affectiva.android:emotion-sdk)Java
  • Android packages target 64-bit ARM devices only (arm64-v8a); 32-bit devices and x86 emulator images are not supported. The native libraries are aligned for 16 KB memory pages, as required by recent Android releases.
  • For platforms not listed here (for example macOS or iOS), contact your iMotions / Affectiva representative.

Hardware requirements

The SDK’s inference runs entirely on the CPU β€” no GPU, NPU, or special accelerator is required on any supported platform. Processing is multithreaded: by default the SDK uses number of cores βˆ’ 1 worker threads, and every detector constructor accepts a maxThreads parameter to bound this.

Camera and input

  • Input is raw frame data from a webcam, phone camera, or decoded video stream. The SDK does not open cameras itself; your application supplies pixel buffers.
  • Accepted pixel formats: RGB, BGR, RGBA, BGRA, YUV (NV21, I420, YUY2), and 8-bit grayscale (grayscale: C++/Python only).
  • Rotated inputs (90Β°/180Β°/270Β°) are handled by declaring the rotation on the Frame β€” useful for portrait-mounted cameras and phones.
  • The default processing rate is 30 fps and is configurable per detector. Higher input rates are simply downsampled by the asynchronous detector.

Licensing

A valid license key is required to use the SDK. The key is checked when a detector starts, and is resolved in this order:

  1. The string passed to the detector’s start(license) method, if non-empty.
  2. Otherwise, the AFFECTIVA_LICENSE_KEY environment variable.

If neither is provided, start() throws an exception. To obtain a license key or discuss licensing terms, contact sales@affectiva.com.

Frequently asked questions

Is inference real-time or batch?

Real-time, per frame. Your application pushes frames and receives metrics through its listener as each frame is processed. Two detector types cover both use cases: FrameDetector processes asynchronously with real-time semantics (it drops frames rather than fall behind live input), while SyncFrameDetector processes every frame synchronously on the calling thread β€” the natural choice for offline analysis of recorded video, where dropping frames is not acceptable. The default processing rate is 30 fps and is configurable per detector.

What is the per-frame latency?

There is no single figure: per-frame cost depends on the CPU, the number of tracked faces, and which features are enabled. The SDK is designed to keep pace with live camera input at the default 30 fps on hardware meeting the hardware requirements. To measure for your deployment, run SyncFrameDetector on your target hardware and time process() β€” and enable only the features you need, which directly reduces per-frame cost.

How many concurrent streams can one instance handle?

One detector processes one stream. To analyze multiple streams in the same process, create one detector per stream and use the maxThreads constructor parameter to partition CPU cores between them (by default a detector uses cores βˆ’ 1 threads). The practical stream count is bounded by CPU cores; validate on your target hardware.

Does the SDK run on device, or does it call back to a server?

Everything runs on device. Inference executes locally on the CPU, the neural-network models are compiled into the library, and the SDK makes no network calls β€” no frames, metrics, or telemetry ever leave the machine. It works fully offline.

Which languages and platforms are supported, and which are first-class?

C++ is the core API and the most complete surface. The Python and Android (Java) APIs are bindings over the same native engine, so metric values are identical across platforms; minor API-surface differences are noted in the API reference. Supported targets are listed under Supported platforms: Linux (x86_64 and aarch64), Windows 10/11, and Android 8.0+ (arm64-v8a). macOS and iOS are not currently offered β€” contact your iMotions / Affectiva representative.

What does a reference implementation look like?

Each quick start contains a complete, runnable program β€” from project setup through processing video and reading metrics β€” and the integration itself is five calls: construct, enable features, register a listener, start, process. The SDK is a library linked into your application, not a hosted API, so most integration effort typically goes into your own camera or video plumbing rather than the SDK itself.

How are model updates delivered?

Models ship inside the SDK library and are versioned with it. Updating models means adopting a new SDK release on your own schedule β€” there are no forced redeploys, no runtime model downloads, and no hot-swapping. This is deliberate: deployments are reproducible and fully offline, and the models in the version you validated are the models that run in production.

What observability hooks does the SDK expose?

The SDK is a passive library: it emits no telemetry and has no built-in exporters for tools like Prometheus, CloudWatch, or Datadog. Instrument it from your application β€” listener callbacks are a natural point to count processed frames, faces, and callback-to-callback timing β€” and surface those measurements through your existing monitoring stack. Errors are reported as exceptions (asynchronous errors via ProcessStatusListener::onProcessingException; see the API reference for per-platform equivalents).

Get started

Metrics guide

Every metric explained in detail β€” what it represents, its facial-action basis, value ranges, and interpretation guidance.

C++ quick start

Link the native library, process video frames, and read metrics with a FaceListener.

Python quick start

Install the affvisionpy wheel and analyze webcam or video input with OpenCV.

Android quick start

Add the AAR to your Gradle project and process camera frames on device.

API reference

Every public class, method, and enum β€” documented per platform: C++, Python, and Android.