How to connect ClickUp to Google Sheets with columns that stay stable
Custom fields are defined per list, so an export spanning lists produces a ragged sheet. Fixing the column set, reporting what is missing, and the time-in-status data nobody exports.
On this page
- What we'll cover
- Why the sheet comes out ragged
- Fix the columns, then map to them
- Building it with CodeWords
- What belongs in the sheet
- Time in status, which nobody exports
- Subtasks, and the double-counting problem
- Field types that arrive awkwardly
- Reporting people will act on
- Making it survive
- Limits worth knowing about
- What to set up first
- Frequently asked questions
- Related reading
An export from one ClickUp list is straightforward. An export spanning several is not, because custom fields and statuses are defined per list, so the same-named field is a different field and a column that exists for one team does not exist for another.
The result is a sheet where a third of the cells are empty for reasons nobody can explain. Fixing that means deciding the column set deliberately and reporting which lists could not supply it — which turns a confusing sheet into a configuration problem somebody can solve.
What we'll cover
- Why the sheet comes out ragged
- Fix the columns, then map to them
- Building it with CodeWords
- What belongs in the sheet
- Time in status, which nobody exports
- Subtasks, and the double-counting problem
- Field types that arrive awkwardly
- Reporting people will act on
- Making it survive
- Limits worth knowing about
- What to set up first
- Frequently asked questions
Why the sheet comes out ragged
Custom fields are per list. A field called "Priority" in two lists is two different fields, with two identifiers and possibly two different option sets.
Statuses are per list or per space, so a single status column can hold values that are not comparable across lists.
Option sets differ. Two lists with a "Priority" dropdown may offer different options, so grouping by the column mixes scales.
Some lists have no equivalent field at all, producing empty cells that look like missing data rather than a missing field.
The hierarchy is uneven, since folders are optional, so a "Folder" column is blank for lists that sit directly in a space.
An export that discovers columns from the data reflects all of this faithfully and unusably. The fix is to decide the columns first.
Fix the columns, then map to them
The approach that produces a usable sheet.
Write down the columns the report needs — usually name, status, assignee, due date, one or two custom fields, and the list it came from.
Map each list's fields onto that fixed set, explicitly, by field identifier.
Keep the mapping in a sheet of its own, so whoever owns the lists can see and maintain it rather than asking somebody to change an automation.
Report lists you could not map, with which column was missing. That report is the useful half — it tells somebody exactly what to configure.
Normalise the values too. If one list says "Urgent" and another says "P1", map both to a common vocabulary or the grouping is meaningless.
Never invent a value to fill a gap. An empty cell with a clear explanation beats a plausible guess.
Building it with CodeWords
CodeWords connects to more than 3,000 integrations, and the connection is made once and reused.
- Open CodeWords and start a new automation.
- Describe what should happen in plain language to Cody, the automation builder: which lists, which fixed columns, and which sheet.
- Authorize the connection to ClickUp with a token belonging to a dedicated integration user, plus access to the target spreadsheet.
- Describe the exceptions: a list missing a mapped field, a status not in your vocabulary, a task moved between lists.
- Run it against two lists with different configurations and check the mapping before extending it.
You describe the outcome; Cody builds it, connects it, and deploys it. The free plan covers light use, with Pro at $39 per month and Business at $100 per month as usage grows; details are on the pricing page.
What belongs in the sheet
The fixed column set, in a fixed order, so formulas pointing at it do not break.
The list and space each task came from, which is what lets a combined sheet be split apart again.
The task identifier as text, so rows can be matched against a later export.
Derived values computed before export — days in current status, days until due, whether the task is overdue — rather than as spreadsheet formulas somebody will break.
A run timestamp, visibly, since a stale project sheet looks identical to a current one.
Not comments, not descriptions, not attachments. They make the sheet enormous and nobody reads them there.
Time in status, which nobody exports
The most useful thing available and the one almost no export includes.
How long a task has spent in its current status is a better health signal than the status itself, and it needs nothing but the status change history.
Report the distribution per status, which shows where work actually queues rather than where anybody assumes.
Watch the tail. Most tasks move through review quickly; the handful sitting for three weeks are the problem, and an average hides them entirely.
Compare across lists, which is where a cross-team export earns its place — a status taking twice as long on one team's list is a question worth asking.
Do not make it a target. A team measured on time in status will move tasks sooner, which improves the number and not the work.
Use it for a monthly conversation about where work waits, which is the whole value.
Subtasks, and the double-counting problem
Subtasks are separate tasks with their own statuses, assignees, and sometimes their own custom fields.
An export that includes them alongside parents double-counts anything summed, because the parent frequently carries the same estimate or value.
An export that excludes them omits most of the work on lists that use subtasks heavily.
Decide, say which you chose, and add a column marking which rows are subtasks, so the reader can filter either way.
Checklists are not subtasks and do not appear as tasks at all, which is a third behaviour teams conflate with the other two.
Multiple list membership compounds this, since a task in two lists appears twice in a cross-list export unless you deduplicate on identifier.
Field types that arrive awkwardly
Dropdown fields return option identifiers, so a readable sheet needs the option list resolved.
Relationship fields return task identifiers, which need a second lookup to render a name.
Formula fields are computed and may be absent or stale for tasks that have not been recalculated.
Dates arrive as timestamps and land in the spreadsheet's own timezone, which is a workbook setting nobody has checked.
Users are identifiers, so an assignee column needs the user list resolved once and cached for the run.
Task identifiers are strings, and custom task identifiers are optional and vary by workspace, so decide which you are keying on.
Reporting people will act on
A project export usually exists because somebody wants a picture, and the picture is more useful than the table.
Lead with what is overdue and what has not moved, since those are the two lists anybody acts on.
Group by team or list, not by individual, so the conversation is about where work waits rather than about who is slow.
Show the change since the last run — what arrived, what completed, what slipped — because a static snapshot looks the same every week.
Include the count of tasks with no assignee and no due date, which is the most reliable measure of how much of the board is decorative.
Put the summary on its own tab, above the data, so the person who wants a glance is not scrolling through four thousand rows.
Keep the raw rows available underneath, since somebody will want to check a number and a summary they cannot verify is a summary they will not trust.
Making it survive
Resolve each list's configuration at the start of the run, rather than storing identifiers as settings.
Deduplicate on task identifier across lists, or multiple list membership inflates every count.
Replace a named range rather than appending, since tasks change and a sheet of current state should reflect that.
Report unmapped lists and missing fields rather than producing empty columns.
Report the outcome. Tasks exported, lists skipped, fields that could not be mapped, and duplicates removed.
Limits worth knowing about
Rate limits apply per token and depend on plan, so a workspace-wide export needs pacing.
Pagination applies to task listings, and a sheet built from the first page understates.
Sheets has a cell limit, which a workspace-wide export with many custom field columns reaches quickly.
Some features are plan-dependent, including parts of custom fields and time tracking.
Status change history availability varies, so confirm you can get what a time-in-status report needs before designing around it.
What to set up first
A fixed-column export across two or three lists, with the mapping in its own sheet and a report of anything that could not be mapped. Start with the lists somebody is already reconciling by hand, because that reconciliation is the work you are removing.
Two habits make the difference. Decide the columns before you look at the lists, since letting the export discover them is what produces the ragged sheet. And publish the unmapped report alongside the data, because it turns "this sheet is full of holes" into a short list of configuration changes somebody can actually make.
Frequently asked questions
Why is my export full of empty cells?
Because custom fields are defined per list, so a column that exists for one team does not exist for another. Fix the column set, map each list onto it explicitly, and report the lists that could not supply a column.
Why does grouping by priority give odd results?
Because two lists' priority dropdowns may offer different options. Normalise the values to a common vocabulary as part of the mapping, or the grouping mixes two different scales.
Should subtasks be included?
Decide, say which in the sheet, and add a column marking them. Including them double-counts anything summed; excluding them omits most of the work on lists that use them heavily. Both are defensible, silence is not.
Why does a task appear twice?
Multiple list membership, where that feature is enabled. Deduplicate on task identifier across lists, or every count in a cross-list export is inflated.
What is the most useful column nobody exports?
Time in current status. It is a better health signal than the status itself, it shows where work actually queues, and it needs only the status change history — which most exports never touch.
Why do dropdown and assignee columns show identifiers?
Because those fields return identifiers rather than labels. Resolve the option and user lists once per run and cache them, rather than doing a lookup per cell.
Where should the mapping live?
In a sheet of its own, so whoever owns the lists can see and maintain it. A mapping buried inside an automation is one nobody can check when a column looks wrong.
What should the summary show?
What is overdue, what has not moved, and the change since last run, grouped by team rather than by person. Plus the count of tasks with no assignee and no due date, which measures how much of the board is decorative.
Should the summary and the data share a sheet?
Same workbook, separate tabs, with the summary first. Somebody wanting a glance should not scroll through four thousand rows, and somebody checking a number should still be able to find it.