Step-by-Step Tutorial
Odoo 18 OWL dashboard empowers you to build custom, interactive dashboards right inside Odoo with minimal code. First, you will learn how to set up your module structure. Next, you will configure assets and QWeb templates. Then, you will implement a JSON controller for live data. Moreover, you will create OWL components to fetch and render data. Finally, you will test and deploy your dashboard in Odoo 18.
Prerequisites and Setup
Before you start building your Odoo 18 OWL dashboard, ensure you meet these requirements and follow these initial setup steps:
- Odoo 18 CE or EE installed and running. You can follow the official guide here: https://www.odoo.com/documentation/18.0/developer/reference/frontend/owl.html
- Developer Mode enabled in Odoo: Go to Settings → General Settings → Activate the developer mode.
- A working Python 3.8+ environment with required dependencies (
odoo,psycopg2, etc.). - Basic familiarity with Odoo module development and JavaScript.
First, create a new directory for your custom module in your addons path:
mkdir -p custom_addons/my_dashboard_owl
cd custom_addons/my_dashboard_owl
Then, create the following file and folder structure:
my_dashboard_owl/
├── __init__.py
├── __manifest__.py
├── controllers/
│ └── main.py
├── models/
│ └── __init__.py
├── static/
│ ├── src/
│ │ └── js/
│ │ └── dashboard.js
│ └── description/
│ └── icon.png
└── views/
└── dashboard_template.xml
Module Manifest and Asset Declaration
Next, you configure your module manifest to register dependencies, data files, and assets.
manifest.py Configuration
First, open __manifest__.py and add the following content:
{
'name': 'My OWL Dashboard',
'version': '1.0',
'summary': 'Custom dashboard using OWL in Odoo 18',
'author': 'Your Name',
'category': 'Tools',
'depends': ['web', 'sale'],
'data': [
'views/dashboard_template.xml',
],
'assets': {
'web.assets_backend': [
'my_dashboard_owl/static/src/js/dashboard.js',
],
},
'installable': True,
'application': False,
}
First, this manifest sets depends to include the web module for OWL support and sale to fetch sales order data. Next, it lists dashboard_template.xml under data so Odoo loads the QWeb template. Then, it adds your JavaScript file under web.assets_backend so Odoo bundles your OWL code into the backend interface.
QWeb Template and Client Action
Then, you will create a QWeb template to host your dashboard container and define a client action to display it.
dashboard_template.xml Structure
Create views/dashboard_template.xml with this content:
<odoo>
<!-- Load your JS asset -->
<template id="assets_backend_inherit" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/my_dashboard_owl/static/src/js/dashboard.js"></script>
</xpath>
</template>
<!-- Dashboard page template -->
<template id="dashboard_page" name="OWL Dashboard">
<t t-call="web.base_layout">
<div class="o_content">
<div class="o_dashboard_container" id="owl_dashboard"></div>
</div>
</t>
</template>
<!-- Client action to show dashboard -->
<record id="action_owl_dashboard" model="ir.actions.client">
<field name="name">OWL Dashboard</field>
<field name="tag">my_owl_dashboard_action</field>
<field name="target">current</field>
</record>
</odoo>
First, this file inherits web.assets_backend to load your dashboard.js file. Then, it declares a dashboard_page template that includes a <div id="owl_dashboard"/> element. Finally, it defines an ir.actions.client record with a custom tag so you can trigger this page via a menu or a button.
JSON Controller for Live Data
After that, you must create a backend controller to serve data to your OWL component.
controllers/main.py
Inside controllers/main.py, write:
from odoo import http
from odoo.http import JsonRequest
class DashboardController(http.Controller):
@http.route('/my_dashboard/data', type='json', auth='user')
def dashboard_data(self):
# Fetch last 20 confirmed sales orders
Order = http.request.env['sale.order']
orders = Order.search([
('state', 'in', ['sale', 'done'])
], limit=20, order='date_order desc')
# Prepare JSON response
data = []
for o in orders:
data.append({
'name': o.name,
'amount_total': float(o.amount_total),
'date_order': o.date_order.strftime('%Y-%m-%d'),
})
return data
First, this controller defines a JSON route at /my_dashboard/data. Next, it queries the sale.order model for the latest 20 orders in sale or done state. Then, it serializes each order into a simple dictionary. Finally, it returns the list as JSON.
OWL Component Implementation
Now, you will create your OWL component in JavaScript. This component will fetch data and render it.
static/src/js/dashboard.js
Open static/src/js/dashboard.js and add:
/** @odoo-module **/
import { Component, useState, onMounted } from 'owl';
class Dashboard extends Component {
setup() {
this.state = useState({ orders: [] });
onMounted(this.loadData.bind(this));
}
async loadData() {
const data = await this.env.services.rpc('/my_dashboard/data');
this.state.orders = data;
}
get totalRevenue() {
return this.state.orders.reduce((sum, o) => sum + o.amount_total, 0);
}
static template = owl.tags.xml/* xml */`
<div class="o_dashboard">
<h1>Sales Overview</h1>
<p>Total Revenue: <t t-esc="totalRevenue"/></p>
<table class="table table-striped">
<thead>
<tr><th>Order</th><th>Date</th><th>Amount</th></tr>
</thead>
<tbody>
<t t-foreach="state.orders" t-as="order">
<tr>
<td><t t-esc="order.name"/></td>
<td><t t-esc="order.date_order"/></td>
<td><t t-esc="order.amount_total"/></td>
</tr>
</t>
</tbody>
</table>
</div>`
}
// Mount function
document.addEventListener('DOMContentLoaded', () => {
const container = document.getElementById('owl_dashboard');
if (container) {
const app = new Dashboard();
app.mount(container);
}
});
First, this code imports OWL primitives (Component, useState, onMounted). Next, it defines the Dashboard class. Then, in setup(), it initializes state and fetches data after mount. Afterwards, it defines a computed property totalRevenue. Finally, it sets up the template to render the revenue and table.
Menu Integration
Moreover, you should add a menu item to launch your dashboard.
Adding a Menu Action
In dashboard_template.xml, add below the client action:
<menuitem id="menu_owl_dashboard"
name="OWL Dashboard"
parent="sale.menu_sale_root"
action="action_owl_dashboard"
sequence="10"/>
First, this menu appears under Sales. Next, clicking it triggers the client action defined earlier.
Testing Your Dashboard
After you install or upgrade your module in Odoo, follow these steps:
- Restart the Odoo server and update the app list.
- Install My OWL Dashboard from Apps.
- Navigate to Sales → OWL Dashboard.
- Confirm that the dashboard loads and displays recent orders.
- Verify the total revenue updates correctly.
If you encounter errors, check the browser console and Odoo logs. Moreover, ensure your routes and asset paths match your module name.
Best Practices and Tips
Performance Optimization
- First, limit JSON payload size by fetching only necessary fields.
- Next, implement pagination if you handle large datasets.
- Then, consider caching frequently used data with Odoo’s cache framework.
Styling and UX
- Apply Odoo’s built-in CSS classes (
.table,.table-striped) for consistent look. - Moreover, use OWL’s reactivity to update data in real time.
- Also, test on various screen sizes to ensure responsive layout.
Extending Functionality
- You can add charts using Chart.js. First, load the library in
assets_backend. Then, render a<canvas>and draw charts inonMounted(). - Next, include filters by adding inputs and binding them to state. Then, filter
state.ordersin your template.
Troubleshooting Common Issues
- Module not found: Ensure
folder nameequals module name. - Asset not loading: Clear the browser cache and Odoo static files cache (
--dev=assets). - RPC errors: Check route path and authentication.
- Template errors: Validate your QWeb syntax with Odoo’s QWeb editor.
Conclusion
First, you set up your Odoo 18 OWL dashboard module structure. Next, you configured the manifest and assets. Then, you created the QWeb template and client action. Moreover, you implemented a JSON controller to serve live data. After that, you built an OWL component to fetch and render data. Finally, you integrated a menu, tested your dashboard, and reviewed best practices.
Now, you can extend this dashboard with charts, filters, and real-time updates to deliver a powerful analytics tool inside Odoo 18.
Happy coding!
Discover more from teguhteja.id
Subscribe to get the latest posts sent to your email.


Pingback: OWL framework tutorial: 7 Essential Steps to Instantly Master Odoo Frontend