Flutter icon

Flutter Quick Start Guide

Get started with FacePing's face recognition API using Flutter

Prerequisites

Installation

Create a new Flutter project and add required dependencies:

flutter create faceping_demo
cd faceping_demo

Update pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  http: ^1.2.0
  image_picker: ^1.0.7

Step 1: Create Face Group

Create lib/create_group.dart:

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

class CreateGroupWidget extends StatefulWidget {
  const CreateGroupWidget({super.key});

  @override
  State<CreateGroupWidget> createState() => _CreateGroupWidgetState();
}

class _CreateGroupWidgetState extends State<CreateGroupWidget> {
  final _groupNameController = TextEditingController();
  String _status = '';

  Future<void> _createGroup() async {
    try {
      final response = await http.post(
        Uri.parse('https://api.faceping.ai/groups/${_groupNameController.text}'),
        headers: {'Authorization': 'Bearer your_api_key_here'},
      );

      setState(() {
        _status = response.statusCode == 200
            ? 'Group created successfully'
            : 'Failed to create group';
      });
    } catch (e) {
      setState(() {
        _status = 'Error creating group';
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        TextField(
          controller: _groupNameController,
          decoration: const InputDecoration(
            labelText: 'Enter group name',
          ),
        ),
        const SizedBox(height: 16),
        ElevatedButton(
          onPressed: _createGroup,
          child: const Text('Create Group'),
        ),
        if (_status.isNotEmpty)
          Padding(
            padding: const EdgeInsets.only(top: 16),
            child: Text(_status),
          ),
      ],
    );
  }
}

Step 2: Upload Face Image

Create lib/upload_face.dart:

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:image_picker/image_picker.dart';
import 'dart:io';

class UploadFaceWidget extends StatefulWidget {
  const UploadFaceWidget({super.key});

  @override
  State<UploadFaceWidget> createState() => _UploadFaceWidgetState();
}

class _UploadFaceWidgetState extends State<UploadFaceWidget> {
  File? _image;
  String _status = '';
  final _picker = ImagePicker();

  Future<void> _pickImage() async {
    final pickedFile = await _picker.pickImage(source: ImageSource.gallery);
    if (pickedFile != null) {
      setState(() {
        _image = File(pickedFile.path);
      });
      await _uploadFace();
    }
  }

  Future<void> _uploadFace() async {
    if (_image == null) return;

    try {
      var request = http.MultipartRequest(
        'POST',
        Uri.parse('https://api.faceping.ai/groups/my-group/faces'),
      );

      request.headers['Authorization'] = 'Bearer your_api_key_here';
      request.files.add(
        await http.MultipartFile.fromPath('image', _image!.path),
      );

      final response = await request.send();
      setState(() {
        _status = response.statusCode == 200
            ? 'Face uploaded successfully'
            : 'Failed to upload face';
      });
    } catch (e) {
      setState(() {
        _status = 'Error uploading face';
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ElevatedButton(
          onPressed: _pickImage,
          child: const Text('Select Image'),
        ),
        const SizedBox(height: 16),
        if (_image != null)
          Image.file(
            _image!,
            height: 200,
            width: 200,
            fit: BoxFit.cover,
          ),
        if (_status.isNotEmpty)
          Padding(
            padding: const EdgeInsets.only(top: 16),
            child: Text(_status),
          ),
      ],
    );
  }
}

Step 3: Search for Faces

Create lib/search_faces.dart:

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:image_picker/image_picker.dart';
import 'dart:convert';
import 'dart:io';

class SearchFacesWidget extends StatefulWidget {
  const SearchFacesWidget({super.key});

  @override
  State<SearchFacesWidget> createState() => _SearchFacesWidgetState();
}

class _SearchFacesWidgetState extends State<SearchFacesWidget> {
  File? _image;
  String _status = '';
  List<double> _matches = [];
  final _picker = ImagePicker();

  Future<void> _pickImage() async {
    final pickedFile = await _picker.pickImage(source: ImageSource.gallery);
    if (pickedFile != null) {
      setState(() {
        _image = File(pickedFile.path);
      });
      await _searchFaces();
    }
  }

  Future<void> _searchFaces() async {
    if (_image == null) return;

    try {
      var request = http.MultipartRequest(
        'POST',
        Uri.parse('https://api.faceping.ai/groups/my-group/search'),
      );

      request.headers['Authorization'] = 'Bearer your_api_key_here';
      request.files.add(
        await http.MultipartFile.fromPath('image', _image!.path),
      );

      final response = await request.send();
      
      if (response.statusCode == 200) {
        final responseData = await response.stream.bytesToString();
        final data = json.decode(responseData);
        setState(() {
          _matches = (data['matches'] as List)
              .map((m) => m['score'] as double)
              .toList();
          _status = 'Found ${_matches.length} matches';
        });
      } else {
        throw Exception('Failed to search faces');
      }
    } catch (e) {
      setState(() {
        _status = 'Error searching faces';
        _matches = [];
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ElevatedButton(
          onPressed: _pickImage,
          child: const Text('Select Image'),
        ),
        const SizedBox(height: 16),
        if (_image != null)
          Image.file(
            _image!,
            height: 200,
            width: 200,
            fit: BoxFit.cover,
          ),
        if (_status.isNotEmpty)
          Padding(
            padding: const EdgeInsets.only(top: 16),
            child: Text(_status),
          ),
        if (_matches.isNotEmpty)
          Expanded(
            child: ListView.builder(
              itemCount: _matches.length,
              itemBuilder: (context, index) {
                return ListTile(
                  title: Text('Match Score: ${_matches[index].toStringAsFixed(2)}'),
                );
              },
            ),
          ),
      ],
    );
  }
}

Security Notes

  • Images are immediately discarded after vector conversion
  • Face vectors cannot be reverse-engineered into images
  • Always use HTTPS for all API calls
  • Store your API keys securely using environment variables

Ready to get started?

Take a look at the API documentation
API docs