Skip to main content
iVentureTeam

boolean_update_flag

A checkbox that also answers a second question: did a human change this, or did the server? boolean_update_flag exists because an onchange cannot tell the difference.

Siddharth JambukiyaSiddharth JambukiyaOdoo Techno-Functional Consultant
August 27, 2026Updated August 27, 20266 min read
Technical nameboolean_update_flag
Field typesboolean
Viewsform, list
Modulesurvey, but nothing in the widget is survey-specific
Used in core1 occurrence, the question time limit block in survey
VersionsOdoo 20.0, Odoo 19.0, Odoo 18.0
No-code setupNo. It needs an options key and a context key that Studio cannot write
Alternativesinteger_update_flag, boolean, boolean_toggle

What the boolean update-flag field does

Odoo has no ordinary way to know whether a field changed because a person edited it or because the server recalculated it. A compute or an onchange writes to the record exactly like a user does, and by the time the value lands nothing remembers where it came from. Most of the time that does not matter. Occasionally it matters a lot.

The case core built this widget for is survey questions. A live session has a default time limit set on the survey; each question may override it. Odoo needs to know which questions were deliberately customized, so that changing the survey default updates the untouched ones and leaves the customized ones alone. A compute cannot answer that. A widget can, because it sits exactly where the human click happens.

So boolean_update_flag renders as a normal checkbox and adds one behavior: when the user toggles it, the widget compares the new value with a reference value taken from the field's context and writes the result of that comparison into a second boolean field. Different means customized, same means back to default.

What this means for your team

The pattern this widget implements is worth recognizing outside surveys, because it appears constantly in configuration screens: a global default, per-record overrides, and the need to know which records are overridden. Without that knowledge, changing the default either silently overwrites everyone's careful settings or refuses to touch anything, and both make users distrust the setting.

The comparison is symmetric, which is the detail people miss. Setting the value back to the default clears the flag, so a record does not stay marked as customized forever after one accidental click. Users can undo their own override without an administrator.

The cost is that this logic lives in the browser. Data imported by CSV, changed through the API, or written by an automation rule never passes through the widget, so the flag will not be updated. If your process depends on that flag being right for imported data, the comparison has to be repeated server side. Plan for that rather than discovering it after a migration.

Supported options in Odoo 19

The widget declares no supported options at all, so nothing below appears in developer tooling or in Studio. Both knobs were read directly from extractProps in the Odoo 19.0 source, and note that they live in two different places: one in the options dictionary, one in the context attribute.

OptionTypeWhat it does
flagFieldNamestring (options key, camelCase)Technical name of the boolean field that receives the comparison result. Written exactly like this, in camelCase, and required: there is no fallback if it is missing or misspelled.(since Odoo 18.0)
referenceValueboolean (context key)The value the checkbox is compared against, supplied through the field's context attribute rather than options. Any Python expression valid in the record's context works, including a field name. Required, and type-checked as a boolean.(since Odoo 18.0)

The option key is camelCase. Almost every option in Odoo is snake_case; this one is written flagFieldName, exactly as it appears in the source, and flag_field_name is silently ignored. Both props are declared without the optional marker, which means a missing flagFieldName or a missing referenceValue is a props validation error rather than a quiet fallback.

Working examples

The core usage, trimmed

<field name="is_time_customized" invisible="True"/>
<field name="is_time_limited" nolabel="1"
       widget="boolean_update_flag"
       options="{'flagFieldName': 'is_time_customized'}"
       context="{'referenceValue': survey_session_speed_rating}"/>

The flag field must be present in the view, and the reference value is an ordinary field expression evaluated in the record's context.

Reference value from a plain literal

<field name="send_reminder" widget="boolean_update_flag"
       options="{'flagFieldName': 'reminder_overridden'}"
       context="{'referenceValue': True}"/>

Legal and useful when the default is fixed rather than read from a parent record.

What does not work

<!-- snake_case key: ignored, then a props error -->
<field name="send_reminder" widget="boolean_update_flag"
       options="{'flag_field_name': 'reminder_overridden'}"/>

The extractor reads only options.flagFieldName. Anything else leaves the prop undefined, and the prop is required.

Eleven lines and one deliberate use of a private method

The class is eleven lines. It extends the standard BooleanField, declares two extra props and overrides onChange. The override calls super.onChange first, so the checkbox's own value is written exactly as it always was, then performs a second write: record._update({ [flagFieldName]: newValue !== referenceValue }).

Two details in that line are worth pulling out. The method is _update, the record's internal update, not the public update. The practical effect is that setting the flag does not itself trigger a server onchange round trip, which keeps the widget from re-entering the very machinery it was written to distinguish itself from.

The comparison is a strict inequality, so the reference value's type matters. The context expression is evaluated as Python, then reaches the prop declared as a boolean. A reference value of 1 rather than True will fail the props type check instead of quietly comparing wrong, which is the friendlier of the two failure modes.

The source docstring states the intent plainly: this behavior is enabled only when a user directly changes the value from the client, and not as a result of another onchange or compute. That sentence is the whole design rationale, and it is also the limitation. Nothing outside the browser sets this flag.

Version compatibility

VersionStatusNotes
Odoo 20.0In developmentNot released. Behavior identical on the development branch; only the Owl props syntax changes.
Odoo 19.0VerifiedVerified against the shipped source. Byte-identical to Odoo 18.
Odoo 18.0VerifiedFirst version. Same option key, same context key, same comparison.
Odoo 17.0Not availableWidget does not exist.
Odoo 16.0Not availableWidget does not exist.

Upgrade note. The widget arrived in Odoo 18 and the Odoo 18 and Odoo 19 files are byte-identical, so views carry over untouched. On Odoo 17 and earlier the widget does not exist; a backport is straightforward, but the surrounding survey fields it was written for do not exist there either.

What is changing in Odoo 20

Odoo 20 is expected at Odoo Experience in Brussels, 24 to 26 September 2026. The development branch is unstable and the notes below can still change; we re-verify this page once Odoo 20 ships.

No behavior change. The option key, the context key, the comparison and the use of the internal update path are all identical. The only difference is the migration to the new Owl props syntax, where the two props are declared with the schema helpers instead of the old static props object. That affects JavaScript that patches the widget, not view XML.

The core usage also survives: the survey question time limit block still uses the widget on the development branch.

Common problems and fixes

SymptomCause and fix
Props error mentioning flagFieldNameThe option is missing or written in snake_case; only options.flagFieldName is read. Use options="{'flagFieldName': 'your_flag_field'}" with that exact spelling.
Props error mentioning referenceValueNo referenceValue in the field's context, or it evaluates to something that is not a boolean. Add context="{'referenceValue': some_boolean_field}" and make sure the expression yields True or False.
The flag never changesThe flag field is not loaded in the view, so the update has nothing to write to. Add the flag field to the view, invisible="True" is enough.
The flag is wrong after an importThe comparison only runs in the browser when a user clicks. Imports and API writes bypass it. Repeat the comparison in a server-side hook if imported data must carry a correct flag.
The flag was set by a recalculationSomething other than this widget wrote the flag field, most likely a compute or an automation rule. Check for other writers on that field; the widget itself never fires outside a user click.
The flag stays true after reverting the valueThe revert happened through an onchange rather than a click, so the widget was not involved. Toggle the checkbox by hand to re-run the comparison, or clear the flag server side.

Boolean update-flag field vs the alternatives

WidgetBest forKey difference
boolean_update_flagKnowing that a person, not a compute, changed a checkboxWrites a second boolean field with the result of comparing the new value to a reference value
integer_update_flagThe same override tracking on a numeric fieldListens to the input's change event instead of overriding onChange
booleanAn ordinary checkboxWrites one field and knows nothing about defaults or overrides
boolean_toggleA checkbox that should read as an on/off switchSwitch styling, still a single-field write

Reach for this widget only when you truly need to know that a human made the change. If you just need a second field kept in step with the first, an onchange or a computed field is simpler, server side, and works for imports and API writes too. For a numeric field with the same requirement, use the twin widget integer_update_flag.

Frequently asked questions

What does boolean_update_flag do that an onchange cannot?+
It distinguishes a user click from a server recalculation. An onchange fires either way, so it cannot tell whether a person deliberately overrode a default. This widget only runs inside the checkbox's own click handler.
Why is the option key camelCase?+
Because the source reads options.flagFieldName literally. Odoo's convention is snake_case, and this widget is an exception; flag_field_name is ignored and then the required prop is missing.
Where does referenceValue come from?+
The field's context attribute, not its options. Core passes a related field from the parent survey, but any expression valid in the record's context works, including a literal True or False.
Does the flag update on import?+
No. The comparison lives entirely in the browser, so CSV imports, API writes and automation rules never set it. Repeat the logic server side if that matters.
Can I use it outside the survey app?+
Yes. Nothing in the twenty lines is survey-specific: it needs a boolean field to render, a boolean field to flag, and a reference value in context.

Fighting a settings screen that overwrites people's work?

Global defaults with per-record overrides look simple and then quietly cause support tickets for a year. We design and build that override logic properly, in the browser and on the server, as part of Odoo customization work on 16 through 19.

Book a free consultation

How this page was produced

The two knobs, their exact spellings, the required-prop declarations and the use of the record's internal update path were read from boolean_update_flag_fields.js on the Odoo 19.0 branch, and the usage pattern from survey/views/survey_question_views.xml in the same branch. Version coverage was established by comparing the file across the 16.0, 17.0, 18.0 and development branches. Spotted an error? Tell us and we will correct the page.