Set Up User Context on Odoo
Pass the logged-in portal user's info to your chatbot from the Odoo website module
What You're Setting
User Context is a client-side JavaScript object. On every page where the widget loads for a logged-in user, you attach an object to window.Asyntai.userContext describing who they are. The widget sends this with each message, so the AI can reply with their name, order status, plan tier, or anything else relevant.
Keys act as labels the AI sees, so make them descriptive — use "Customer name" or "Loyalty points", not just "name" or "points".
window.Asyntai = window.Asyntai || {};
window.Asyntai.userContext = {
"Customer name": "Sarah Chen",
"Email": "sarah@example.com",
"Subscription plan": "Pro",
"Loyalty points": 1840,
"Last order": "#8847, out for delivery"
};
Two ways to set it
Either assign synchronously (if data is already on the page), or provide a fetcher that runs when the chat opens. The second option is better for performance — user data is only loaded when someone actually opens the chat.
// Option A — synchronous (data already available)
window.Asyntai.userContext = { "Customer name": "Sarah", ... };
// Option B — async fetch on chat open (better performance)
window.Asyntai.fetchUserContext = function() {
return fetch('/api/chat-context/')
.then(r => r.json())
.then(data => { window.Asyntai.userContext = data; });
};
Security & size: Never include passwords, credit card numbers, API tokens, or anything sensitive — this data is on the client and visible to anyone inspecting the page. Context is capped at 2,000 characters on Standard and 10,000 characters on Pro; if you exceed it, the tail is truncated.
How Odoo Exposes the User
Odoo's website module renders a global odoo.session_info JavaScript object on every front-end page. When a portal user is logged in, it contains uid, name, username (email), and partner_id — enough to identify the visitor.
Option 1 — QWeb Template Override
The cleanest integration is a tiny Odoo module that inherits website.layout and injects a script block before the closing body tag. Here's the minimal version:
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="asyntai_user_context" inherit_id="website.layout" name="Asyntai User Context">
<xpath expr="//body" position="inside">
<t t-if="not user_id._is_public()">
<script>
window.Asyntai = window.Asyntai || {};
window.Asyntai.userContext = {
"Customer name": "<t t-esc='user_id.name'/>",
"Email": "<t t-esc='user_id.partner_id.email or user_id.login'/>",
"Partner ID": <t t-esc='user_id.partner_id.id'/>
};
</script>
</t>
</xpath>
</template>
</odoo>
Package this in a tiny module (just __manifest__.py with depends: ['website'] plus views/templates.xml), install it, and the script runs site-wide for any logged-in non-public user.
Option 2 — Client-side session_info
If you'd rather skip building a module, add an inline script to the website's Customize → Custom Code area (available in Odoo 16+) that reads odoo.session_info directly:
<script>
(function waitForSession() {
if (!window.odoo || !window.odoo.session_info) return setTimeout(waitForSession, 50);
var s = odoo.session_info;
if (!s.uid || s.is_website_user === false) return; // public visitor
window.Asyntai = window.Asyntai || {};
window.Asyntai.userContext = {
"Customer name": s.name,
"Email": s.username,
"Partner ID": s.partner_id,
"Company": s.company_name || ''
};
})();
</script>
Adding Rich Portal Data
For orders, invoices, sales data — call a custom public controller (auth='user') that queries the current user's records and returns JSON:
# controllers/asyntai.py
from odoo import http
from odoo.http import request
import json
class AsyntaiContext(http.Controller):
@http.route('/asyntai/context', type='http', auth='user', website=True)
def context(self):
p = request.env.user.partner_id
orders = request.env['sale.order'].sudo().search([
('partner_id', '=', p.id), ('state', 'in', ['sale', 'done'])
], limit=5, order='date_order desc')
data = {
'Customer name': p.name,
'Email': p.email,
'Recent orders': [f"{o.name} ({o.state})" for o in orders],
}
return request.make_response(json.dumps(data),
headers=[('Content-Type', 'application/json')])
Then wire it up client-side with fetchUserContext:
window.Asyntai = window.Asyntai || {};
window.Asyntai.fetchUserContext = function() {
return fetch('/asyntai/context', { credentials: 'include' })
.then(r => r.ok ? r.json() : null)
.then(data => { if (data) window.Asyntai.userContext = data; });
};
Rozwiązywanie problemów
Open your browser DevTools → Console → type window.Asyntai.userContext after the page loads. You should see your object. If it says undefined, your script didn't run — check the script order (context must be set after the widget script loads, or be re-set whenever the user logs in).
The widget reads window.Asyntai.userContext on every message. If a page loads fresh (no SPA routing), you need to set context on that page too. For single-page apps, set it once after login and update it whenever user data changes.
Re-assign window.Asyntai.userContext with the fresh data after any update. The next message the user sends will include the updated values — no page reload needed.
You're over the size limit (2k chars Standard, 10k Pro). Trim verbose fields — keep order history to last 2-3 items, truncate long descriptions, drop fields the AI doesn't need.
Visit the User Context settings page while logged in as a test user, then send a chat message. The status refreshes within a few seconds. If still empty, check the browser console for JavaScript errors and verify the object is set before the chat message is sent.
Privacy reminder: Only share fields relevant to the conversation. Passing a customer's full purchase history when they just want to ask a general question is wasteful and can confuse the AI. Scope context to what helps.