diff --git a/main.js b/main.js
index acbbeaf807c3d3560ecd347fcd5cd02ea5a037d6..85bd2b42d614c66c930baad5d08453a75fe60265 100644
--- a/main.js
+++ b/main.js
@@ -5,6 +5,7 @@ const MOMENT = require('moment')
 
 const MENU_URL = 'https://www.studierendenwerk-aachen.de/speiseplaene/ahornstrasse-w-en.html'
 
+const fetchTime = MOMENT()
 AXIOS.get(MENU_URL)
   .then(processResponse)
   .catch(err => console.error('ERR: ', err));
@@ -13,9 +14,21 @@ function processResponse(response) {
   const dom = new JSDOM(response.data)
   const doc = dom.window.document
   const daysDom = doc.querySelectorAll('.accordion > div')
+  const additivesDom = doc.querySelector('#additives')
   const daysParsed = [...daysDom].map(parseDay)
+  const daysMap = {}
+  daysParsed.forEach(d => {  daysMap[d.date] = d })
+  const additives = parseAdditives(additivesDom)
 
-  console.log(JSON.stringify(daysParsed))
+
+  const result = {
+    days: daysMap,
+    additives,
+    url: MENU_URL,
+    fetchedAt: fetchTime.format()
+  }
+
+  console.log(JSON.stringify(result))
 }
 
 function parseDay(dayDom) {
@@ -27,12 +40,14 @@ function parseDay(dayDom) {
   const extrasDom = dayDom.querySelectorAll('table.extras tr')
 
   const menues = [...menuesDom].map(parseMenuEntry)
+  const extras = [...extrasDom].map(parseExtrasEntry)
 
   return {
     date: date.format('YYYY-MM-DD'),
     label: titleText,
     today: isActive,
     menu: [...menues],
+    extras,
   }
 }
 
@@ -50,8 +65,8 @@ function parseMenuEntry(row) {
     case 'bg-color': return null
     default: return '?:'+cls
   }}).filter(e => !!e)
-  const categoryDom = row.querySelector('menue-category');
-  const priceDom = row.querySelector('menue-price');
+  const categoryDom = row.querySelector('.menue-category');
+  const priceDom = row.querySelector('.menue-price');
   const descDom = row.querySelector('.expand-nutr')
   const nutrDom = row.querySelector('.nutr-info')
 
@@ -69,6 +84,30 @@ function parseMenuEntry(row) {
   }
 }
 
+function parseExtrasEntry(row) {
+  const categoryDom = row.querySelector('.menue-category');
+  const descDom = row.querySelector('.menue-desc')
+  const nutrDom = row.querySelectorAll('.nutr-info')
+
+  const category = categoryDom ? categoryDom.textContent : undefined
+  const description = parseDescription(descDom)
+  const nutrition = [...nutrDom].map(parseNutrition)
+  const count = Math.max(description.length, nutrition.length)
+
+  let options = [];
+  for (let i = 0; i < count; i++) {
+    options.push({
+      description: description[i] || null,
+      nutrition: nutrition[i] || null,
+    })
+  }
+
+  return {
+    category,
+    options,
+  }
+}
+
 function parseDescription(descDom) {
   const parts = []
   descDom.childNodes.forEach(node => {
@@ -89,8 +128,10 @@ function parseDescription(descDom) {
 }
 
 function parseNutrition(nutrDom) {
+  if (nutrDom.textContent === '-') return null
   const values = {}
-  nutrDom.querySelector('div').childNodes.forEach(node => {
+  const container = nutrDom.querySelector('div') || nutrDom
+  container.childNodes.forEach(node => {
     if (node.nodeName !== '#text') return;
     const match = node.data.match(/^\s*([^=]*?)\s*=\s*(.*?)\s*$/)
     if (!match) { // should not happen ...
@@ -111,3 +152,25 @@ function parseNutrition(nutrDom) {
   })
   return values
 }
+
+function parseAdditives(additivesDom) {
+  const rawText = additivesDom.textContent
+  const values = {}
+  rawText
+    .split(',')
+    .forEach(s => {
+      const matches = s
+        .trim()
+        .replace(/^\s*(with|contains)\s*/, '')
+        .match(/^\((.*?)\)\s*(.*?)$/)
+      if (!matches) {
+        if (!values['_?']) values['_?'] = []
+        values['_?'].push(s)
+        return
+      }
+      const symbol = matches[1]
+      const text = matches[2]
+      values[symbol] = text
+    })
+  return values
+}
diff --git a/package-lock.json b/package-lock.json
index 8ab5eea0a2d755c4b5d6ced9e4ed50865cb4a0f5..b37d166ac93b54bb8ec6296d176023c2d9f99ad7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -440,6 +440,11 @@
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
       "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
     },
+    "mustache": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.0.0.tgz",
+      "integrity": "sha512-FJgjyX/IVkbXBXYUwH+OYwQKqWpFPLaLVESd70yHjSDunwzV2hZOoTBvPf4KLoxesUzzyfTH6F784Uqd7Wm5yA=="
+    },
     "nwsapi": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz",
diff --git a/package.json b/package.json
index 6551ca8287994fd0b56121f1a97123bc07fd5008..7c0726b38d0ee9bb4298faaf6aa73f878a002195 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
   "dependencies": {
     "axios": "^0.19.2",
     "jsdom": "^16.2.0",
-    "moment": "^2.24.0"
+    "moment": "^2.24.0",
+    "mustache": "^4.0.0"
   }
 }