How to use Claude for data analysis — without re-uploading every time
Claude is a genuinely good data analyst. The hard part was never the analysis — it's the data getting there, and staying there. Drop a CSV into a claude.ai conversation and you'll get a clean read of it in seconds: the outlier flagged, the segment that's dragging the average, the SQL to reproduce it. Then the conversation ends, and the next time you need that same answer you're exporting the same file again. This guide covers both halves: what the upload workflow is actually good at, and how to give Claude a standing connection to your data so recurring analysis stops being a re-upload ritual.
What Claude can already do with a table of numbers
It's worth being precise about where the capability sits, because the ceiling isn't where most people assume.
- It reads tabular data properly. Not just "summarize this" — it will notice that your conversion rate jumped because the denominator changed, not the numerator.
- It writes and debugs real analysis code. SQL with window functions, a pandas pivot, a quick chart. And it iterates when the first query returns something implausible.
- It knows the metric traps. That CTR isn't CVR, that averaging an average is usually wrong, that a spike in impressions with flat clicks means you started ranking for junk.
- It explains itself. The reason a model beats a dashboard for exploratory work is that you can ask "why?" and get a chain of reasoning rather than another chart.
None of that is the bottleneck. The bottleneck is reach: Claude analyzes what you can put in front of it, and how you put it there decides whether the analysis is a one-off or a habit.
Two surfaces, two different ceilings
People searching for how to use claude.ai for data analytics are usually on one of two surfaces, and they fail differently.
claude.ai with file uploads
You upload a CSV or spreadsheet into the conversation and ask questions in plain language. This is excellent for what it is: zero setup, no install, good for a file someone emailed you or a one-time question about last quarter. The ceiling is structural — the data is a snapshot you carried in by hand. Nothing connects back to Search Console, GA4 or your ad accounts, so a weekly question means a weekly export. And each new conversation starts from zero: the definitions you agreed on last time ("revenue means net of refunds") don't carry over.
Claude Code in your terminal
Claude Code can already reach your filesystem and run any command. That solves the "carried in by hand" problem for files on disk — see CSV analysis with Claude Code for that path specifically. But your marketing and product numbers mostly aren't files on disk. They're behind OAuth flows and rate-limited APIs, and wiring each one up by hand is a small engineering project you'd rather not maintain.
The fix: give Claude a queryable backend, not more files
The move that changes the workflow is to stop feeding Claude data and start giving it a place to query data. That's what TableBI is — a data backend built to be driven by a CLI-native agent, around three verbs:
- Pipe — connect each source once with a browser OAuth round-trip. Search Console, GA4, Meta Ads and Google Ads connect live; anything else arrives as CSV and is normalized into the same definitions. Data lands at two altitudes: metrics, one cross-channel table where spend is spend and clicks are clicks regardless of platform, and raw, the lossless per-platform tables underneath.
- Ask — read-only SQL against either altitude, from the terminal. Cross-channel questions hit the unified definitions; forensic questions hit raw.
- Pin — freeze any analysis into a live dashboard at a public read-only URL that keeps refreshing as sources sync.
Worth being explicit about: TableBI hosts no LLM. The backend serves deterministic numbers from a SQL engine; the reasoning happens inside your own Claude session, under your account and your data policy. Inference cost on our side is $0 because your agent is the brain.
Setting it up
Install the CLI, then plant the skill so Claude Code knows the tool exists and when to reach for it:
# install the CLI, then teach your agent to drive it
npm i -g @tablebi/cli
tablebi login
tablebi install
tablebi install drops a skill into ~/.claude/skills. After that you don't type commands at all — "connect my Search Console" or "which channel lost the most conversions last month?" is enough, and the agent picks the commands itself. Connecting each source is one OAuth round-trip:
# live sources — browser opens for OAuth, then data syncs in tablebi connect gsc --site sc-domain:example.com tablebi connect ga4 tablebi connect meta_ads tablebi connect google_ads # files land in the same definitions instead of a one-off upload tablebi connect csv --file tiktok-export.csv --platform tiktok_ads
Every session then opens with a single rehydration call — definitions, connected sources, freshness, and the command cheatsheet in one JSON blob the agent holds in context. This is the piece that replaces "re-explaining your data model every conversation":
tablebi context --json
What the analysis actually looks like
Cross-channel questions run against the unified metrics table, with definition macros — roas, ctr, cpa, cvr, aov — so the arithmetic is never re-derived by hand:
# where is the money going, and what is it returning? tablebi ask "SELECT platform, SUM(cost) AS spend, roas(SUM(conversion_value), SUM(cost)) AS roas FROM facts WHERE date >= (SELECT MAX(date) FROM facts) - 30 GROUP BY platform ORDER BY spend DESC"
Diagnostic questions drop to the raw altitude — the exact rows each platform reported, nothing averaged away:
# which pages are getting seen but not clicked? tablebi ask "SELECT page, SUM(impressions) AS imp, SUM(clicks) AS clicks, avg_position(SUM(position*impressions), SUM(impressions)) AS pos FROM search_console_raw WHERE date >= (SELECT MAX(date) FROM search_console_raw) - 28 GROUP BY page HAVING SUM(impressions) > 100 ORDER BY clicks / SUM(impressions) ASC LIMIT 20"
Note the date filter: (SELECT MAX(date) FROM …) - 28 rather than today's date. Sources finalize on their own clocks — Search Console lands roughly two to three days behind — so anchoring the window to the newest row you actually have is how you avoid a "traffic collapsed!" panic that's really just a reporting lag.
How Claude avoids being confidently wrong
This is the part that matters most when a model is doing the analyzing, and it's the part upload-a-CSV workflows structurally can't give you. Every answer ships with a trust block alongside the rows:
- Freshness per source — what date each source has data through, how many days old that is, and whether it counts as stale. The agent can say "Meta is current, Search Console runs three days behind" instead of quietly comparing incomparable windows.
- Caveats — the definitional landmines, in plain language. For example: a Search Console click and a GA4 session are different populations counted different ways, and shouldn't be expected to reconcile. Claude reads that and explains the gap rather than inventing a reason for it.
A model with no metadata will happily produce a confident number from a half-synced table. A model handed freshness and caveats will tell you which number not to trust yet. More on that design in Claude Code analytics.
Make the analysis outlive the session
The deepest limitation of chat-based analysis is that the work evaporates when the conversation closes. When an analysis is worth keeping, pin it instead of screenshotting it:
tablebi pin --title "Weekly performance" \ --widget "Daily clicks (28d)::line=SELECT date, SUM(clicks) AS clicks FROM facts …" \ --widget "Spend by platform=SELECT platform, SUM(cost) AS spend FROM facts …" ✓ published → https://dk.tablebi.com/d/dsh_… (public, read-only, self-refreshing)
You get a URL, not an artifact — it keeps refreshing as the sources sync. Here's a real one, live Search Console data across a portfolio of sites, pinned exactly this way: