Saltar al contenido

Fuentes de datos

Fuentes de datos

Orden de autoridad

No todas las fuentes valen lo mismo, y el motor lo sabe: evalúa por este orden y lo enseña en la tabla de fuentes de cada resultado.

#FuenteConfianzaPor qué ahí
1Etiqueta fotografiadaaltaEs el envase concreto, del mercado concreto, hoy
2Fabricante verificadoaltaIdentidad comprobada y documentación aportada
3Fuentes oficialesaltaAutoridades, retiradas
4GS1altaCuando haya licencia
5DistribuidormediaFeed propio, calidad desigual
6Open Food FactsmediaComunitaria: cualquiera la edita
7ComunidadbajaAportaciones sin revisar

«Verificado» en el nivel 2 significa identidad del proveedor de datos verificada. No significa producto seguro, y en ningún punto de la interfaz se insinúa lo contrario.

Cómo se combinan

Se analizan todas y sus resultados se funden, pero las discrepancias no se resuelven: se conservan. Si Open Food Facts dice una cosa y la etiqueta otra, el resultado es contradictoria y la acción sugerida es fotografiar el envase que la persona tiene delante.

Elegir la fuente optimista sería el fallo más fácil de cometer aquí, y el más difícil de detectar.

Open Food Facts

Base abierta y colaborativa. Se usa bajo Open Database License (ODbL).

Implementado:

  • API v2, endpoint /api/v2/product/{barcode}.json con fields acotado.
  • Caché local con caducidad de 7 días, poda por cuota y lectura de caducados como respaldo sin conexión, siempre con su fecha.
  • Una sola petición en vuelo por código: cortesía con una base gratuita.
  • Atribución con licencia y enlace al producto de origen, visible en la pantalla de fuentes.
  • Traducción de sus tags (en:gluten, en:nuts…) a identificadores canónicos.

Decisión de diseño que merece explicación: los campos estructurados de alérgenos y trazas de OFF no entran por un camino aparte. Se convierten en frases sintéticas en español (Contiene: gluten, leche.) y pasan por el mismo motor de reglas que una etiqueta fotografiada. Una sola ruta de decisión, no dos. Dos rutas acaban divergiendo, y la que menos se prueba es la que falla.

Limitación conocida: el User-Agent

Open Food Facts pide que las aplicaciones se identifiquen por User-Agent. El navegador no permite fijar esa cabecera, y ningún truco lo cambia.

Lo que se hace hoy: identificarse por parámetros de consulta (app_name, app_version), que es lo que sí se puede.

Lo que hay que hacer para producción: un proxy propio que ponga el User-Agent correcto, centralice la caché y absorba los límites de uso. Está en la lista de bloqueantes del README. El cliente ya acepta un base distinto, así que el cambio es de configuración, no de código.

Búsqueda: tres limitaciones averiguadas probando (16/09/2026)

Las tres condicionan el diseño, y las tres apuntan al mismo sitio.

1. El buscador nuevo no se puede usar desde un navegador. search.openfoodfacts.org da buenos resultados de texto libre pero no manda cabeceras CORS. Se usa /api/v2/search de world.openfoodfacts.org, que sí.

2. Un límite de uso es indistinguible de una caída de red. /api/v2/search está limitado por uso, y al pasarse no devuelve un 429: devuelve una página HTML con código 200, que además no lleva cabeceras CORS. Desde el navegador, fetch falla con un error de red y no hay forma de saber cuál de las dos cosas ha pasado.

Consecuencias implementadas:

  • Se reintenta también ante fallo de red, no solo ante 429.
  • Las esperas son de 3 y 5 segundos: el límite se cuenta por minuto, así que reintentar a los 300 ms solo gasta otro intento.
  • Se comprueba el content-type antes de parsear, por si la página de error sí llega (fuera del navegador, sí llega).
  • El mensaje al usuario no afirma cuál de las dos es. Dice que puede ser la cobertura o el ritmo, y le recuerda que escanear sí funciona.

3. El buscador no devuelve la lista de ingredientes. Devuelve código, nombre, marca y tags declarados (allergens_tags, traces_tags, labels_tags), pero no ingredients_text. Traerla obligaría a una petición por candidato.

Esta es la que más cambia el producto: una lista de resultados no es un análisis, es una preselección. Los tags declarados son datos reales y pasan por el mismo motor de reglas, pero con menos cobertura. Y el motor lo sabe: con esPreseleccion: true, un «no hemos detectado X» se degrada a información insuficiente, porque no hemos mirado los ingredientes. Lo único que puede salir en verde en una lista es una declaración de ausencia, que sí es un dato del envase.

Lo que la búsqueda ya está cazando

Filtrando galletas declaradas sin gluten en España, dos productos salieron como información contradictoria: Open Food Facts los tiene a la vez etiquetados no-gluten y con gluten en allergens_tags. Una implementación que se fiara del filtro los habría mostrado como aptos.

Lo que OFF no es

No es verdad clínica. Es una base comunitaria, muy útil y muy amplia, que cualquiera puede editar. Por eso:

  • Autoridad media, por debajo de la etiqueta y del fabricante.
  • Su fecha de última modificación se muestra siempre.
  • Si la información tiene más de un año, sale un aviso explícito de recencia.

Recencia

Se registran cuatro momentos distintos, porque no son lo mismo:

CampoQué es
first_seenCuándo vimos esta fuente por primera vez
last_seenCuándo la consultamos por última vez
last_verifiedCuándo alguien comprobó que seguía siendo correcta
source_updatedCuándo la fuente dice que se actualizó

Por encima de 365 días, el resultado lleva un aviso: «La información más reciente que tenemos es de hace N meses. Las fórmulas cambian.»

Versiones de producto

Un GTIN identifica un producto. No identifica una fórmula permanente. Una fórmula puede cambiar, y puede cambiar en un mercado y no en otro.

Por eso el modelo es producto + mercado + versión de fórmula + fecha (product_formulations), con un índice único que garantiza una sola fórmula vigente por producto y mercado, y superseded_by para encadenar el histórico.

Cuando alguien dice «el envase ha cambiado» y fotografía el nuevo, se crea una nueva versión. No se sobrescribe la anterior. El histórico es lo que permite avisar a quien tenía el producto en favoritos.

Cobertura real, medida (16/09/2026)

Muestreando 200 productos españoles de Open Food Facts por categoría:

Con lista de ingredientes96 %
Con alérgenos declarados84 %
Sin ninguna de las dos cosas2 %

Diez escaneos reales de galletas españolas se respondieron 10 de 10 sin tener que fotografiar nada.

El sesgo de esa medición, dicho: el buscador de OFF ordena por popularidad y completitud, así que la muestra favorece las fichas bien rellenadas. La cola larga —marca blanca, productos regionales, formatos nuevos— está peor. El caso que lo destapó fue real: las Galletas María Oro de Cuétara tienen ficha, nombre, marca y foto en OFF, y cero ingredientes.

Conclusión operativa: el escaneo resuelve la mayoría de las veces, y para el resto hay dos salidas, en este orden.

1. Fotografiar la etiqueta. Responde en segundos y sin depender de nadie. 2. Que esa lectura se quede. Es lo que evita que el siguiente se encuentre lo mismo.

Aportaciones de la comunidad

Estados posibles, y se muestran distintos:


UNVERIFIED  →  REVIEWED  →  LABEL EVIDENCE / MANUFACTURER

No existe, ni va a existir, un estado «verificado seguro». Si algún día hay una certificación propia, significará información validada, y así se dirá.

El volante, implementado


escaneo sin ingredientes
   ↓  «NOS FALTAN LOS INGREDIENTES», con el nombre del producto
fotografías la etiqueta
   ↓  OCR → análisis → TU RESPUESTA, que es lo que venías a buscar
   ↓  y DESPUÉS, opcional:
«¿nos ayudas a completar este producto?»
   ↓  POST /v1/contributions, con consentimiento explícito
cola de moderación
   ↓  nadie lo ve como etiqueta comprobada mientras tanto
aprobada → formulación vigente
   ↓
el siguiente escaneo responde al instante

Cuatro salvaguardas, todas comprobadas por tests:

1. Consentimiento explícito. Sin consent: true, 422. Y se registra en consents con su propósito y versión de política. 2. Se aporta el texto, no la foto. Son dos consentimientos distintos y aquí solo se pide el primero. 3. Validación antes de guardar. Si el motor no reconoce una lista de ingredientes, se rechaza: meter una foto del gato ensucia la base sin ayudar a nadie. 4. No se publica sin revisión. Entra como fuente comunidad, autoridad 7 de 7 y confianza baja, y no crea formulación vigente hasta que alguien la aprueba. Un test comprueba que lo aportado no se sirve antes de revisarlo.

Lo que falta de este bucle

  • Devolver la aportación a Open Food Facts. Su API de escritura existe. Si alguien completa una ficha aquí, debería completarse allí también: nos han dado los datos y lo justo es devolverlos.
  • OCR en servidor para las fotos que el navegador no resuelve.
  • Acuerdos con fabricantes y distribuidores. El portal de marcas ya está construido; lo que falta son las conversaciones, no el código.

Alertas oficiales por alérgeno no declarado

Esta fuente responde a una pregunta distinta de todas las demás. El resto dice qué lleva un producto según su etiqueta. Esta dice que la etiqueta está mal.

«Advertencia por presencia de gluten: gluten no declarado en salsas etiquetadas "sin gluten"» — AESAN, ES2026/517, 26/08/2026

Ese producto habría salido de nuestro motor como «declarado sin gluten», y el motor habría acertado sobre lo que ponía el envase. Ninguna cantidad de lectura de ingredientes detecta eso. Solo lo sabe la autoridad que lo investigó.

Por eso las alertas se pintan por encima del resultado del análisis, nunca dentro, y por eso el módulo que las lee no importa el motor. Ver packages/fuentes/src/alertas/modelo.js, que explica la trampa: el motor trata «sin gluten» como falso positivo a propósito, así que pasarle el texto de una alerta de gluten le haría concluir que ahí no hay gluten.

AESAN (España)

https://www.aesan.gob.es/alertas/buscador-alertas?type=8c7503b4-…

Publica los avisos del SCIRI, con una categoría propia para alergias e intolerancias. No tiene API: se leen sus páginas, una a una, con pausa entre ellas, una vez al día y fuera de la aplicación. Nunca desde el navegador de nadie.

Es la única fuente encontrada que publica el código de barras del producto afectado. Eso permite emparejar un escaneo con una alerta oficial sin adivinar.

Pero solo en 5 de los 57 avisos que mantiene publicados (medido el 16/09/2026). Los otros 52 identifican el producto por marca, nombre y lote. Esa es la limitación que manda sobre el diseño: el emparejamiento exacto por código cubre el 9 % de los casos, y el resto solo puede ofrecerse como pista.

Tres formatos de documento distintos conviven ahí, con las etiquetas escritas de varias maneras («Número de lote», «Números de lote», «Número de lotes», «Marca comercial», «Nombre de marca comercial») y algún : : de más al teclear. El analizador los aguanta y tiene un caso por cada variante en packages/motor/test/alertas.test.js, con las páginas reales guardadas en datos/alertas/fixtures/. Lo que no reconoce, lo anota como incidencia; no lo rellena.

Food Standards Agency (Reino Unido)

https://data.food.gov.uk/food-alerts/id.json?type=AA

API documentada, Open Government Licence v3, con los alérgenos ya codificados como URI en vez de escritos en prosa. Es lo que habría que poder pedirle a AESAN. type=AA aísla las alertas de alergia de las de Salmonella o cuerpos extraños.

Está aquí porque media despensa española lleva producto importado y el fabricante suele ser el mismo. Sale con su país y su organismo bien visibles.

No publica código de barras. Por eso sus avisos se leen y se buscan, pero no se emparejan con un escaneo: rellenar ese hueco adivinando emparejaría a alguien con una alerta que no es la suya.

Las fotos del envase

AESAN adjunta imágenes del producto afectado en casi todas sus alertas, y son el dato más útil que publica. Quien está delante de la despensa reconoce el bote de un vistazo; nadie compara un código de barras de trece cifras, y menos con prisa.

Por eso la foto va lo primero, antes del texto, tanto en el sitio como en la aplicación. El código de barras dejó de enseñarse: se sigue guardando, pero solo para que un escaneo pueda emparejarse con su alerta.

Se copian a nuestro dominio en vez de enlazarlas, y la razón de peso no es técnica. Si el navegador de alguien pide una imagen a aesan.gob.es mientras mira una alerta de gluten, el servidor de AESAN ve su IP junto a esa página. En una herramienta donde la persona consulta lo que no puede comer, eso es un dato de salud saliendo por la puerta de atrás. En esta aplicación no se carga nada de terceros; ver docs/PRIVACY.md.

Condiciones de reutilización, del aviso legal de AESAN: autoriza la reutilización, comercial incluida, con tres condiciones —no desnaturalizar el contenido, citar la fuente y decir la fecha de actualización—. Las tres se cumplen: las imágenes no se recortan ni se retocan, cada galería lleva debajo el organismo, la referencia y la fecha, y la alerta enlaza al original.

Lo único que se hace es reescalarlas a 1200 px y recomprimirlas a calidad 80, que baja una foto de 950 KB a 190 sin que deje de leerse la letra de la etiqueta. Eso está pendiente de revisión legal junto con el resto (docs/REGULATORY.md): reducir el tamaño no altera lo que se ve, pero «no desnaturalizar» es una condición que conviene que interprete alguien que sepa. Si la respuesta es que no, se guardan tal cual y ya está.

La FSA no incluye imágenes en su API.

Lo que NO se dice nunca

Que un producto no tiene alertas. La consulta devuelve checkedAt —cuándo miramos— y las listas. Que estén vacías significa que no hemos encontrado nada en las fuentes que cubrimos y a esa fecha; no que no exista. Puede que la autoridad no lo haya publicado todavía, que sea de un país que no cubrimos, o que nuestra copia esté vieja.

Tampoco se dice que un producto sea peligroso. Una alerta es de un lote. El mismo código de barras con otro lote puede estar perfecto, y por eso el lote va siempre delante, en monoespaciada, para poder compararlo carácter a carácter contra lo impreso en el envase.