contact_image
New in Odoo 19: the photo frame on contact and user forms is its own widget. contact_image extends the image field with one trick, when the photo is empty it shows the record's generated avatar and a centered Add Photo button.
| Technical name | contact_image |
|---|---|
| Field types | binary, many2one |
| Views | form |
| Module | web, present in every Odoo database |
| Used in core | 3 occurrences in hr's user form, plus 5 more on the base res.partner and res.users forms |
| Versions | Odoo 20.0, Odoo 19.0 |
| No-code setup | No. Applied in view XML together with an invisible preview field |
| Alternatives | image, attachment_image, background_image |
What the Contact Image field does
What this means for your team
Supported options in Odoo 19
| Option | Type | What it does |
|---|---|---|
preview_image | field name | Binary field rendered instead of the main field, and, specific to this widget, shown as the empty-state fallback. Core always passes avatar_128 and loads it invisibly in the view. Effectively required here. |
size | selection [width,height] | Display box as [width, height]; a zero side is treated as unset. Core contact forms use [130,130] and [100,100]. The size option beats width and height attributes. |
zoom | boolean | Shows an enlarged preview on hover. The base users form enables it; combine with zoom_delay to tune the hover delay. |
zoom_delay | number (ms) | Milliseconds before the hover zoom appears. Only meaningful together with zoom. |
accepted_file_extensions | string | Comma-separated extension filter passed to the file picker for uploads, for example '.png,.jpg'. |
convert_to_webp | boolean | Converts the uploaded image to WebP and generates the resized attachment set, same pipeline as the image widget. |
reload | boolean | Reloads the image after saving so the freshly stored version replaces the local preview.(default: true) |
img_class | string (undocumented) | Extra CSS classes for the img element, read only in extractProps and absent from the declared options. Core passes rounded-4 on user forms and rounded border on partner forms. |
The preview field must be loaded in the view. Every core usage places <field name="avatar_128" invisible="1"/> right next to the widget, with the source comment Needed in contact_image widget. Omit it and the fallback silently renders nothing, because the record data simply does not contain the avatar.
Working examples
How the avatar fallback actually works
Version compatibility
| Version | Status | Notes |
|---|---|---|
| Odoo 20.0 | In development | Not released. Internals reworked on the development branch; options unchanged. See below. |
| Odoo 19.0 | Verified | Introduced here and adopted across partner, user and hr preference forms. |
| Odoo 18.0 | Not available | Widget does not exist; the same forms use image with preview_image. |
| Odoo 17.0 | Not available | Widget does not exist. |
| Odoo 16.0 | Not available | Widget does not exist. |
Upgrade note. Views written for Odoo 18 or earlier use widget="image" with preview_image on these same fields and keep working in 19 unchanged. Adopting contact_image during an upgrade is a one-word view change per field, plus the invisible avatar_128 companion if it is not already in the view.
What is changing in Odoo 20
Common problems and fixes
| Symptom | Cause and fix |
|---|---|
| Empty contacts show a blank frame, not the initials avatar | The preview_image field is not loaded in the view, so the fallback has no data to render. Add the invisible companion: <field name="avatar_128" invisible="1"/> next to the widget. |
| Widget crashes or is missing after backporting a view | contact_image is 19.0-new; Odoo 16 to 18 have no such registration. Use widget="image" with the same options on older versions. |
| Custom model shows only an Add Photo button in the empty state | The model has no computed avatar field to fall back on, unlike partners and users. Add a computed binary in the avatar style, or accept the plain empty state. |
| Uploaded picture seems ignored | The file failed the image validation, and the widget quietly fell back to the avatar. Check the file really is a valid image below the field's size limit and try again. |
| Corners are square although the form looks rounded elsewhere | The rounding on core forms comes from the undocumented img_class option, not from the widget. Pass options="{'img_class': 'rounded-4'}" (or rounded border) like the core views. |
Contact Image field vs the alternatives
| Widget | Best for | Key difference |
|---|---|---|
contact_image | Profile photos on person-shaped forms: contacts, users, employees | Falls back to the preview_image field's generated avatar and shows a centered Add Photo button when empty |
| image | Any binary image with upload, zoom and sizing needs | Same option set, but the empty state is a static placeholder frame with a corner pencil button |
| attachment_image | Displaying one of the record's attachments, the kanban cover pattern | Reads a many2one to ir.attachment and offers no editing at all |
| background_image | Decorative image display without editing chrome | Bare lazy img rendering; no fallback, no upload overlay |
Frequently asked questions
Where does the colored initials avatar come from?+
Why do core views add an invisible avatar_128 field next to the widget?+
Can I use contact_image on my own model?+
Is contact_image available in Odoo 18?+
What sizes should the photo field use?+
Building a directory your team actually recognizes?
Employee registers, member databases and customer files all read better with faces on them. We wire up avatar fallbacks, photo pipelines and polished contact forms, contact_image included, as part of Odoo implementations on version 19.
Book a free consultation