Chris Collins

Tools · data

Data wrangler

Clean and reshape tables with a recipe of steps — trim, retype, split, cluster near-duplicates, join, pivot, group — preview every step, then replay the recipe on new files or export it as SQL or pandas. DuckDB takes over for millions of rows.

Added · updated 28 October 2026

Works with

  • Log parser Dataopens a log parsed in the log parser as a CSV table to clean and reshape
How to use it

Load one or more tables, then build a recipe: a list of steps, each a small cleaning or reshaping operation. Every step shows its result as you edit it, can be switched off, edited, dragged to a new place, or deleted, and the whole recipe can be saved and replayed on next month’s file. It works like OpenRefine or Excel’s Power Query, in the browser.

⛶ Full screen (or F) gives the table the whole screen — the browser’s full screen where it is allowed, otherwise a full-window layer (iPhone); ◫ Panels hides the file and table toolbar, the recipe, the profile and the export tabs, so the grid gets the whole height (on a phone they start hidden). Escape leaves (or closes an open menu first).

Loading data

  • Open files… or drop files anywhere on the tool: CSV, TSV and text (the delimiter, quote character, header row and text encoding are detected; ⚙ on a table overrides them), JSON (an array of objects, an object holding one, or NDJSON — nested objects become dotted columns such as warehouse.city), Excel .xlsx (each sheet becomes a table; the SheetJS reader loads from cdnjs the first time), and Parquet (read by DuckDB).

  • Paste takes CSV, TSV, JSON or NDJSON from the clipboard.

  • Samples has deliberately messy data: customers with stray spaces, inconsistent case, near-duplicate names and companies, dates written five ways, money as text ($1,234.50, 1.200,00, (45.00)), blanks and duplicates, plus their orders for joins; wide monthly sales for pivots; nested JSON; and a million synthetic rows generated in DuckDB.

You can load several tables. The main table is the one the recipe runs on; the others are there to join or append. Use on another table makes it the main one and replays the recipe on it, warning about any step whose columns are missing.

Steps

Click a column header for its menu (sort, filter, pick values, change type, trim, split, cluster, fill, group, pivot, rename, drop…), press + Add step (or A), or use a Fix button in the profile. New steps go after the selected one.

  • Columns: rename, reorder, drop, keep.

  • Rows: filter with an expression; pick values (a facet); sort on several keys (blanks last); remove duplicates (whole rows or chosen keys, optionally ignoring case and spaces); sample or limit (first, last, random with a seed, a percentage, every nth); row numbers.

  • Text: trim and collapse whitespace (including non-breaking spaces); change case; find and replace (plain, whole cell, or regular expressions with $1 groups); split a column by a delimiter or regex into columns or rows; merge columns; extract with a regex capture; pad; substring.

  • Values: change type — number (currency symbols, thousands separators, 1.234,50 decimal commas, (45) negatives and % understood), integer, boolean, date or date-time (formats detected, or given such as DD/MM/YYYY), text — with the cells that failed reported; fill blanks (a constant, down, up, mean, median, most common); cluster and merge near-duplicates; computed columns.

  • Reshape: group with count, sum, average, min, max, median, distinct count, first, last and concatenate; pivot (long to wide) and unpivot (wide to long).

  • Combine: join with another table (inner, left, right, full, anti, semi), with key diagnostics — matched and unmatched rows, repeated keys that multiply rows, and near misses that differ only in case or spaces; append tables by column name.

Click a step to see the table as it was after it. Cells the step changed are highlighted (hover one to see what it was) and new columns are tinted. Undo and Redo cover every change to the recipe.

Clustering

Cluster and merge finds values that are probably the same thing, the way OpenRefine does:

  • Fingerprint ignores case, accents, punctuation, extra spaces and word order, so Acme Corp., ACME corp and Corp Acme meet.

  • N-gram fingerprint compares the letter pairs (or triples) in each value, catching some typos.

  • Nearest neighbours groups values within a few edits (Levenshtein distance) of each other, such as Jon Smith and John Smith.

Tick the clusters to merge and choose the value each becomes. The step records exactly which values map to which, so it replays the same way on new data.

Expressions

Filters and computed columns use a small expression language (it is parsed by the tool, never run as JavaScript). Columns by name, or [Name With Spaces]; text in quotes.

  • Operators: + - * / % ^, & joins text, = != < ⇐ > >=, and or not, in (…), ?? (first non-blank). Text columns holding numbers are converted for arithmetic and comparisons with numbers; blanks stay blank (qty * 2 is blank when qty is).

  • Text: upper lower title sentence trim collapse len left right substr replace regex_replace regex_extract regex_match contains starts_with ends_with split_part concat lpad rpad repeat reverse find pattern fingerprint.

  • Numbers: number int round floor ceil abs sign sqrt pow exp ln log10 mod min max.

  • Dates: date datetime year quarter month day hour minute second weekday week date_add date_diff format_date today now.

  • Logic and blanks: if case coalesce isnull isblank ifblank nullif.

For example if(qty > 10, 'bulk', 'single'), round(number(price) * 1.2, 2), date_diff(signup_date, today(), 'day'), upper(left(country, 2)) & '-' & id.

Profile

The side panel profiles one column of the table you are looking at: its type (and what it looks like if it is text holding numbers or dates), blanks, distinct values, min, max, mean and median, a histogram for numbers and dates, the most common values, and value patterns — A for capitals, a for lower case, 9 for a digit, so a postcode column shows A9 9A, A9A 9A and the odd one out. Click a bar, value or pattern to add a filter. Data quality lists stray spaces, case variants, numbers stored as text, mixed date formats, blanks, near-duplicates and duplicate rows, each with a fix.

Big files and DuckDB

Small and medium tables (a few hundred thousand rows) run in plain JavaScript with nothing to download. Switch the engine to DuckDB — or open a file over 50 MB, or a Parquet file, and it switches itself — and the recipe is compiled to SQL and run by DuckDB-Wasm (about 35 MB from jsDelivr the first time). The table then fetches only the rows you scroll to, so millions of rows are fine. Both engines follow the same rules; the tests check that the SQL gives the same table as the JavaScript, cell for cell.

Recipes, SQL and pandas

  • Recipe JSON (and Recipe ▾ → Save as JSON) is the recipe as a file; Open recipe… applies a saved recipe to the main table and reports steps whose columns are missing. Your last recipe and small tables are remembered in this browser.

  • SQL is the whole recipe as one DuckDB query — run it with the duckdb command line next to your files. A few helper macros (number parsing, trimming) come first.

  • pandas is a Python script that applies the same steps with pandas and writes the result as CSV. It includes small helpers so blanks, numbers, dates and text follow the wrangler’s rules exactly, rather than pandas' own.

  • Export writes CSV, TSV, JSON, NDJSON, a Markdown table, SQL INSERT statements, or Parquet (via DuckDB), or copies the result for a spreadsheet.

Keyboard

A adds a step, [ and ] step back and forward through the recipe, ⌘Z / Ctrl+Z undoes and ⇧⌘Z / Ctrl+Y redoes. In the step list, ↑ ↓ select, Enter edits, Space switches a step off or on, ⇧↑ ⇧↓ move it and Delete removes it. ⌘/Ctrl+Enter applies the step being edited; Esc cancels. ? shows the list.

Limits

  • The JavaScript engine keeps tables in memory; past a few hundred thousand rows (or a 50 MB file) use DuckDB. Live previews of a step on very large JavaScript tables use the first 50,000 rows.

  • Regular expressions are JavaScript’s in the JavaScript engine and RE2’s in DuckDB: lookahead and lookbehind do not work in DuckDB. Title case capitalises after spaces only.

  • Excel files are read as the values shown in the sheet (as text); formulas are not kept.

  • Generated SQL for JSON sources reads nested objects as DuckDB structs rather than dotted columns, and Excel sources must be saved as CSV first.

  • DuckDB and SheetJS load from jsDelivr and cdnjs when first needed; your data never leaves the page.

Sharing

Share link (and Recipe ▾ → Copy recipe link) copies a link carrying the recipe — compressed into ?r= — but not your data, unless you are working on one of the samples, which the link loads too. For example tidies the sample customers' countries and counts them. ?tab=sql, pandas, json or export opens that tab.

Related: CSV viewer (fast browsing, sorting and filtering of a big CSV), data converter (JSON, YAML, CSV, XML and TOML), and the JSON workbench.

Runs entirely in your browser — network requests go only to the services named on this page.