In modern business applications, integrating enterprise systems with mobile apps is essential. Odoo, one of the most popular open-source ERP platforms, provides powerful APIs to manage business data. Flutter, on the other hand, enables developers to build high-performance cross-platform applications.
In this blog, we will explore how to read Odoo records using filters (domains) in Flutter, allowing you to fetch only relevant data based on specific conditions.
This guide is useful for developers building mobile ERP systems, CRM apps, HR management tools, and more.
What Are Domains in Odoo?
In Odoo, a domain is a list of conditions used to filter records. Domains are similar to SQL WHERE clauses.
Example Domain
[("state", "=", "done"), ("amount", ">", 1000)]This domain retrieves records where:
- state is done
- amount is greater than 1000
Domains are commonly used in:
- search()
- search_read()
- read_group()
Architecture: Flutter and Odoo Integration
Flutter communicates with Odoo using XML-RPC or JSON-RPC APIs.
Typical flow:
Flutter App > HTTP Request > Odoo Server > Response > Flutter UI
In most Flutter-Odoo integrations, developers use JSON-RPC for better compatibility.
Required Dependencies in Flutter
Add the following dependencies to your pubspec.yaml file:
dependencies:
http: ^1.1.0
Then run:
flutter pub get
Step 1: Create Odoo API Service
Create a service file odoo_service.dart to manage API calls.
import 'dart:convert';
import 'package:http/http.dart' as http;
class OdooService {
final String url;
final String db;
final String username;
final String password;
int? uid;
OdooService({
required this.url,
required this.db,
required this.username,
required this.password,
});
/// Authenticate User
Future<void> authenticate() async {
final uri = Uri.parse('$url/jsonrpc');
final response = await http.post(
uri,
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
"jsonrpc": "2.0",
"method": "call",
"params": {
"service": "common",
"method": "login",
"args": [db, username, password]
},
"id": 1
}),
);
final data = jsonDecode(response.body);
uid = data['result'];
}
}
Step 2: Reading Records Using Domains
After authentication, we can use the search_read method to fetch filtered records.
Example: Fetch Employees from HR Module
Future<List<dynamic>> fetchEmployees() async {
final uri = Uri.parse('$url/jsonrpc');
final response = await http.post(
uri,
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
"jsonrpc": "2.0",
"method": "call",
"params": {
"service": "object",
"method": "execute_kw",
"args": [
db,
uid,
password,
"hr.employee",
"search_read",
[
[
["department_id", "=", 3],
["active", "=", true]
]
],
{
"fields": ["name", "job_title", "work_email"],
"limit": 20
}
]
},
"id": 2
}),
);
final result = jsonDecode(response.body);
return result['result'];
}Step 3: Understanding Domain Syntax
Domains use a list of triplets:
[field, operator, value]
Common Operators
| Operator | Description |
| = | Equals |
| != | Not equal |
| > | Greater than |
| < | Less than |
| >= | Greater or equal |
| <= | Less or equal |
| ilike | Case-insensitive contains |
| in | In list |
Step 4: Using Logical Operators
Odoo supports logical operators:
| Operator | Meaning |
| & | AND |
| | | OR |
| ! | NOT |
Example: OR Condition
[
'|',
['state', '=', 'draft'],
['state', '=', 'confirmed']
]
Example: Complex Domain
[
'&',
['active', '=', true],
'|',
['country_id', '=', 1],
['country_id', '=', 2]
]
Step 5: Display Data in Flutter UI
Example using FutureBuilder:
FutureBuilder<List<dynamic>>(
future: odooService.fetchEmployees(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
final employees = snapshot.data!;
return ListView.builder(
itemCount: employees.length,
itemBuilder: (context, index) {
final emp = employees[index];
return ListTile(
title: Text(emp['name']),
subtitle: Text(emp['job_title'] ?? ''),
);
},
);
},
)
Performance Tips
To optimize performance when using domains:
- Use limit and offset for pagination
- Select only required fields
- Avoid unnecessary nested domains
- Use indexed fields for filtering
- Cache frequently used data
Security Best Practices
- Never hardcode credentials in production
- Use environment variables
- Enable HTTPS
- Use Odoo access rules
- Restrict API permissions
Common Errors and Solutions
1. Authentication Failed
Ensure correct database name and credentials.
2. Invalid Domain Format
Check domain structure and operators.
3. Access Rights Error
Verify user permissions in Odoo.
Real-World Use Case
Employee Management App
Using domains, you can:
- Filter employees by department
- Show active staff only
- Search by job role
- Display region-wise data
This helps in building powerful HR mobile systems integrated with Odoo.
Reading Odoo records with domains in Flutter is the foundation for building intelligent, data-driven business applications. By leveraging search_read with well-structured domain filters, you can deliver real-time, role-specific data to users — whether it's live inventory, filtered reports, or job-specific records on the go.
The real strength here lies in flexibility. Domains let you filter by virtually any field condition, keeping your Flutter app perfectly in sync with the business logic your Odoo backend already enforces — no redundancy, no duplicated rules.
As you scale, consider pairing domain queries with pagination, caching, and role-based filtering to maintain performance across larger datasets.
We also specialize in Odoo development, Flutter mobile integration, and custom ERP solutions — helping businesses build scalable, production-ready applications. Whether you're architecting a new mobile app, optimizing Odoo workflows, or integrating third-party systems, we're here to help you build it the right way.
To read more about How to Integrate RESTful APIs in Flutter Applications, refer to our blog How to Integrate RESTful APIs in Flutter Applications.