Ask CSV

Ask a plain-English question about a spreadsheet and get back the number, the calculation that produced it, the rows it came from and a chart. The question is read by a parser rather than a language model, so there is no API key, no per-question cost, and no chance of a confident invention. Everything runs in this tab.

Local Deterministic No upload No API key

Want a question this tier will not answer? Open the full app, where you can bring your own LLM key or point at a local model, and the generated SQL is validated against your data before it is applied.

What this page does

You have an export. Somebody wants to know which region is ahead, whether last month was up on the month before, and how many rows are missing a value. Answering that means either a pivot table you will rebuild next week, a SQL prompt you have to remember the dialect of, or pasting the file into a chatbot and hoping. This page is the fourth option: type the question, read the number, and see exactly how it was calculated.

Behind the box is a parser with a fixed vocabulary. It peels a sentence apart from the outside in. A date expression comes off first, so "in Q1 2024" is understood as a window rather than mistaken for a column. Then any filter clause, so the word "North" in "where region is North" is never read as a metric. Then the shape of the question: is it a trend, a ranking, a breakdown, a comparison, a data-quality check? Only what is left is matched against your column names, using exact matches, a synonym table that knows revenue and sales and amount are usually the same idea, and edit distance for the typo you made at speed.

What comes out is a DuckDB query. It runs against your file in WebAssembly, in this tab, and the result is drawn with everything you would need to check it: the operation, the matched columns, the literal formula, the result rows, a sample of the underlying rows, and a chart chosen to fit the shape of the answer. If you would rather run the query yourself, the SQL is one click away and it is ordinary SQL.

A worked example

Press Try with sample data and a 10,000-row order file loads: an order id, an order date across two years, a region, a channel, a unit count, an amount and a refunded flag. The left rail fills in immediately. Metrics detected: amount and units. Group by: region and channel. Dates: order_date. Underneath, six starter questions generated from those roles, each one a sentence the parser is guaranteed to answer.

Type total amount by region. The chips read Operation Total amount, Metric amount, Group region. The formula reads SUM(amount) GROUP BY region. The headline is the leading region's total, with the exact figure underneath it, and a sentence saying which region is highest and how many groups there are. A horizontal bar chart appears, then the four result rows, then ten rows from your own file drawn from the leading region so you can see the raw numbers the total was built from.

Now narrow it: total amount by region where channel is online in 2024. Two more chips appear, one for the filter and one for the window, and the SQL grows a WHERE clause with both. Text comparison is case-insensitive on purpose, so typing "online" against data that says "Online" finds the rows rather than returning zero and letting you believe there were none.

Ask amount month over month and you get a line chart of monthly totals with a LAG column showing the change and the percentage change. Ask outliers in amount and you get a count, the fence the count used, and the rows furthest outside it. Ask show missing values and you get one row per column with a count and a percentage, blanks counted alongside nulls because an empty string in a CSV is a missing value whatever the type system says. Ask why did revenue fall and you get a refusal, on purpose.

From answers to a report

Press Pin to brief on each answer worth keeping. Pinned findings collect in the right rail in the order you pinned them, and you can move them up and down until the argument reads properly. Give the brief a title and an analyst note explaining what the reader is looking at, then download it.

The HTML export is one self-contained file. No script tag, no web font, no image, no analytics, and an inline Content-Security-Policy of default-src 'none' that forbids the browser from fetching anything at all, together with noindex and no-referrer directives. Every finding carries its question, its number, its chips, its formula, its result table and, in a collapsed block, the SQL that produced it. It prints properly and it reads properly in dark mode. The Markdown export carries the same content for a wiki or a pull request.

Recipes, for the report you write every week

Most analysis is not a one-off. It is the same eight questions against a new export every Monday. Save the pinned question list as an analysis recipe and you get a small JSON file holding a schema version, a name, a report title, your context note and the questions in order. That is the whole contract: no filename, no rows, no answers, no formulas, no chart points, no column values. You can read the file and confirm it yourself, and the format is documented at recurring report recipes.

Next Monday, drop the new file, press Run on this file, and every question is answered again against the new rows. If a column has been renamed or dropped, the questions that depended on it are skipped and listed by name with the reason. That is deliberate. A recipe that quietly substituted a similar-looking column would produce a report that looks the same and means something different, which is the failure mode worth engineering against.

What it will not do

It will not explain why a number moved. It will not forecast next quarter. It will not recommend an action, name a root cause, or write a narrative around your figures. Those questions are refused by name rather than answered badly. It will also refuse any question whose words do not match a column in your file, and it will tell you which words failed and suggest the nearest column name if one is close. Where two columns fit a phrase equally well, it asks which you meant instead of picking.

For the open-ended question, the full app takes over. There you can bring your own key for any of ten LLM providers, or point it at a local model on your own machine, and the SQL the model writes is validated against your actual schema before it becomes a step you can edit, chain and re-run. The deterministic tier on this page is the floor, not the ceiling.

Questions it understands

What is the total amount?

Sums, averages, medians, minima, maxima, distinct counts, row counts.

Average amount by channel

Any aggregate grouped by any column, with an optional share of total.

Top 5 region by amount

Top or bottom N, and "which region has the highest amount".

Amount by month

Trends at day, week, month, quarter or year, with the grain stated.

Amount year over year

Period-over-period change, in absolute terms and as a percentage.

Total amount where region is North

Filters on equality, inequality, ranges, contains and starts with.

Total amount in Q1 2024

Years, quarters, months, "last 30 days", "since March", explicit ranges.

Correlation between units and amount

Pearson correlation with the pair count, and the caveat stated.

Outliers in amount

The 1.5 x interquartile fence, the count, and the rows outside it.

Show missing values

Nulls and blanks per column, as a count and a percentage.

Are there duplicate rows?

Exact repeats across every column, with the repeated rows shown.

Compare North and South by amount

Two values of one column, with the gap in absolute and percentage terms.

Questions and answers

Is this AI, and do I need an API key?

No and no. The question is read by a parser, not a language model. It recognises a fixed set of shapes: totals, averages, medians, minima and maxima, distinct counts, rankings, group-by breakdowns, trends at a chosen grain, month-over-month and year-over-year change, filters, date windows, correlations, outliers, missing values and duplicate rows. Each one compiles to a DuckDB query that runs in your browser tab. There is no key to paste, no account to make and no per-question cost, and the same question against the same file always produces the same number.

Does my file get uploaded anywhere?

No. The only network request this page makes is the one that fetches the DuckDB WebAssembly engine from a CDN, and that request carries none of your data. Your file is read by JavaScript in your own tab, queried in memory, and forgotten when you close it. Nothing is stored between visits except your question history and any recipes you save, both of which live in your browser and hold no rows from your file.

What happens when it cannot answer my question?

It says so, and it says which words it could not match to a column. It never picks a plausible column and hands back a confident number, because a wrong answer that looks right is worse than no answer. Questions about causes, forecasts and recommendations are refused by name: this tier calculates what is in the file and will not invent what is not. After a refusal you get a short list of questions that this particular file can answer, each one clickable.

How do I know the number is right?

Every answer shows its working. You get chips naming the operation, the matched metric, the grouping column and any filter; the calculation as one readable line, for example SUM(amount) GROUP BY region; the full SQL, expandable and copyable; the result rows; and a sample of the rows from your own file that stand behind the leading figure. Copy the SQL into DuckDB, a warehouse or anything else that speaks SQL and you will get the same figure.

What is an analysis recipe?

An ordered list of up to twelve questions saved as portable JSON, plus a report title and your own context note. It holds no filename, no rows, no answers, no formulas and no chart points, so it is safe to commit to a repository or mail to a colleague. Load next week's export, run the recipe, and every figure recalculates. A question whose column has vanished is skipped and named, because a schema change is news rather than something to paper over.

What can the brief export do?

Pin any answer and it joins an ordered list of findings on the right. Give the brief a title and a context note, reorder the findings, then export standalone HTML or Markdown. The HTML is a single file with no script, no external font and no image reference, carrying an inline Content-Security-Policy that blocks the lot along with a noindex directive. It shows the same figures on a colleague's laptop as it does on yours, and it carries the SQL for every finding so the reader can re-run it.

Which file formats work here?

CSV, TSV, plain-text delimited files, JSON, JSON Lines, Parquet, and the first sheet of an Excel workbook. Delimiters, quoting and column types are sniffed by DuckDB, so a semicolon-separated European export and a comma-separated American one both work without a setting. For a workbook with several sheets worth asking about, split it first with the Excel to CSV converter.

How large a file can it handle?

Files of a few hundred megabytes are comfortable on a normal laptop, because the work is done by DuckDB compiled to WebAssembly rather than by JavaScript looping over rows. The practical ceiling is the memory your browser tab is allowed, not a row count we imposed. Ten million rows of numbers will answer a total in about the time it takes to read the question back.

A question, a number, and the working

Free, no account, no upload, no API key. Drop the file and ask.

Back to the top