AutomationFlowsWeb Scraping › Compare LLM Token Costs Across 350+ Models with Openrouter

Compare LLM Token Costs Across 350+ Models with Openrouter

ByPhilflow @philflow on n8n.io

Use cases are many: Compare costs across different models, plan your AI budget, optimize prompts for cost efficiency, or track expenses for client billing! OpenRouter charges a platform fee on top of model costs. See OpenRouter Pricing for details. You need an OpenRouter account…

Chat trigger trigger★★★★☆ complexityAI-powered21 nodesChat TriggerExecute Workflow TriggerFormChatForm TriggerOpenRouter ChatHTTP Request
Web Scraping Trigger: Chat trigger Nodes: 21 Complexity: ★★★★☆ AI nodes: yes Added:

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

This workflow follows the Chat → Chat Trigger 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
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "1492691c-98f1-46a3-8d27-3d7f067620dd",
      "name": "When chat message received",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        784,
        64
      ],
      "parameters": {
        "options": {
          "responseMode": "responseNodes"
        }
      },
      "typeVersion": 1.4
    },
    {
      "id": "16164596-fe99-4e3c-929a-414be89200da",
      "name": "When Executed by Another Workflow",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "position": [
        784,
        576
      ],
      "parameters": {
        "workflowInputs": {
          "values": [
            {
              "name": "chatInput"
            },
            {
              "name": "model"
            }
          ]
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "28dac69d-44a9-4c52-8a06-efafc48c3e8d",
      "name": "Code in JavaScript",
      "type": "n8n-nodes-base.code",
      "position": [
        2000,
        576
      ],
      "parameters": {
        "jsCode": "// Hole die Pricing-Daten vom Filter Node\nconst modelData = $('Filter').first().json;\nconst pricing = modelData.pricing;\n\n// Hole die Token-Usage vom LangChain Code Node\nconst tokenUsage = $json.tokenUsage;\n\n// Preise pro Token (von OpenRouter - sind bereits in Dollar pro Token)\nconst promptPrice = parseFloat(pricing.prompt);      // z.B. 0.0000004\nconst completionPrice = parseFloat(pricing.completion); // z.B. 0.0000016\n\n// Berechne Kosten\nconst inputCost = tokenUsage.input_tokens * promptPrice;\nconst outputCost = tokenUsage.output_tokens * completionPrice;\nconst totalCost = inputCost + outputCost;\n\nreturn {\n  // Original Output\n  output: $json.output,\n  \n  // Token Usage\n  tokenUsage: {\n    input_tokens: tokenUsage.input_tokens,\n    output_tokens: tokenUsage.output_tokens,\n    total_tokens: tokenUsage.total_tokens\n  },\n  \n  // Kosten in USD\n  costs: {\n    input_cost_usd: inputCost,\n    output_cost_usd: outputCost,\n    total_cost_usd: totalCost,\n    // Formatiert f\u00fcr bessere Lesbarkeit\n    total_cost_formatted: `$${totalCost.toFixed(8)}`\n  },\n  \n  // Model Info\n  model: {\n    id: modelData.id,\n    name: modelData.name,\n    prompt_price_per_token: promptPrice,\n    completion_price_per_token: completionPrice\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "8dc228d4-7dd0-4003-a444-4a36be89edb1",
      "name": "LangChain Code",
      "type": "@n8n/n8n-nodes-langchain.code",
      "position": [
        1680,
        576
      ],
      "parameters": {
        "code": {
          "execute": {
            "code": "const { PromptTemplate } = require('@langchain/core/prompts');\n\n// Get the LLM from ai_languageModel input\nconst llm = await this.getInputConnectionData('ai_languageModel', 0);\n\n// Get the chat input\nconst chatInput = $('When Executed by Another Workflow').first().json.chatInput;\n\n// Variable for token data\nlet tokenUsage = null;\n\n// Callback handler for token tracking\nconst tokenCallback = {\n  handleLLMEnd: async function(output, runId, parentId) {\n    try {\n      const generation = output.generations[0][0];\n      const message = generation.message;\n      if (message && message.usage_metadata) {\n        tokenUsage = {\n          input_tokens: message.usage_metadata.input_tokens,\n          output_tokens: message.usage_metadata.output_tokens,\n          total_tokens: message.usage_metadata.total_tokens\n        };\n      }\n    } catch (e) {\n      console.log('Token tracking error:', e);\n    }\n  }\n};\n\n// Create prompt and chain\nconst prompt = PromptTemplate.fromTemplate('{input}');\nconst chain = prompt.pipe(llm);\n\n// Invoke WITH callbacks (important: on invoke, not on the LLM!)\nconst response = await chain.invoke(\n  { input: chatInput },\n  { callbacks: [tokenCallback] }\n);\n\n// Return response with token data\nreturn [{\n  json: {\n    output: response.content,\n    tokenUsage: tokenUsage\n  }\n}];"
          }
        },
        "inputs": {
          "input": [
            {
              "type": "main",
              "required": true,
              "maxConnections": 1
            },
            {
              "type": "ai_languageModel",
              "required": true,
              "maxConnections": 1
            }
          ]
        },
        "outputs": {
          "output": [
            {
              "type": "main"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "0365fe8b-f2ec-4144-b7e5-d09cb88cd193",
      "name": "Filter",
      "type": "n8n-nodes-base.filter",
      "position": [
        1456,
        576
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "5e3a6f70-614e-4dda-bd44-f03d041dffba",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.id }}",
              "rightValue": "={{ $('When Executed by Another Workflow').item.json.model }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "1e2846e8-2cd4-4b41-b208-5971b7c0dd56",
      "name": "Code in JavaScript1",
      "type": "n8n-nodes-base.code",
      "position": [
        1456,
        288
      ],
      "parameters": {
        "jsCode": "// Dropdown values must be { option: \"...\" } format (not name/value)\nconst dropdownValues = items\n  .map(item => ({\n    option: item.json.id,\n  }))\n  .sort((a, b) => a.option.localeCompare(b.option));\n\nconst formJson = [\n  {\n    fieldLabel: \"Select Model\",\n    fieldType: \"dropdown\",\n    fieldOptions: {\n      values: dropdownValues,\n    },\n    requiredField: true,\n  },\n  {\n    fieldLabel: \"Prompt\",\n    fieldType: \"textarea\",\n    placeholder: \"Enter your prompt/question\",\n    requiredField: true,\n  },\n];\n\n// Form Node expects a single item carrying the JSON\nreturn [{\n  json: {\n    formJson,\n    // Pass templates through for resolution after form submit\n    templates: items.map(i => i.json),\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "ba0e8b3a-22ee-4054-873a-2884aacb3fc9",
      "name": "Form",
      "type": "n8n-nodes-base.form",
      "position": [
        1680,
        288
      ],
      "parameters": {
        "options": {
          "customCss": ":root {\n  --font-family: 'Inter', system-ui, -apple-system, sans-serif;\n  --font-weight-normal: 400;\n  --font-weight-bold: 600;\n  --font-size-body: 12px;\n  --font-size-label: 14px;\n  --font-size-input: 14px;\n  --font-size-header: 20px;\n  \n  /* Dark Theme Colors */\n  --color-background: #0f0f0f;\n  --color-card-bg: #1a1a1a;\n  --color-card-border: #2a2a2a;\n  --color-card-shadow: rgba(0, 0, 0, 0.4);\n  \n  --color-header: #e5e5e5;\n  --color-label: #888888;\n  --color-input-border: #2a2a2a;\n  --color-input-text: #e5e5e5;\n  --color-input-bg: #141414;\n  --color-focus-border: #2563eb;\n  \n  --color-submit-btn-bg: #2563eb;\n  --color-submit-btn-text: #ffffff;\n  --color-error: #ef4444;\n  --color-required: #ef4444;\n  \n  --color-html-text: #888888;\n  --color-html-link: #60a5fa;\n  --color-link: #888888;\n  \n  --border-radius-card: 12px;\n  --border-radius-input: 6px;\n  --box-shadow-card: 0px 4px 16px 0px var(--color-card-shadow);\n  --opacity-placeholder: 0.4;\n}\n\n/* Textarea & Select hover/focus */\ntextarea, select, input {\n  background: var(--color-input-bg) !important;\n  transition: border-color 0.15s ease, box-shadow 0.15s ease;\n}\n\ntextarea:hover, select:hover, input:hover {\n  border-color: #3a3a3a !important;\n}\n\ntextarea:focus, select:focus, input:focus {\n  border-color: var(--color-focus-border) !important;\n  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.3) !important;\n  outline: none;\n}\n\n/* Select dropdown arrow */\nselect {\n  appearance: none;\n  background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23888888' d='M6 8L1 3h10z'/%3E%3C/svg%3E\") !important;\n  background-repeat: no-repeat !important;\n  background-position: right 12px center !important;\n  padding-right: 36px !important;\n  cursor: pointer;\n}\n\n/* Submit Button hover */\nbutton[type=\"submit\"], .submit-btn {\n  transition: background-color 0.15s ease, transform 0.1s ease;\n}\n\nbutton[type=\"submit\"]:hover, .submit-btn:hover {\n  background: #3b82f6 !important;\n}\n\nbutton[type=\"submit\"]:active, .submit-btn:active {\n  transform: scale(0.98);\n}"
        },
        "defineForm": "json",
        "jsonOutput": "={{ $json.formJson }}"
      },
      "typeVersion": 2.3
    },
    {
      "id": "0158a19d-a67a-4723-84f0-90cf345e47e5",
      "name": "Form1",
      "type": "n8n-nodes-base.form",
      "position": [
        2128,
        288
      ],
      "parameters": {
        "operation": "completion",
        "respondWith": "showText",
        "responseText": "=<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>AI Response Display</title>\n  <style>\n    * { margin: 0; padding: 0; box-sizing: border-box; }\n    body {\n      font-family: system-ui, -apple-system, sans-serif;\n      background: #0f0f0f;\n      color: #e5e5e5;\n      min-height: 100vh;\n      padding: 2rem;\n    }\n    .container { max-width: 600px; margin: 0 auto; }\n    .card {\n      background: #1a1a1a;\n      border: 1px solid #2a2a2a;\n      border-radius: 12px;\n      padding: 1.5rem;\n    }\n    .output {\n      font-size: 1rem;\n      line-height: 1.7;\n      padding-bottom: 1rem;\n      border-bottom: 1px solid #2a2a2a;\n      margin-bottom: 1rem;\n    }\n    \n    /* Markdown Styles */\n    .output h1 { font-size: 1.5rem; margin: 1.5rem 0 1rem; color: #fff; }\n    .output h2 { font-size: 1.25rem; margin: 1.25rem 0 0.75rem; color: #fff; }\n    .output h3 { font-size: 1.1rem; margin: 1rem 0 0.5rem; color: #fff; }\n    .output h4 { font-size: 1rem; margin: 1rem 0 0.5rem; color: #ddd; }\n    .output h1:first-child, .output h2:first-child, .output h3:first-child { margin-top: 0; }\n    \n    .output p { margin: 0.75rem 0; }\n    .output strong { color: #fff; font-weight: 600; }\n    \n    .output code {\n      background: #2a2a2a;\n      padding: 0.15rem 0.4rem;\n      border-radius: 4px;\n      font-family: 'SF Mono', Consolas, monospace;\n      font-size: 0.9em;\n      color: #f472b6;\n    }\n    \n    .output pre {\n      background: #141414;\n      border: 1px solid #2a2a2a;\n      border-radius: 8px;\n      padding: 1rem;\n      margin: 1rem 0;\n      overflow-x: auto;\n    }\n    .output pre code {\n      background: none;\n      padding: 0;\n      color: #e5e5e5;\n      font-size: 0.85rem;\n    }\n    \n    .output ul, .output ol {\n      margin: 0.75rem 0;\n      padding-left: 1.5rem;\n    }\n    .output li { margin: 0.35rem 0; }\n    \n    .output hr {\n      border: none;\n      border-top: 1px solid #2a2a2a;\n      margin: 1.5rem 0;\n    }\n    \n    .output a {\n      color: #60a5fa;\n      text-decoration: none;\n    }\n    .output a:hover { text-decoration: underline; }\n\n    /* Meta & Details */\n    .meta {\n      display: flex;\n      justify-content: space-between;\n      align-items: center;\n      font-size: 0.875rem;\n      margin-bottom: 1rem;\n    }\n    .model {\n      background: #2563eb;\n      color: white;\n      padding: 0.25rem 0.75rem;\n      border-radius: 6px;\n      font-weight: 500;\n    }\n    .cost {\n      color: #22c55e;\n      font-family: monospace;\n      font-size: 0.9rem;\n    }\n    \n    details {\n      border-top: 1px solid #2a2a2a;\n      padding-top: 1rem;\n    }\n    summary {\n      cursor: pointer;\n      color: #888;\n      font-size: 0.8rem;\n      user-select: none;\n      display: flex;\n      align-items: center;\n      gap: 0.5rem;\n    }\n    summary:hover { color: #aaa; }\n    summary::marker { content: ''; }\n    summary .icon {\n      transition: transform 0.2s;\n      font-size: 0.7rem;\n    }\n    details[open] summary .icon {\n      transform: rotate(90deg);\n    }\n    \n    .details-grid {\n      display: grid;\n      grid-template-columns: 1fr 1fr;\n      gap: 1rem;\n      margin-top: 1rem;\n      padding: 1rem;\n      background: #141414;\n      border-radius: 8px;\n    }\n    .detail-section h4 {\n      color: #666;\n      font-size: 0.7rem;\n      text-transform: uppercase;\n      letter-spacing: 0.05em;\n      margin-bottom: 0.5rem;\n    }\n    .detail-row {\n      display: flex;\n      justify-content: space-between;\n      font-size: 0.8rem;\n      padding: 0.25rem 0;\n    }\n    .detail-row .label { color: #888; }\n    .detail-row .value { \n      font-family: monospace;\n      color: #e5e5e5;\n    }\n    .detail-row .value.green { color: #22c55e; }\n    .detail-row .value.blue { color: #60a5fa; }\n  </style>\n</head>\n<body>\n  <div class=\"container\">\n    <div class=\"card\">\n      <div class=\"output\">{{ $json.output }}</div>\n      \n      <div class=\"meta\">\n        <span class=\"model\">{{ $json.model.id }}</span>\n        <span class=\"cost\">{{ $json.costs.total_cost_formatted }}</span>\n      </div>\n      \n      <details>\n        <summary><span class=\"icon\">\u25b6</span>Show details</summary>\n        <div class=\"details-grid\">\n          <div class=\"detail-section\">\n            <h4>Token Usage</h4>\n            <div class=\"detail-row\">\n              <span class=\"label\">Input</span>\n              <span class=\"value\">{{ $json.tokenUsage.input_tokens }}</span>\n            </div>\n            <div class=\"detail-row\">\n              <span class=\"label\">Output</span>\n              <span class=\"value\">{{ $json.tokenUsage.output_tokens }}</span>\n            </div>\n            <div class=\"detail-row\">\n              <span class=\"label\">Total</span>\n              <span class=\"value blue\">{{ $json.tokenUsage.total_tokens }}</span>\n            </div>\n          </div>\n          \n          <div class=\"detail-section\">\n            <h4>Costs</h4>\n            <div class=\"detail-row\">\n              <span class=\"label\">Input</span>\n              <span class=\"value\">${{ $json.costs.input_cost_usd }}</span>\n            </div>\n            <div class=\"detail-row\">\n              <span class=\"label\">Output</span>\n              <span class=\"value\">${{ $json.costs.output_cost_usd }}</span>\n            </div>\n            <div class=\"detail-row\">\n              <span class=\"label\">Total</span>\n              <span class=\"value green\">${{ $json.costs.total_cost_usd }}</span>\n            </div>\n          </div>\n          \n          <div class=\"detail-section\" style=\"grid-column: span 2;\">\n            <h4>Model Pricing</h4>\n            <div class=\"detail-row\">\n              <span class=\"label\">Prompt (per token)</span>\n              <span class=\"value\">${{ $json.model.prompt_price_per_token }}</span>\n            </div>\n            <div class=\"detail-row\">\n              <span class=\"label\">Completion (per token)</span>\n              <span class=\"value\">${{ $json.model.completion_price_per_token }}</span>\n            </div>\n            <div class=\"detail-row\">\n              <span class=\"label\">Model Name</span>\n              <span class=\"value\">{{ $json.model.name }}</span>\n            </div>\n          </div>\n        </div>\n      </details>\n    </div>\n  </div>\n</body>\n</html>"
      },
      "typeVersion": 2.3
    },
    {
      "id": "8e0635fb-e651-4848-8491-07b8c0c58ed8",
      "name": "Split Out",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        1232,
        288
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "data"
      },
      "typeVersion": 1
    },
    {
      "id": "3de0f267-dc22-4807-a9ef-32812e8f5ecd",
      "name": "Split Out1",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        1232,
        576
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "data"
      },
      "typeVersion": 1
    },
    {
      "id": "ea0a8895-e1e3-4897-8198-2348e4deb84a",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        0
      ],
      "parameters": {
        "width": 688,
        "height": 224,
        "content": "## Chat (simple testing via chat)\n"
      },
      "typeVersion": 1
    },
    {
      "id": "1615dd6e-0c15-46cc-872c-9d9cea8cbb9b",
      "name": "Respond to Chat",
      "type": "@n8n/n8n-nodes-langchain.chat",
      "position": [
        1232,
        64
      ],
      "parameters": {
        "message": "={{ $json.output }}\n\n---\n\n**{{ $json.model.id }}** \u00b7 `{{ $json.costs.total_cost_formatted }}`\n\n**Tokens** \u00b7 Input: {{ $json.tokenUsage.input_tokens }} \u00b7 Output: {{ $json.tokenUsage.output_tokens }} \u00b7 Total: **{{ $json.tokenUsage.total_tokens }}**\n\n**Costs** \u00b7 Input: ${{ $json.costs.input_cost_usd.toFixed(7) }} \u00b7 Output: ${{ $json.costs.output_cost_usd.toFixed(7) }} \u00b7 Total: **{{ $json.costs.total_cost_formatted }}**\n\n*{{ $json.model.name }} \u00b7 Prompt ${{ $json.model.prompt_price_per_token.toFixed(7) }}/tk \u00b7 Completion ${{ $json.model.completion_price_per_token.toFixed(7) }}/tk*",
        "options": {},
        "waitUserReply": false
      },
      "typeVersion": 1
    },
    {
      "id": "b4cd2c9f-18fd-4ae0-9569-cf68e351fd80",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        240
      ],
      "parameters": {
        "color": 7,
        "width": 1648,
        "height": 240,
        "content": "## UI\n"
      },
      "typeVersion": 1
    },
    {
      "id": "de85ae21-918d-48d4-8e29-62fc275bbc83",
      "name": "On form submission",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        784,
        288
      ],
      "parameters": {
        "options": {
          "customCss": ":root {\n  --font-family: 'Inter', system-ui, -apple-system, sans-serif;\n  --font-weight-normal: 400;\n  --font-weight-bold: 600;\n  --font-size-body: 12px;\n  --font-size-label: 14px;\n  --font-size-input: 14px;\n  --font-size-header: 20px;\n  \n  /* Dark Theme Colors */\n  --color-background: #0f0f0f;\n  --color-card-bg: #1a1a1a;\n  --color-card-border: #2a2a2a;\n  --color-card-shadow: rgba(0, 0, 0, 0.4);\n  \n  --color-header: #e5e5e5;\n  --color-label: #888888;\n  --color-input-border: #2a2a2a;\n  --color-input-text: #e5e5e5;\n  --color-input-bg: #141414;\n  --color-focus-border: #2563eb;\n  \n  --color-submit-btn-bg: #2563eb;\n  --color-submit-btn-text: #ffffff;\n  --color-error: #ef4444;\n  --color-required: #ef4444;\n  \n  --color-html-text: #888888;\n  --color-html-link: #60a5fa;\n  --color-link: #888888;\n  \n  --border-radius-card: 12px;\n  --border-radius-input: 6px;\n  --box-shadow-card: 0px 4px 16px 0px var(--color-card-shadow);\n  --opacity-placeholder: 0.4;\n}\n\n/* Textarea & Select hover/focus */\ntextarea, select, input {\n  background: var(--color-input-bg) !important;\n  transition: border-color 0.15s ease, box-shadow 0.15s ease;\n}\n\ntextarea:hover, select:hover, input:hover {\n  border-color: #3a3a3a !important;\n}\n\ntextarea:focus, select:focus, input:focus {\n  border-color: var(--color-focus-border) !important;\n  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.3) !important;\n  outline: none;\n}\n\n/* Select dropdown arrow */\nselect {\n  appearance: none;\n  background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23888888' d='M6 8L1 3h10z'/%3E%3C/svg%3E\") !important;\n  background-repeat: no-repeat !important;\n  background-position: right 12px center !important;\n  padding-right: 36px !important;\n  cursor: pointer;\n}\n\n/* Submit Button hover */\nbutton[type=\"submit\"], .submit-btn {\n  transition: background-color 0.15s ease, transform 0.1s ease;\n}\n\nbutton[type=\"submit\"]:hover, .submit-btn:hover {\n  background: #3b82f6 !important;\n}\n\nbutton[type=\"submit\"]:active, .submit-btn:active {\n  transform: scale(0.98);\n}",
          "buttonLabel": "Start"
        },
        "formTitle": "LLM Token Cost Tracker",
        "formDescription": "\ud83d\udd0d Find out exactly what your AI requests cost.\n\n  This tool lets you:\n  \u2022 Choose from 350+ LLM models (GPT-4, Claude, Llama, etc.)\n  \u2022 Enter any prompt and run it\n  \u2022 See the exact token usage and cost breakdown\n\n  Perfect for comparing model prices or tracking your AI spending"
      },
      "typeVersion": 2.3
    },
    {
      "id": "c70b764d-65eb-41bd-81a7-61c20a983239",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        496
      ],
      "parameters": {
        "color": 6,
        "width": 1536,
        "height": 336,
        "content": "## Backend\n"
      },
      "typeVersion": 1
    },
    {
      "id": "a305499a-09d9-4636-bd66-9f0fdd9e230a",
      "name": "OpenRouter",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        1680,
        720
      ],
      "parameters": {
        "model": "={{ $('When Executed by Another Workflow').item.json.model }}",
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "5119d08c-5d14-43e1-b89c-010cb11abc30",
      "name": "Backend",
      "type": "n8n-nodes-base.executeWorkflow",
      "position": [
        1904,
        288
      ],
      "parameters": {
        "options": {},
        "workflowId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $workflow.id }}",
          "cachedResultUrl": "/workflow/=%7B%7B%20$workflow.id%20%7D%7D"
        },
        "workflowInputs": {
          "value": {
            "model": "={{ $json[\"Select Model\"] }}",
            "chatInput": "={{ $json.Prompt }}"
          },
          "schema": [
            {
              "id": "chatInput",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "chatInput",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "model",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "model",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": true
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "17649aeb-5fe6-4ef6-89b6-797b6a98d5a7",
      "name": "Backend1",
      "type": "n8n-nodes-base.executeWorkflow",
      "position": [
        1008,
        64
      ],
      "parameters": {
        "options": {},
        "workflowId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $workflow.id }}",
          "cachedResultUrl": "/workflow/=%7B%7B%20$workflow.id%20%7D%7D"
        },
        "workflowInputs": {
          "value": {
            "model": "openai/gpt-4.1-mini",
            "chatInput": "={{ $json.chatInput }}"
          },
          "schema": [
            {
              "id": "chatInput",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "chatInput",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "model",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "model",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": true
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "1a982773-b900-45cf-9bb9-6a6cccef8c2c",
      "name": "Get Openrouter models",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1008,
        288
      ],
      "parameters": {
        "url": "https://openrouter.ai/api/v1/models",
        "options": {},
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "3816f346-0b0b-40cf-9c15-63a1851b34b7",
      "name": "Get Openrouter models1",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1008,
        576
      ],
      "parameters": {
        "url": "https://openrouter.ai/api/v1/models",
        "options": {},
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "ddde7547-c651-43a5-b58f-d67bde3e8839",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "color": 4,
        "width": 704,
        "height": 1600,
        "content": "# LLM Token Cost Tracker\n  \ud83d\udd0d **Find out exactly what your AI requests cost.**\n  ---\n  ## \u2728 Features\n  - **350+ Models** - Access GPT-4, Claude, Llama, Mistral, and many more\n  - **Real-time Pricing** - Costs calculated using live OpenRouter pricing data\n  - **Detailed Breakdown** - See input tokens, output tokens, and cost per category\n  - **Two Interfaces** - Use via Chat or interactive Form\n  ---\n  ## \ud83d\udee0\ufe0f Setup\n  ### 1. Get your OpenRouter API Key\n  1. Visit [OpenRouter API Keys](https://openrouter.ai/settings/keys)\n  2. Click **\"Create Key\"**\n  3. Copy your new API key\n\n  ### 2. Configure the HTTP Node\n  1. Open the **HTTP Request** node (fetches model list)\n  2. In the **Authentication** dropdown, select **\"Bearer YOUR_TOKEN_HERE\"**\n  3. Click **\"Create New Credential\"**\n  4. Paste your API key and save\n\n  ### 3. Configure the OpenRouter Chat Model\n  1. Open the **OpenRouter Chat Model** node (attached to the LangChain Code node)\n  2. Click **\"Create New Credential\"**\n  3. Paste the same API key and save\n\n  \u2705 **Done!** Your workflow is ready to use.\n  ---\n\n  ## \ud83d\ude80 Usage\n  ### Option 1: Chat Interface\n  The quickest way to test:\n\n  1. Open the **Chat** panel in n8n\n  2. Type any prompt\n  3. Get your response + cost breakdown directly in the chat\n\n  ### Option 2: Form Interface\n  For model selection and detailed results:\n\n  1. Click **\"Form Submission\"** \u2192 **\"Start\"**\n  2. Wait a moment while all available models are fetched from OpenRouter\n  3. **Select a model** from the dropdown (e.g., `openai/gpt-4.1-mini`)\n  4. **Enter your prompt** in the textarea\n  5. Click **\"Submit\"**\n  6. View the **result form** with:\n     - The AI response\n     - Total cost\n     - Click **\"Show Details\"** for full breakdown:\n       - Input tokens\n       - Output tokens\n       - Cost per token type\n       - Model pricing info\n\n  ---\n  ## \ud83d\udca1 Use Cases\n  - **Compare model costs** - Same prompt, different models, see price differences\n  - **Budget planning** - Estimate costs before scaling up\n  - **Optimize prompts** - See how prompt length affects cost\n  - **Client billing** - Track exact costs per request\n  ---\n  ## \ud83d\udd17 Links\n  - [OpenRouter](https://openrouter.ai/) - Multi-model API gateway\n  - [OpenRouter Pricing](https://openrouter.ai/models) - Current model prices\n  - [Get API Key](https://openrouter.ai/settings/keys) - Create your key here\n\n  ---\n  Made with \u2764\ufe0f by philflow for the n8n community\n  ---"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Form": {
      "main": [
        [
          {
            "node": "Backend",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter": {
      "main": [
        [
          {
            "node": "LangChain Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Backend": {
      "main": [
        [
          {
            "node": "Form1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Backend1": {
      "main": [
        [
          {
            "node": "Respond to Chat",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out": {
      "main": [
        [
          {
            "node": "Code in JavaScript1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter": {
      "ai_languageModel": [
        [
          {
            "node": "LangChain Code",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Split Out1": {
      "main": [
        [
          {
            "node": "Filter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "LangChain Code": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "On form submission": {
      "main": [
        [
          {
            "node": "Get Openrouter models",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript1": {
      "main": [
        [
          {
            "node": "Form",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Openrouter models": {
      "main": [
        [
          {
            "node": "Split Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Openrouter models1": {
      "main": [
        [
          {
            "node": "Split Out1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When chat message received": {
      "main": [
        [
          {
            "node": "Backend1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When Executed by Another Workflow": {
      "main": [
        [
          {
            "node": "Get Openrouter models1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

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

About this workflow

Use cases are many: Compare costs across different models, plan your AI budget, optimize prompts for cost efficiency, or track expenses for client billing! OpenRouter charges a platform fee on top of model costs. See OpenRouter Pricing for details. You need an OpenRouter account…

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

More Web Scraping workflows → · Browse all categories →

Related workflows

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

Web Scraping

Accounting teams spend hours manually entering purchase bills into accounting systems—copying vendor details, creating items, checking duplicates, and reconciling totals. This workflow removes that ma

HTTP Request, QuickBooks, Information Extractor +2
Web Scraping

pfe-hunter-sophistique. Uses lmChatGroq, chatTrigger, chainLlm, httpRequest. Chat trigger; 24 nodes.

Groq Chat, Chat Trigger, Chain Llm +1
Web Scraping

This workflow contains community nodes that are only compatible with the self-hosted version of n8n.

Chat Trigger, HTTP Request, N8N Nodes Aimlapi +1
Web Scraping

Generate Videos from Chat with Google Vertex AI (Veo3) - Beginner Friendly

HTTP Request, Chat Trigger
Web Scraping

This workflow allows you to import any workflow from a file or another n8n instance and map the credentials easily. A multi-form setup guides you through the entire process At the beginning you have t

Execute Command, Read Write File, HTTP Request +3