Google Sheets Writer
Log every generation to a Google Sheet while you batch
- STRING
The other half of the spreadsheet workflow
If Google Sheets Reader turns a spreadsheet into your prompt file, Google Sheets Writer (GoogleSheetsWriter) is how your workflow talks back. Drop it at the end of a batch and it appends whatever text you feed it into a sheet - the prompt that made an image, the seed, the parameters, a rating you toggled manually, anything. Same pack (comfyui_google_sheets_integration by lazniak / PabloGFX), same OAuth setup, complementary job. People use this to build a generation log, track A/B tests across prompt variants, or quietly accumulate a dataset row by row instead of hand-copying from the ComfyUI console.
How it works
It's a write-side wrapper over the Google Sheets v4 API, and it's smarter than the name suggests. Give it a range like Sheet1!A and it finds the first empty cell in that column, writes your value there with USER_ENTERED (so Google interprets numbers and formulas like it would if you'd typed them), then returns a confirmation string naming the exact cell. If you'd rather write to a specific spot, the range syntax accepts a full cell ref - Sheet1!A7 - and it'll land there instead. It even auto-extends the sheet's grid if you aim past the last row. The author built in rate-limit handling too: it throttles to ~55 requests/minute with a minimum 1.1s gap, and retries once on a 429. That's the "why does it feel slow in a tight loop" answer, and it's deliberate.
The inputs
Four required, and the first three are the same strings as the Reader:
spreadsheet_id- the ID from the sheet's URL.range- sheet name plus column or cell, likeSheet1!A(append) orSheet1!B12(exact spot). No!in the string and the node raises.client_secrets_file- path toclient_secret.json; the default targets the pack's own folder, which is where it should be.STORE- the actual text to write, a multiline string box. One value per run; if you want a whole row of metadata, join it into a single string or run the node multiple times.
The output is a STRING list holding a confirmation like Data successfully written to Sheet1!A5. - an output node, so it just reports; there's nothing to wire downstream.
Install
Same pack as the Reader, so one install gets you both. ComfyUI Manager ("Google Sheets Integration"), or:
cd ComfyUI/custom_nodes
git clone https://github.com/lazniak/comfyui_google_sheets_integration
pip install google-auth-oauthlib google-auth-httplib2 google-api-python-client cryptography
Ignore the README's hyphenated clone URL - it 404s; the underscore one above is the real repo. Then set up the OAuth credential: enable the Sheets API in Google Cloud Console, create a Desktop-app OAuth client, download client_secret.json into the pack's folder. First run opens a browser to authorize, and the token is stored encrypted in token.pickle (the pack generates a Fernet key for it). The Google account that authorizes needs edit access to the target sheet, not just view - the single most common "it reads but won't write" cause.
Gotchas worth knowing
USER_ENTERED cuts both ways: write =SUM(A1:A5) and it lands as a live formula; write 007 and it may become the number 7. If you want literal text, quote or prefix it. The "first empty cell" tracking is cached per sheet+column, so a manual edit in the sheet mid-batch can make it overwrite a row it thinks is empty. And because each run writes one value, "one row of metadata per image" means looping the Writer with control_after_generate-incrementing row counters or joining your metadata into one string - same pattern as the Reader's iteration. Errors come back as the output string, and the pack logs details to google_sheets_plugin.log in its own directory. It's plain, a little quirky, and exactly the node you reach for when "did I save that seed" becomes a spreadsheet question.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| spreadsheet_id | STRING | — | |
| range | STRING | — | |
| client_secrets_file | STRING | /tmp/ComfyUI/custom_nodes/comfyui_google_sheets_integration/client_secret.json | — |
| STORE | STRING | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| STRING | STRING | — |