Age-restricted products need a way to verify that a customer is old enough. Alcohol delivery, online gambling, vaping shops, and some social platforms require an age verification system by law. Most solutions rely on ID document uploads, which creates friction. A faster approach: estimate the customer's age from a selfie using a face analysis API.
This tutorial builds a complete age verification endpoint in Python using the Face Analyzer API.
Curious how it works? Try the Face Analyzer API on your own images.
How Face-Based Age Verification Works
The user takes a selfie. The API detects the face, analyzes facial features, and returns an estimated age range (e.g., 25-35). Your app checks whether the lower bound meets the legal threshold (18, 21, etc.).
This is faster than document verification (under 1 second vs 10-30 seconds), works on any device with a camera, and doesn't require the user to have their ID. Unlike biometric authentication that stores templates, this can be stateless: process the image, get the result, discard the photo.
What the API Returns
The /faceanalysis endpoint returns an AgeRange object with Low and High bounds for each detected face:
{
"statusCode": 200,
"body": {
"faces": [
{
"facialFeatures": {
"Gender": "Female",
"Smile": true,
"Eyeglasses": false,
"Sunglasses": false,
"AgeRange": { "Low": 9, "High": 15 },
"Emotions": ["HAPPY"]
}
}
]
}
}
AgeRange.Low is what matters. If it's below your threshold, the user doesn't pass. Using the lower bound is the conservative approach.
Age Verification Function in Python
import requests
API_URL = "https://faceanalyzer-ai.p.rapidapi.com/faceanalysis"
HEADERS = {
"x-rapidapi-host": "faceanalyzer-ai.p.rapidapi.com",
"x-rapidapi-key": "YOUR_API_KEY",
}
def verify_age(image_path: str, min_age: int = 18) -> dict:
"""Check if the person in the image meets the minimum age."""
with open(image_path, "rb") as f:
resp = requests.post(API_URL, headers=HEADERS, files={"image": f})
data = resp.json()
faces = data["body"]["faces"]
if not faces:
return {"allowed": False, "reason": "no face detected"}
age_range = faces[0]["facialFeatures"]["AgeRange"]
estimated_low = age_range["Low"]
estimated_high = age_range["High"]
allowed = estimated_low >= min_age
return {
"allowed": allowed,
"age_range": f"{estimated_low}-{estimated_high}",
"threshold": min_age,
"reason": "meets age requirement" if allowed else "below age threshold",
}
result = verify_age("selfie.jpg", min_age=21)
print(result)
# {"allowed": False, "age_range": "9-15", "threshold": 21, "reason": "below age threshold"}
Wrapping It in a Flask Endpoint
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/verify-age", methods=["POST"])
def verify_age_endpoint():
if "image" not in request.files:
return jsonify({"error": "no image provided"}), 400
image = request.files["image"]
min_age = int(request.form.get("min_age", 18))
resp = requests.post(
API_URL,
headers=HEADERS,
files={"image": ("selfie.jpg", image.read(), image.content_type)},
)
data = resp.json()
faces = data["body"]["faces"]
if not faces:
return jsonify({"allowed": False, "reason": "no face detected"}), 200
age_range = faces[0]["facialFeatures"]["AgeRange"]
allowed = age_range["Low"] >= min_age
return jsonify({
"allowed": allowed,
"age_range": {"low": age_range["Low"], "high": age_range["High"]},
"threshold": min_age,
})
if __name__ == "__main__":
app.run(port=5000)
See the full implementation with cURL and JavaScript examples in the complete age verification tutorial.
Testing It with cURL
curl -X POST \
'https://faceanalyzer-ai.p.rapidapi.com/faceanalysis' \
-H 'x-rapidapi-host: faceanalyzer-ai.p.rapidapi.com' \
-H 'x-rapidapi-key: YOUR_API_KEY' \
-F 'image=@selfie.jpg'
Compliance by Industry
- Alcohol delivery - 21 (US) / 18 (EU, UK). Face estimation + ID fallback for borderline cases
- Vaping / tobacco - 21 (US) / 18 (EU). Face estimation at checkout
- Online gambling - 18-21 depending on jurisdiction. Face estimation + full KYC for account creation
- Adult content - 18. Face estimation (UK Online Safety Act compliant)
- Social media - 13-16. Face estimation for parental consent flow
Regulations are tightening: UK Online Safety Act, US state laws (Louisiana, Virginia, Utah), EU Digital Services Act. An age verification API lets you add compliance in one endpoint call.
Handling Edge Cases
- No face detected - Blurry photo or no visible face. Ask the user to retake
- Multiple faces - Use the face with the largest bounding box (closest to camera)
-
Borderline age - API returns 16-22, threshold is 18. Use
AgeRange.Lowand deny, or offer an ID upload fallback -
Sunglasses - Check the
Sunglassesboolean in the response and ask to remove them - Spoofing - Someone holds up a printed photo. Add liveness detection (blink check, head turn) for high-risk use cases
Tips
- Always use
AgeRange.Lowfor the threshold check - the conservative approach protects you legally - Offer an ID upload fallback for borderline cases instead of flat-out rejecting users
- Don't store the selfie. Process, get the result, discard. Log only the decision for audit (GDPR)
- Set the threshold higher than the legal minimum (e.g., 21 instead of 18) for a safety margin
- Check the
Sunglassesfield and ask users to remove them for better accuracy
Read the full guide with comparison tables, JavaScript examples, and detailed compliance breakdown on ai-engine.net.
Top comments (0)