AutomationFlowsAI & RAG › Track Monthly Openai Token Usage with Google Sheets and Gmail Reports

Track Monthly Openai Token Usage with Google Sheets and Gmail Reports

ByPatrick Campbell @therealpjc014 on n8n.io

Who's this for Finance teams, AI developers, product managers, and business owners who need to monitor and control OpenAI API costs across different models and projects. If you're using GPT-4, GPT-3.5, or other OpenAI models and want to track spending patterns, identify cost…

Cron / scheduled trigger★★★★☆ complexity13 nodesHTTP RequestGoogle SheetsGoogle DriveGmail
AI & RAG Trigger: Cron / scheduled Nodes: 13 Complexity: ★★★★☆ Added:

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

This workflow follows the Gmail → Google Drive 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": "HnVFowdm6-T8Itn60-5Zl",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Track OpenAI token usage to Google Sheets with monthly email reports",
  "tags": [],
  "nodes": [
    {
      "id": "78fca6be-db2a-4b21-88ca-3d64e6881b32",
      "name": "Fetch OpenAI Usage Data",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        32,
        144
      ],
      "parameters": {
        "url": "https://api.openai.com/v1/organization/usage/completions",
        "options": {},
        "sendQuery": true,
        "authentication": "predefinedCredentialType",
        "queryParameters": {
          "parameters": [
            {
              "name": "start_time",
              "value": "={{ Math.floor(Date.UTC(new Date().getFullYear(), new Date().getMonth() - 1, 1) / 1000) }}"
            },
            {
              "name": "end_time",
              "value": "={{ Math.floor(Date.UTC(new Date().getFullYear(), new Date().getMonth(), 0, 23, 59, 59) / 1000) }}"
            },
            {
              "name": "api_key_ids[]",
              "value": "your-api-key-id"
            },
            {
              "name": "limit",
              "value": "31"
            },
            {
              "name": "bucket_width",
              "value": "1d"
            },
            {
              "name": "group_by[]",
              "value": "model"
            }
          ]
        },
        "nodeCredentialType": "openAiApi"
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "2d0bd1b3-bba6-4bf0-8b3a-a52b2382e664",
      "name": "Transform Usage to Daily Breakdown",
      "type": "n8n-nodes-base.code",
      "position": [
        240,
        144
      ],
      "parameters": {
        "jsCode": "// Get the data from the HTTP Request node\nconst inputData = $input.all();\n\n// The data is directly an array with one object that has a 'data' property\nconst rawData = inputData[0].json.data;\n\n// Transform each bucket (day) into a flat structure\nconst outputData = [];\n\nfor (const bucket of rawData) {\n  const date = bucket.start_time_iso.split('T')[0]; // Get just YYYY-MM-DD\n  \n  // If there are results for this day\n  if (bucket.results && bucket.results.length > 0) {\n    for (const result of bucket.results) {\n      outputData.push({\n        date: date,\n        model: result.model || 'N/A',\n        input_tokens: result.input_tokens || 0,\n        output_tokens: result.output_tokens || 0\n      });\n    }\n  } else {\n    // If no usage for this day, add a row showing zero usage\n    outputData.push({\n      date: date,\n      model: 'No usage',\n      input_tokens: 0,\n      output_tokens: 0\n    });\n  }\n}\n\nreturn outputData.map(item => ({ json: item }));"
      },
      "typeVersion": 2
    },
    {
      "id": "96775d45-7c96-4888-960c-14058f627f17",
      "name": "Append Data to Google Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        448,
        144
      ],
      "parameters": {
        "columns": {
          "value": {
            "Date": "={{ $json.date }}",
            "Model": "={{ $json.model }}",
            "Token Usage In": "={{ $json.input_tokens }}",
            "Token Usage Out": "={{ $json.output_tokens }}"
          },
          "schema": [
            {
              "id": "Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Model",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Model",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Token Usage In",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Token Usage In",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Token Usage Out",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Token Usage Out",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": []
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Create Monthly Report from Template').item.json.id }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "77773788-5d6a-4a91-bd46-601d4fdbc6ff",
      "name": "Create Monthly Report from Template",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -240,
        144
      ],
      "parameters": {
        "name": "=Token_Tracking_{{ $now.minus({months: 1}).toFormat('LLLL') }}_{{ $now.minus({months: 1}).toFormat('yyyy') }}",
        "fileId": {
          "__rl": true,
          "mode": "list",
          "value": "your-template-file-id"
        },
        "options": {},
        "operation": "copy"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "4b6b6fea-51b8-47c1-95b5-51cc7716b5d9",
      "name": "Export Sheet as Excel",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        704,
        64
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Create Monthly Report from Template').item.json.id }}"
        },
        "options": {
          "fileName": "={{ $('Create Monthly Report from Template').item.json.name }}.xlsx",
          "binaryPropertyName": "data",
          "googleFileConversion": {
            "conversion": {
              "sheetsToFormat": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
            }
          }
        },
        "operation": "download"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 3
    },
    {
      "id": "5d0e6993-e7ed-4a5a-a344-0fded932b4ec",
      "name": "Archive Report to Drive",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        944,
        64
      ],
      "parameters": {
        "name": "={{ $('Create Monthly Report from Template').item.json.name }}.xlsx",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "your-archive-folder-id"
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 3
    },
    {
      "id": "c739b7b5-c19f-405c-8862-44012dbaa49a",
      "name": "Email Report to Stakeholder",
      "type": "n8n-nodes-base.gmail",
      "position": [
        944,
        208
      ],
      "parameters": {
        "sendTo": "user@example.com",
        "message": "Please see attached token usage data for the previous month.",
        "options": {
          "attachmentsUi": {
            "attachmentsBinary": [
              {}
            ]
          },
          "appendAttribution": false
        },
        "subject": "Monthly OpenAI Token Usage Report"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "d886ba78-d654-4ecc-9bb9-5b4f22e36ac0",
      "name": "Export Sheet as PDF for Email",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        704,
        208
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Create Monthly Report from Template').item.json.id }}"
        },
        "options": {
          "fileName": "={{ $('Create Monthly Report from Template').item.json.name }}.pdf",
          "binaryPropertyName": "data",
          "googleFileConversion": {
            "conversion": {
              "sheetsToFormat": "application/pdf"
            }
          }
        },
        "operation": "download"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 3
    },
    {
      "id": "ac6f42bc-d87b-4a45-a23a-4703d170154e",
      "name": "Workflow Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1040,
        -400
      ],
      "parameters": {
        "color": 5,
        "width": 460,
        "height": 1316,
        "content": "## Track OpenAI Token Usage with Automated Monthly Reports\n\nThis workflow automatically monitors your OpenAI API usage and costs on a monthly basis. Perfect for finance teams and developers who need to track AI spending across different models and projects.\n\n### How it works\n* Runs automatically on the 5th of each month via Schedule Trigger\n* Creates a new Google Sheet from your template for the reporting period (template can be found [HERE](https://github.com/WorkFlowAutomationNetwork/Youtube-Resources/tree/main/N8NTemplate) )\n* Fetches previous month's usage data from OpenAI API\n* Transforms raw API data into daily breakdown by model\n* Appends usage data to Google Sheets (input/output tokens per model)\n* Your sheet calculates costs automatically using formulas\n* Generates PDF report and Excel file\n* Emails the PDF report to stakeholders\n* Archives Excel file in Google Drive for recordkeeping\n\n### Requirements\n* OpenAI Admin API access (to access organization usage endpoints)\n* Google Sheets template with cost calculation formulas\n* Google Drive for storage\n* Gmail account for email notifications\n\n### Setup Instructions\n1. **Create Google Sheets template** with columns: Date, Model, Token Usage In, Token Usage Out, Token Cost Input, Token Cost Output, Total Cost USD (add formulas for automatic calculations) (note a template is provided if you don't want to create your own)\n2. **Configure credentials** in n8n for OpenAI API, Google Sheets, Google Drive, and Gmail\n3. **Update the HTTP Request node** with your OpenAI API key ID\n4. **Replace placeholder email** (your-email@example.com) with recipient address\n5. **Set your Google Drive folders** for template source and archive destination\n6. **Test the workflow** using the manual trigger before enabling schedule\n\n### Customization Ideas\n* Track multiple API keys by adding more `api_key_ids[]` parameters\n* Change reporting frequency by modifying the Schedule Trigger\n* Add Slack notifications instead of or in addition to email\n* Include budget threshold alerts using IF nodes\n* Add cost forecasting based on trends\n* Track additional metrics like average tokens per request\n* Support multiple currencies with conversion rates\n"
      },
      "typeVersion": 1
    },
    {
      "id": "838ae489-19f4-480c-a6a8-a9962cdf752d",
      "name": "Monthly Report Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -528,
        144
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "months",
              "triggerAtDayOfMonth": 5
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "c75ec0dc-4d1b-481a-b8e9-28e2d07d225e",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -32,
        -144
      ],
      "parameters": {
        "color": 7,
        "width": 608,
        "height": 544,
        "content": "## Step 2: Fetch and Process Usage Data\n\nRetrieves OpenAI usage data for the previous month via API, transforms it into a daily breakdown by model (input/output tokens), and populates the Google Sheet.\n\n**Note:** Make sure to replace 'your-api-key-id' with your actual OpenAI API key ID in the HTTP Request node."
      },
      "typeVersion": 1
    },
    {
      "id": "9bb45d33-875c-4286-9df8-6830cf04288e",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        576,
        -144
      ],
      "parameters": {
        "color": 7,
        "width": 896,
        "height": 544,
        "content": "## Step 3: Generate and Distribute Report\n\nDownloads the completed sheet as both PDF and Excel formats, emails the PDF to stakeholders with usage summary, and archives the Excel file in Google Drive for long-term storage.\n\n**Remember to update:** Email recipient address and Google Drive archive folder ID."
      },
      "typeVersion": 1
    },
    {
      "id": "b3e56d33-58f6-479d-b00a-9722601489c0",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -576,
        -144
      ],
      "parameters": {
        "color": 7,
        "width": 544,
        "height": 544,
        "content": "## Step 1: Initialize Monthly Report\n\nTriggers on the 5th of each month and copies the Google Sheets template with proper naming convention (e.g., 'Token_Tracking_December_2025').\n\n**Update:** Set your template file ID in the Google Drive node."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "54d77165-1ab3-4a88-a799-60ff1032a998",
  "connections": {
    "Export Sheet as Excel": {
      "main": [
        [
          {
            "node": "Archive Report to Drive",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Monthly Report Trigger": {
      "main": [
        [
          {
            "node": "Create Monthly Report from Template",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch OpenAI Usage Data": {
      "main": [
        [
          {
            "node": "Transform Usage to Daily Breakdown",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append Data to Google Sheet": {
      "main": [
        [
          {
            "node": "Export Sheet as Excel",
            "type": "main",
            "index": 0
          },
          {
            "node": "Export Sheet as PDF for Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Export Sheet as PDF for Email": {
      "main": [
        [
          {
            "node": "Email Report to Stakeholder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Transform Usage to Daily Breakdown": {
      "main": [
        [
          {
            "node": "Append Data to Google Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Monthly Report from Template": {
      "main": [
        [
          {
            "node": "Fetch OpenAI Usage Data",
            "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

Who's this for Finance teams, AI developers, product managers, and business owners who need to monitor and control OpenAI API costs across different models and projects. If you're using GPT-4, GPT-3.5, or other OpenAI models and want to track spending patterns, identify cost…

Source: https://n8n.io/workflows/12646/ — 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

Founder's Discovery Engine. Uses googleSheets, googleDrive, httpRequest, gmail. Scheduled trigger; 18 nodes.

Google Sheets, Google Drive, HTTP Request +1
AI & RAG

Sales managers and team leads who use Zoom Phone for outbound calls and want automated performance tracking without manually reviewing every recording. A schedule trigger runs periodically and fetches

HTTP Request, Google Drive, Google Sheets
AI & RAG

Know what your competitors are doing every morning before your first meeting. This workflow visits each competitor website daily, uses OpenAI to analyse it for strategic signals, and emails your team

HTTP Request, Gmail, Google Sheets
AI & RAG

Take full control of your expected loyalty points. This workflow helps you log every coupon and the points you should receive, store proof of purchase, and get a weekly summary so you can quickly spot

Google Drive, Google Sheets, Gmail +1
AI & RAG

This workflow is a complete outbound automation system that discovers local businesses, extracts contact emails, generates personalized cold emails using AI, and runs a multi-step follow-up sequence —

Stop And Error, Google Sheets, HTTP Request +2