AutomationFlowsAI & RAG › Meal Planner: Cost Tracking, Leftover Recipes & Nutrition Diary in Google Sheets

Meal Planner: Cost Tracking, Leftover Recipes & Nutrition Diary in Google Sheets

Bytakuma @takuma on n8n.io

This template is for home cooks, small restaurant owners, or anyone who wants to streamline their meal planning, ingredient cost tracking, leftover management, nutritional analysis, and social media promotion. It's ideal for those looking to optimize their kitchen operations,…

Webhook trigger★★★★☆ complexityAI-powered18 nodesOpenRouter ChatOutput Parser StructuredGoogle SheetsTwitterAgent
AI & RAG Trigger: Webhook Nodes: 18 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #10967 — we link there as the canonical source.

This workflow follows the Agent → Google Sheets recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "iiX2o66wTdLNtnhT",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Meal Planner: Cost Tracking, Leftover Recipes & Nutrition Diary in Google Sheets",
  "tags": [],
  "nodes": [
    {
      "id": "3be82f45-7aad-4c17-80e6-a5ff30488753",
      "name": "OpenRouter Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        -1424,
        112
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "b0771629-a41c-498f-846d-032d4c9d752e",
      "name": "Structured Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        -1296,
        112
      ],
      "parameters": {
        "jsonSchemaExample": "[\n  {\n    \"json\": {\n      \"Date\": \"2023-10-27\",\n      \"Item\": \"Braised Pork Belly\",\n      \"Ingredients\": \"Pork Belly (block)\",\n      \"Ingredient Cost\": 800,\n      \"Unit Price\": \"1,600$/1kg\",\n      \"Quantity\": \"500g\",\n      \"Total\": 800,\n      \"Cost\": 1070,\n      \"Leftover Ingredients\": \"None\"\n    }\n  },\n  {\n    \"json\": {\n      \"Date\": \"2023-10-27\",\n      \"Item\": \"Braised Pork Belly\",\n      \"Ingredients\": \"Ginger\",\n      \"Ingredient Cost\": 50,\n      \"Unit Price\": \"100\u5186/100g\",\n      \"Quantity\": \"1 piece\",\n      \"Total\": 50,\n      \"Cost\": 1070,\n      \"Leftover Ingredients\": \"None\"\n    }\n  }\n]"
      },
      "typeVersion": 1.3
    },
    {
      "id": "2b8ad996-0b53-43b5-a391-3f0efc39d3a0",
      "name": "Append row in sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -1072,
        -128
      ],
      "parameters": {
        "columns": {
          "value": {
            "Cost": "={{ $json.output[0].json['Cost'] }}",
            "Date": "={{ $json.output[0].json['Date'] }}",
            "Item": "={{ $json.output[0].json['Item'] }}",
            "Total": "={{ $json.output[0].json['Total'] }}",
            "Quantity": "={{ $json.output[0].json['Quantity'] }}",
            "Unit Price": "={{ $json.output[0].json['Unit Price'] }}",
            "Ingredients": "={{ $json.output[0].json['Ingredients'] }}",
            "Ingredient Cost": "={{ $json.output[0].json['Ingredient Cost'] }}",
            "Leftover Ingredients": "={{ $json.output[0].json['Leftover Ingredients'] }}"
          },
          "schema": [
            {
              "id": "Date",
              "required": false,
              "displayName": "Date",
              "canBeUsedToMatch": true
            },
            {
              "id": "Item",
              "required": false,
              "displayName": "Item",
              "canBeUsedToMatch": true
            },
            {
              "id": "Ingredients",
              "required": false,
              "displayName": "Ingredients",
              "canBeUsedToMatch": true
            },
            {
              "id": "Ingredient Cost",
              "required": false,
              "displayName": "Ingredient Cost",
              "canBeUsedToMatch": true
            },
            {
              "id": "Unit Price",
              "required": false,
              "displayName": "Unit Price",
              "canBeUsedToMatch": true
            },
            {
              "id": "Quantity",
              "required": false,
              "displayName": "Quantity",
              "canBeUsedToMatch": true
            },
            {
              "id": "Total",
              "required": false,
              "displayName": "Total",
              "canBeUsedToMatch": true
            },
            {
              "id": "Cost",
              "required": false,
              "displayName": "Cost",
              "canBeUsedToMatch": true
            },
            {
              "id": "Leftover Ingredients",
              "required": false,
              "displayName": "Leftover Ingredients",
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "output"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {
          "cellFormat": "USER_ENTERED"
        },
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultUrl": "",
          "cachedResultName": "recipe"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultUrl": "",
          "cachedResultName": "Recipe List"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "1c6ad655-8149-43f7-bd94-4c1c22570751",
      "name": "Append row in sheet1",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        80,
        -128
      ],
      "parameters": {
        "columns": {
          "value": {
            "Diary": "={{ $json.output }}"
          },
          "schema": [
            {
              "id": "Diary",
              "required": false,
              "displayName": "Diary",
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Diary"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultUrl": "",
          "cachedResultName": "diary"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultUrl": "",
          "cachedResultName": "Recipe List"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "c24b82e7-52b5-44f3-9bd7-e739001d1975",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -1648,
        -128
      ],
      "parameters": {
        "path": "your-webhook-path",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2.1
    },
    {
      "id": "57916f99-a102-4af8-a262-9a23705f2d90",
      "name": "OpenRouter Chat Model1",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        384,
        112
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "90922a4d-9fe2-4542-a1bd-b41836212cea",
      "name": "OpenRouter Chat Model2",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        -208,
        112
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "88c896f1-6444-406f-9b99-6c2cade605b0",
      "name": "OpenRouter Chat Model3",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        -784,
        112
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "8dea555e-872d-46ab-bfe3-cbaa25acb606",
      "name": "Append row in sheet2",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -496,
        -128
      ],
      "parameters": {
        "columns": {
          "value": {
            "Date": "={{ $('Menu Agent').item.json.output[0].json['Date'] }}",
            "Ingredients": "={{ $json.output }}"
          },
          "schema": [
            {
              "id": "Date",
              "required": false,
              "displayName": "Date",
              "canBeUsedToMatch": true
            },
            {
              "id": "Ingredients",
              "required": false,
              "displayName": "Ingredients",
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultUrl": "",
          "cachedResultName": "leftovers"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultUrl": "",
          "cachedResultName": "Recipe List"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "9d3cb079-4053-4f31-a82e-8def53383c4c",
      "name": "Create Direct Message",
      "type": "n8n-nodes-base.twitter",
      "position": [
        656,
        -128
      ],
      "parameters": {
        "text": "={{ $json.output }}",
        "user": {
          "__rl": true,
          "mode": "username",
          "value": ""
        },
        "resource": "directMessage",
        "additionalFields": {}
      },
      "typeVersion": 2
    },
    {
      "id": "a06637b5-b25b-4e18-a391-1a459bb733ac",
      "name": "Menu Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -1424,
        -128
      ],
      "parameters": {
        "text": "={{ $json.body }}",
        "options": {
          "systemMessage": "You are a housekeeper. From the searched content, output the necessary ingredients and costs. You do not need to show the cost per use for seasonings. Costs should be shown as both the total amount for one shopping trip and the unit price. Include units for ingredients and prices."
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 3
    },
    {
      "id": "62fa2287-a374-4a6d-9770-f74323381a84",
      "name": "Leftovers Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -848,
        -128
      ],
      "parameters": {
        "text": "={{ $('Menu Agent').item.json.output }}",
        "options": {
          "systemMessage": "You are a specialist in utilizing unused ingredients effectively. List leftover ingredients. Suggest three recipes that can be cooked with the remaining ingredients. You do not need to describe the cooking method."
        },
        "promptType": "define"
      },
      "typeVersion": 3
    },
    {
      "id": "5bf1ec16-a1ee-4b0c-b06d-25662fe1fb56",
      "name": "Nutritionist Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -272,
        -128
      ],
      "parameters": {
        "text": "={{ $('Menu Agent').item.json.output }}",
        "options": {
          "systemMessage": "You are a nutritionist specialist. Create a diary-style entry with dietary advice and what nutrients should be consumed."
        },
        "promptType": "define"
      },
      "typeVersion": 3
    },
    {
      "id": "52e4b8a7-cb34-4db7-a9ed-267dbd5ecfe3",
      "name": "Post Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        304,
        -128
      ],
      "parameters": {
        "text": "={{ $json['Diary'] }}",
        "options": {
          "systemMessage": "You are an X (Twitter) poster. Create a compelling post to attract viewers."
        },
        "promptType": "define"
      },
      "typeVersion": 3
    },
    {
      "id": "1ce6d15e-6710-4138-a7eb-bb8f96db5240",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2320,
        -592
      ],
      "parameters": {
        "width": 496,
        "height": 624,
        "content": "### How it works / What it does\n\nThis advanced workflow acts as a comprehensive culinary assistant. Triggered by a new menu item, it performs several key functions:\n\n*   **Cost and Ingredient Tracking:** A \"Menu Agent\" uses AI to analyze your input (e.g., a recipe or dish) and extract a detailed list of ingredients, their associated costs, unit prices, and total cost, then logs this into a Google Sheet as a \"Recipe List.\"\n*   **Leftover Management:** A \"Leftovers Agent\" identifies any unused ingredients from your planned dish and suggests three new recipes to utilize them, helping to minimize food waste. This information is also recorded in a Google Sheet.\n*   **Nutritional Diary:** A \"Nutritionist Agent\" generates a diary-style entry with dietary advice based on the meal, highlighting key nutrients and offering personalized suggestions. This entry is appended to a \"Diary\" Google Sheet.\n*   **Social Media Promotion:** A \"Post Agent\" takes the nutritional diary entry and transforms it into an engaging social media post (specifically for X/Twitter in this template), which is then sent as a direct message, ready for you to share with your followers.\n\n### Requirements\n\n*   An n8n instance.\n*   A Google account with Google Sheets enabled.\n*   An OpenRouter API key.\n*   A Twitter (X) account with developer access to send Direct Messages"
      },
      "typeVersion": 1
    },
    {
      "id": "8df4e680-cb25-4d27-8623-347c12727dcd",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1152,
        -416
      ],
      "parameters": {
        "color": 7,
        "width": 1392,
        "height": 448,
        "content": " **Google Sheets Integration:**\n\n    *   You need to set up a Google Sheets credential for your n8n instance.\n    *   Create a Google Sheet document (e.g., \"Recipe List\"). Within this document, create three sheets:\n        *   **\"Recipe:** This sheet will store your menu items, ingredients, costs, etc. Ensure it has columns for `Date`, `Item`, `Ingredients`, `Ingredient Cost`, `Unit Price`, `Quantity`, `Total`, `Cost`, and `Leftover Ingredients`.\n        *   **\"leftovers\" (Leftovers):** This sheet will store suggested recipes for leftover ingredients. Ensure it has columns for `Date` and `Ingredients`.\n        *   **\"diary\" (Diary):** This sheet will store your nutritional diary entries. Ensure it has a column for `Diary`.\n    *   In the \"Append row in sheet\", \"Append row in sheet1\", and \"Append row in sheet2\" nodes, replace the `Document ID` with the ID of your Google Sheet. For \"Sheet Name,\" ensure you select the correct sheet (e.g., \"\u30ec\u30b7\u30d4\", \"diary\", \"leftovers\") from the dropdown."
      },
      "typeVersion": 1
    },
    {
      "id": "410700dd-3d65-4d9a-8211-2f58b697e03c",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1696,
        -416
      ],
      "parameters": {
        "color": 7,
        "width": 192,
        "height": 448,
        "content": "  **Webhook Trigger:**\n\n    *   The workflow starts with a Webhook. Copy the webhook URL from the \"Webhook\" node. You will send your menu item input to this URL."
      },
      "typeVersion": 1
    },
    {
      "id": "d559ed46-36d3-4021-a74f-4e179dca7115",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        576,
        -416
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 448,
        "content": "**Twitter Integration:**\n    *   Set up your Twitter credentials for the \"Create Direct Message\" node.\n    *   In the \"Create Direct Message\" node, specify the `User` (username) to whom the direct message should be sent. This is typically your own Twitter handle or a test account.\n"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "bc536540-7bb6-4efb-84b1-366a01c56907",
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Menu Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Menu Agent": {
      "main": [
        [
          {
            "node": "Append row in sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post Agent": {
      "main": [
        [
          {
            "node": "Create Direct Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Leftovers Agent": {
      "main": [
        [
          {
            "node": "Append row in sheet2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Nutritionist Agent": {
      "main": [
        [
          {
            "node": "Append row in sheet1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append row in sheet": {
      "main": [
        [
          {
            "node": "Leftovers Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append row in sheet1": {
      "main": [
        [
          {
            "node": "Post Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append row in sheet2": {
      "main": [
        [
          {
            "node": "Nutritionist Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Menu Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "Post Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter Chat Model2": {
      "ai_languageModel": [
        [
          {
            "node": "Nutritionist Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter Chat Model3": {
      "ai_languageModel": [
        [
          {
            "node": "Leftovers Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Menu Agent",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This template is for home cooks, small restaurant owners, or anyone who wants to streamline their meal planning, ingredient cost tracking, leftover management, nutritional analysis, and social media promotion. It's ideal for those looking to optimize their kitchen operations,…

Source: https://n8n.io/workflows/10967/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

leads. Uses supabase, gmail, formTrigger, httpRequest. Webhook trigger; 62 nodes.

Supabase, Gmail, Form Trigger +13
AI & RAG

Transform your WhatsApp group conversations into actionable business intelligence through automated AI analysis and daily reporting. This workflow eliminates manual conversation monitoring by capturin

OpenRouter Chat, Output Parser Autofixing, Agent +6
AI & RAG

This template is perfect for: Market Researchers tracking industry trends. Tech Teams wanting to stay updated on specific technologies (e.g., "AI", "Cybersecurity"). Content Creators looking for curat

HTTP Request, Agent, OpenRouter Chat +5
AI & RAG

⏺ 🚀 How it works

Agent, Anthropic Chat, Output Parser Structured +6
AI & RAG

This comprehensive workflow automates the complete financial document processing pipeline using AI. Upload invoices via chat, drop expense receipts into a folder, or add bank statements - the system a

Chat Trigger, HTTP Request, Google Sheets +8