Skip to main content
iVentureTeam

additional_identifiers_list

New in Odoo 20. It renders a partner's additional identifiers, tax and registration numbers, from a JSON field whose shape is described by a second, server-computed field.

September 18, 2026Updated September 18, 20264 min read
Technical nameadditional_identifiers_list
Field typesjson
Viewsform
Also registered asPaired with additional_identifiers_button, which adds new types to the same field
Moduleweb, present in every Odoo 20 database
Used in core3 uses across Odoo 20 Community and Enterprise views, excluding tests. Does not exist in Odoo 19.
VersionsOdoo 20.0
No-code setupNo. The source states it is only for the additional_identifiers field on the res.partner form.
Alternativesadditional_identifiers_button, json, char

What the additional_identifiers_list widget does

Different countries want different numbers on a contact: a VAT number here, a company registration number there, a tax identification number somewhere else. Modeling that as a column per identifier does not scale, so Odoo 20 stores them in a single JSON field and describes the available types in a second, server-computed JSON field.

This widget renders the editable list. Its sibling, additional_identifiers_button, provides the dropdown that adds a new type. Both extend a shared base and both declare supportedTypes: ["json"].

The source is explicit about its scope: a comment states it is only used for the additional_identifiers JSON field of the res.partner form view.

What this means for your team

For any business trading across borders, this is the field that stops your contact form growing a new box every time you enter a new market. The set of identifiers a country needs is decided server-side and localization modules extend it.

The practical consequence for your team is that if an identifier your accountants need is missing from a contact, the fix is usually a localization module or a server-side change, not a view edit. Nothing in the XML controls which identifiers appear.

Working examples

The standard pairing on a contact form. Both widgets act on the same field:

<field name="additional_identifiers" widget="additional_identifiers_list"/>
<field name="additional_identifiers" widget="additional_identifiers_button"/>

The metadata field does not need placing in the view. Both widgets declare it as a dependency, so Odoo loads it for them.

How the metadata field controls what users see

Both widgets read the same companion field, declared as a dependency on each descriptor:

const METADATA_FIELD = "available_additional_identifiers_metadata";

const metadataFieldDependency = [{ name: METADATA_FIELD, type: "json", readonly: true }];

That metadata drives everything visible: each identifier type's label, its help text, its sort order and whether it is offered at all. None of it lives in the view, so a module adding a new identifier type changes what users see without touching any XML.

The display_optional flag is the part worth understanding, because it has three states rather than two:

  1. Unset. The type is offered in the Add dropdown and appears in the list once chosen. This is the normal case.
  2. "show". The type is always rendered in the list, empty and ready to fill, and is never offered in the dropdown because it is already there.
  3. "hide". The type is not offered in the dropdown at all. It only appears if the record already has a value for it.

The dropdown filter reads !v.display_optional, so any value of that flag removes the type from the Add menu. That is the single rule behind both the show and hide behaviors.

One more detail that surprises people: clearing a value does not store an empty string, it removes the key entirely. onUpdateValue trims the input and calls delete this.state.identifiers[identifierType] when the result is empty. So a type the user blanks out disappears from the list unless its metadata marks it "show". Writes are debounced by 50 milliseconds, so rapid typing produces one record update rather than one per keystroke.

Finally, the JSON parsing is deliberately forgiving. parseJson catches any error and returns an empty object, which means malformed stored data renders as an empty widget rather than a broken form. Quiet, but worth knowing when a partner shows no identifiers and you expect some: check the stored value before the view.

Version compatibility

VersionStatusNotes
Odoo 19.0Not availableDoes not exist, and neither does the field it renders.
Odoo 20.0VerifiedIntroduced in Odoo 20. Verified against the shipped 20.0 source.

This widget does not exist before Odoo 20.

What is changing in Odoo 20

Introduced in Odoo 20 as part of a broader rework of how partner identifiers are stored. Odoo 19 has neither widget and no additional_identifiers field to render.

Both widgets are written against the Odoo 20 runtime. They use useProps for prop declaration and OWL 3's proxy for component state, neither of which exists in Odoo 19, so they could not be backported without rewriting.

Common problems and fixes

SymptomCause and fix
An identifier row disappeared after the user cleared itAn empty value deletes the key rather than storing an empty string. Expected, unless the type's metadata marks it display_optional 'show', which keeps it rendered.
An identifier type is missing entirelyIt is not in the server-computed metadata, or it is flagged 'hide' and the record has no value for it. Check the metadata the server produces. Nothing in the view controls the available types.
The widget renders empty on a record you expect to have valuesparseJson catches malformed stored JSON and returns an empty object rather than failing. Inspect the stored field value directly.
The widget does nothing on another modelThe source states it is only for the additional_identifiers field on res.partner, and it depends on a specific metadata field. Use ordinary fields on your own models.

Additional_identifiers_list widget vs the alternatives

WidgetBest forKey difference
additional_identifiers_listEditing a partner's country-specific identifiersDriven entirely by a server-computed metadata field, with no view configuration
additional_identifiers_buttonAdding a new identifier typeThe dropdown half of the same pair
jsonSeeing the raw stored structureRead-only text, no editing
charA single identifier on your own modelA real column, so it is searchable and reportable

There is no alternative, because no other widget understands the metadata shape. If you need an identifier that the server does not offer, the honest answer is a server-side change rather than a different widget. For a one-off number on your own model, an ordinary char field is simpler and more reportable than a JSON blob.

Frequently asked questions

Where do Odoo 20's additional identifier types come from?+
From a server-computed companion field, available_additional_identifiers_metadata, which both widgets declare as a dependency. It carries each type's label, help text, sequence and display flag. Nothing in the view controls the list.
Why did an identifier row vanish when I cleared it?+
Because an empty value deletes the key rather than storing an empty string. The row only stays visible if the type's metadata marks it display_optional: "show".
Can I use this widget on my own model?+
No. The source states it is only for the additional_identifiers field on the res.partner form, and it depends on a specific metadata field. Use ordinary fields on your own models.

Trading across borders with a contact form that cannot keep up?

Every new market brings another tax or registration number, and most Odoo databases answer that with another custom field. We set up localizations properly so identifiers, tax rules and reporting all arrive together.

Talk to an Odoo consultant

How this page was produced

Verified by reading addons/web/static/src/views/fields/additional_identifiers/additional_identifiers.js on the 20.0 branch of a local clone of the official Odoo repository. The metadata dependency, the display_optional filtering, the key deletion on an empty value, the 50 millisecond debounce and the forgiving parseJson are all quoted or read directly from that file. The scope limitation comes from the file's own comment. The usage count comes from scanning every non-test XML file in Community, Enterprise and odoo/addons. Corrections welcome via our contact page.