# How to Integrate face_recognition with a Flask Web Service: A Complete Guide

> Integrate face_recognition with Flask by building an HTTP endpoint for image uploads. Extract encodings, compare faces, and return JSON results for seamless facial recognition in your web service.

- Repository: [Adam Geitgey/face_recognition](https://github.com/ageitgey/face_recognition)
- Tags: how-to-guide
- Published: 2026-03-06

---

**To integrate face_recognition with Flask, create an HTTP endpoint that accepts image uploads, extracts 128-dimensional face encodings using `face_recognition.face_encodings`, and compares them against known vectors with `face_recognition.compare_faces` to return JSON match results.**

The `face_recognition` library by ageitgey wraps dlib's deep learning models to provide a simple Python API for face detection and recognition. When you need to expose this functionality via HTTP, Flask serves as a lightweight framework for handling image uploads and returning structured responses, as demonstrated in the repository's [`examples/web_service_example.py`](https://github.com/ageitgey/face_recognition/blob/main/examples/web_service_example.py).

## Architecture Overview

A clean separation of concerns makes the integration maintainable. Flask handles HTTP request validation and JSON serialization, while the `face_recognition` library manages the computationally intensive work of image decoding, face detection, and encoding generation.

The data flow follows this pattern:

1. Client POSTs an image (`multipart/form-data`) to the Flask endpoint
2. Flask validates the file extension against an allowlist
3. The raw stream passes to `face_recognition.load_image_file`, which converts it to a NumPy RGB array
4. `face_recognition.face_encodings` generates 128-dimensional vectors for each detected face
5. `face_recognition.compare_faces` calculates Euclidean distance against known encodings (default threshold < 0.6)
6. Flask returns a JSON payload indicating detected faces and any matches

## Prerequisites and Installation

Both packages are available via pip. The `face_recognition` library includes `dlib` and pretrained model files, though Linux users may need system dependencies for compilation.

```bash
pip install flask face_recognition

```

On Ubuntu or Debian, install build dependencies first:

```bash
sudo apt-get install -y cmake libboost-dev libopencv-dev

```

## Building the Flask Web Service

### File Upload Validation

Before processing, validate incoming files to prevent path traversal and ensure compatible formats. The helper function `allowed_file` from [`examples/web_service_example.py`](https://github.com/ageitgey/face_recognition/blob/main/examples/web_service_example.py) checks extensions against a predefined set.

```python
ALLOWED_EXTENSIONS = {"png", "jpg", "jpeg", "gif"}

def allowed_file(filename):
    return "." in filename and \
           filename.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS

```

### Processing Images with face_recognition

The core integration happens in your route handler. Use `face_recognition.load_image_file` to read the uploaded file stream directly into a NumPy array, then extract encodings.

```python
import face_recognition

# Load image from file stream (Flask's FileStorage works directly)

image = face_recognition.load_image_file(file_stream)

# Returns list of 128-dimensional face encodings

face_encodings = face_recognition.face_encodings(image)

```

Each encoding represents facial features as a 128-dimensional vector suitable for mathematical comparison.

### Comparing Face Encodings

To identify individuals, compare extracted encodings against known reference vectors using `face_recognition.compare_faces`. This function computes Euclidean distance and applies a default tolerance of 0.6.

```python

# known_encoding is a pre-calculated 128-dim list

matches = face_recognition.compare_faces(
    [known_encoding], 
    face_encodings[0]
)

# Returns list of boolean values

is_match = matches[0]

```

Store known encodings in a dictionary mapping names to vectors for scalable lookups.

## Complete Implementation Example

Below is a production-ready Flask application derived from [`examples/web_service_example.py`](https://github.com/ageitgey/face_recognition/blob/main/examples/web_service_example.py), generalized to support multiple known faces and JSON responses.

```python

# app.py

import json
import face_recognition
from flask import Flask, request, jsonify, redirect

app = Flask(__name__)

# Configuration

ALLOWED_EXTENSIONS = {"png", "jpg", "jpeg", "gif"}

# Known faces: name -> 128-dim encoding

# In production, load these from a database or JSON file

KNOWN_FACES = {
    "Barack Obama": [
        -0.09634063, 0.12095481, -0.00436332, -0.07643753, 0.0080383,
        0.01902981, -0.07184699, -0.09383309, 0.18518871, -0.09588896,
        0.23951106, 0.0986533, -0.22114635, -0.1363683, 0.04405268,
        0.11574756, -0.19899382, -0.09597053, -0.11969153, -0.12277931,
        0.03416885, -0.00267565, 0.09203379, 0.04713435, -0.12731361,
        -0.35371891, -0.0503444, -0.17841317, -0.00310897, -0.09844551,
        -0.06910533, -0.00503746, -0.18466514, -0.09851682, 0.02903969,
        -0.02174894, 0.02261871, 0.0032102, 0.20312519, 0.02999607,
        -0.11646006, 0.09432904, 0.02774341, 0.22102901, 0.26725179,
        0.06896867, -0.00490024, -0.09441824, 0.11115381, -0.22592428,
        0.06230862, 0.16559327, 0.06232892, 0.03458837, 0.09459756,
        -0.18777156, 0.00654241, 0.08582542, -0.13578284, 0.0150229,
        0.00670836, -0.08195844, -0.04346499, 0.03347827, 0.20310158,
        0.09987706, -0.12370517, -0.06683611, 0.12704916, -0.02160804,
        0.00984683, 0.00766284, -0.18980607, -0.19641446, -0.22800779,
        0.09010898, 0.39178532, 0.18818057, -0.20875394, 0.03097027,
        -0.21300618, 0.02532415, 0.07938635, 0.01000703, -0.07719778,
        -0.12651891, -0.04318593, 0.06219772, 0.09163868, 0.05039065,
        -0.04922386, 0.21839413, -0.02394437, 0.06173781, 0.0292527,
        0.06160797, -0.15553983, -0.02440624, -0.17509389, -0.0630486,
        0.01428208, -0.03637431, 0.03971229, 0.13983178, -0.23006812,
        0.04999552, 0.0108454, -0.03970895, 0.02501768, 0.08157793,
        -0.03224047, -0.04502571, 0.0556995, -0.24374914, 0.25514284,
        0.24795187, 0.04060191, 0.17597422, 0.07966681, 0.01920104,
        -0.01194376, -0.02300822, -0.17204897, -0.0596558, 0.05307484,
        0.07417042, 0.07126575, 0.00209804
    ]
}

def allowed_file(name):
    return "." in name and name.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route("/", methods=["GET", "POST"])
def upload():
    if request.method == "POST":
        if "file" not in request.files:
            return redirect(request.url)

        file = request.files["file"]
        if file.filename == "" or not allowed_file(file.filename):
            return redirect(request.url)

        # Face processing pipeline

        img = face_recognition.load_image_file(file)
        encodings = face_recognition.face_encodings(img)

        response = {"face_found": bool(encodings), "matches": []}
        if encodings:
            for name, known_enc in KNOWN_FACES.items():
                match = face_recognition.compare_faces([known_enc], encodings[0])[0]
                if match:
                    response["matches"].append(name)

        return jsonify(response)

    # Simple HTML form for manual testing

    return """
    <!doctype html>
    <title>Face Recognition Demo</title>
    <h1>Upload a picture</h1>
    <form method="POST" enctype="multipart/form-data">
      <input type="file" name="file">
      <input type="submit" value="Upload">
    </form>
    """

if __name__ == "__main__":
    # Expose on all interfaces for Docker/Kubernetes usage

    app.run(host="0.0.0.0", port=5000, debug=False)

```

## Testing the API

Start the server locally:

```bash
python app.py

```

Send a test image using `curl`:

```bash
curl -X POST -F "file=@obama2.jpg" http://127.0.0.1:5000/

```

The service returns JSON indicating whether a face was detected and which known faces match:

```json
{
  "face_found": true,
  "matches": ["Barack Obama"]
}

```

## Key Source Files in the Repository

Understanding the underlying implementation helps with debugging and extending the service.

| File | Purpose | Key Functions |
|------|---------|---------------|
| [`examples/web_service_example.py`](https://github.com/ageitgey/face_recognition/blob/main/examples/web_service_example.py) | Reference Flask implementation demonstrating single-face matching | `allowed_file`, `detect_faces_in_image` |
| [`face_recognition/api.py`](https://github.com/ageitgey/face_recognition/blob/main/face_recognition/api.py) | Core library interface wrapping dlib models | `load_image_file`, `face_encodings`, `compare_faces` |
| [`setup.py`](https://github.com/ageitgey/face_recognition/blob/main/setup.py) | Dependency declarations including `dlib`, `numpy`, and `Pillow` | Package metadata |

The `face_recognition` library abstracts dlib's C++ inference behind a pure-Python API, while [`examples/web_service_example.py`](https://github.com/ageitgey/face_recognition/blob/main/examples/web_service_example.py) provides the HTTP scaffolding necessary for production deployments.

## Summary

- **Separate concerns**: Let Flask handle HTTP request validation and JSON serialization while `face_recognition` manages image processing and neural network inference.
- **Use `load_image_file`**: This function accepts file streams directly, eliminating the need to save uploads to disk before processing.
- **Leverage `compare_faces`**: The built-in Euclidean distance calculation with a 0.6 tolerance threshold provides accurate matching without manual vector math.
- **Validate inputs**: Always check file extensions and handle empty uploads to prevent processing errors.
- **Scale horizontally**: The stateless design allows you to containerize the Flask app and scale behind a load balancer, though GPU acceleration requires specific `dlib` compilation flags.

## Frequently Asked Questions

### How do I handle multiple known faces in a single Flask endpoint?

Store your reference encodings in a dictionary mapping names to 128-dimensional vectors. When processing an upload, iterate through the dictionary and use `face_recognition.compare_faces` against each known encoding. Append matching names to your response list. For production systems, load these encodings from a database or JSON file at startup rather than hard-coding them in memory.

### What is the default tolerance for face matching, and how do I adjust it?

The `face_recognition.compare_faces` function uses a default tolerance of 0.6, which corresponds to the Euclidean distance between 128-dimensional face encodings. Lower values (e.g., 0.5) make the system stricter and reduce false positives, while higher values (e.g., 0.7) increase recall. Pass the `tolerance` parameter explicitly: `face_recognition.compare_faces([known], unknown, tolerance=0.5)`.

### Can I process images without saving them to disk in Flask?

Yes. The `face_recognition.load_image_file` function accepts file-like objects, including Flask's `FileStorage` streams from `request.files`. Pass the file object directly without calling `save()`: `img = face_recognition.load_image_file(request.files['file'])`. This keeps your service stateless and avoids disk I/O bottlenecks, making it suitable for containerized deployments.

### How do I deploy this Flask service in a Docker container?

Create a Dockerfile that installs system dependencies (`cmake`, `libboost-dev`, `libopencv-dev`) before installing Python packages. Copy your [`app.py`](https://github.com/ageitgey/face_recognition/blob/main/app.py) and any known face encodings, then expose port 5000. Use `app.run(host="0.0.0.0", port=5000, debug=False)` to ensure the server accepts connections from outside the container. For GPU acceleration, use an NVIDIA CUDA base image and compile `dlib` with CUDA flags enabled.