Proposal for a new personalized experience in the Open Food Facts app and website

The Personal Search project introduced the idea of personalization in Open Food Facts: each user can set food preferences to declare which criteria he/she cares about, and how important it is.

Those settings currently have several effects on the Open Food Facts website:

  • On pages that list multiple products:
    • Each product card has small icons to show the status of each product attribute (e.g. Nutri-Score, no gluten, vegan, organic) the user cars about
      • The list of products on the page can be filtered and ranked according to the user’s food preferences
    • Product cards become green, red or grey depending on whether the product is compatible with the user’s preferences
      • Products are incompatible only if the user specified a product attribute is “mandatory”
    • Each product is scored against the user’s food preferences in order to first show the products that match the best
      • With the caveat that this scoring and re-ranking is done on the client-side, and only for the products shown on the page (up to 100 products).
  • On the product page:
    • At the top of the page, cards are shown to show the status of each product attribute the user cares about

With the new Open Food Facts app (code name Smoothie), we would like to go one step further in order to not only check if a product is compatible, but also to score how well it matches with the user preferences.

So here is a proposal on how we could make a new personalized experience on both the website and app:

Food preferences settings

We can keep the existing logic and settings from the website, with 4 possible levels for each product attribute:

  • not important
    • the attribute (e.g. the Nutri-Score or whether a product contains gluten) is not shown proeminently in product previews (product cards on the website, product scan cards in the app, product summary at the top of the product card)
    • the attribute is not used to check if a product is compatible and how well it matches
  • important
    • attribute shown proeminently, and used for scoring products
  • very important
    • attribute shown more proeminently (before important attributes), and with a greater weight for scoring products
  • mandatory
    • attribute shown first, with the greatest weight for scoring product
    • attribute also used to check if a product is compatible

The “mandatory” setting is for people who have strict restrictions (e.g. allergies, strict vegan or vegetarian diet etc).

While 4 levels may sound like a lot, having both “important” and “very important” is necessary in order to be able to have a gradation, otherwise every criteria has the same level (e.g. Nutri-Score + Eco-Score + NOVA + Organic).

Food product scoring according to user preferences

Instead of having only a “Compatible”, “Incompatible” and “Unknown” status when users have specified that some attributes are mandatory, we can compute a 0 to 100 score (today we compute a score for ranking, but it’s not normalized from 0 to 100) and have a gradation:

  • Very good match: 75% and above
  • Good match: 50% and above
  • Poor match: less than 50%
  • Unknown match: if too many of the selected attributes (e.g. 50% of the weights) are unknown.
    ** Note: if a selected attribute is unknown, for scoring, we consider it does not match.
  • Incompatible: only if the user specified a mandatory product attribute
  • May not be compatible: only if the user specified a mandatory product attribute

Visually, on both the website and app, we could show this gradation on a banner of top of product cards, with colors (e.g. green = very good, yellow / orange = good, red = poor, black = incompatible, or possibly green / yellow / orange / red).


We could try to use the banner to display an explanation (e.g. “May contain gluten” instead of just “Incompatible”), but it’s likely that we will have issues in many languages / for many attributes. (e.g. “Peut contenir des arachides” is longer)

We could also possibly display the corresponding % (e.g. in the summary card on top of product pages).


  • All users can get a clear visual cue of how good a product is, according to their criteria, or according to reasonable default values (currently set to Nutri-Score = very important, NOVA = important, Eco-Score = important).


  • Website: relatively straight forward as we already have pretty much everything need in place, we just need to normalize the scoring from 0 to 100, and compute the corresponding matching grade
  • App:
    • We need to go back to 4 levels for settings
    • We need to update the scoring in openfoodfacts-dart and use it instead of having a custom scoring
    • We need to show attributes selected by users instead of having a separate handling to put Nutri-Score and Eco-Score on top

Going further: always score products according to the user’s preferences but no re-order

The current system on the website is a bit bizarre: we get 100 results that are sorted server side (e.g. most scanned products, or most recently added/edited), and then users can switch on personalized results to see colors (green for compatible products, red for incompatible products) and to re-rank the results (but only the 100 listed on the page, that were ordered differently).

The greatest value of the “Personal Search” project is in the personalization of each indvidual result, not really on ranking of the results (because of the fact that we only have the 100 products ordered by something different).

So we could:

  1. Always show results that are individually personalized (with a very good / good / poor / incompatible setting).
  2. Remove the re-ranking of results.
  3. Remove the tabs for compatible / incompatible / unknown.

This would greatly simplify the interface, and also allow us to request and display less results per page.

If we want the users to get personalized ranking of results, then it’s probably a better idea to do it server side (which does mean that the user preferences would have to be communicated to us).

What do you think?

  1. Just a simple UX point, I think it’s enough to add the information on allergen in the upper banner (contient: gluten), and avoid it at the bottom to keep our actual scores.

  2. Concerning server side ranking :

  • I think it’s ok to eventually send the user preferences as a parameter of the request (you only need to send changes to the baseline)
  • a question: do you think it’s easy and efficient enough to do the ranking with a mongodb request ? (In elasticsearch you can sort according to a script, but after a quick search, I didn’t see it in mongo)

I don’t know. There are some ways to have a custom sort order in mongodb by adding extra aggregations steps (e.g. MongoDB sort with a custom expression or function - Stack Overflow ), but then that means we can’t use indexes and we have to score and rank all possibly matching products.

But we could do things a bit differently. e.g. do what we currently do client side (get a big number of results (between 100 and 1000), and then re-rank them), and possibly cache it server side.

Or we could have a separate database (e.g. in postgresql) that would be specifically tailored for searching.

That said, it’s still very complicated. Primael had chosen to separate allergens in his designs (here’s a Smoothified version of a screen he designed)


I think separating the things that are mandatory (deal breakers) from preferences is a great idea, it will solve our problem.

We can have 2 screens, each with binary settings:

  1. Restrictions
  • Vegan, Vegetarian
  • All allergens
  1. Preferences
  • Everything else

And we can put some of the restrictions available here as well:

  • Vegan, vegetarian
  • Allergens (or only selected allergens like gluten, milk, eggs)

The 1. Restrictions are only used to determine if a product is compatible, not compatible, or maybe not compatible (e.g. if we did not recognize one ingredient, we don’t know if it’s vegan or contains an allergen).

The 2. Preferences are used to categorize compatible products only in 3 different statuses: “Very good match”, “Good match”’, “Poor match” + “Unknown match” if the preferences correspond to too many unknown attributes.

I think that would simplify everything and make it much more clear what the settings do.

1 Like