How to filter an inventory csv to low stock items
- Step 1Export the full inventory CSV — From your WMS, ERP, or stock spreadsheet — anything with one row per SKU and a numeric quantity column (
Quantity,On Hand,Stock,Available). Make sure the quantity column holds plain numbers, not42 unitsor1,200with a thousands comma (those won't parse — see edge cases). - Step 2Drop the file onto the filter above — PapaParse parses it in your browser and auto-detects the delimiter. Headers populate the Filter column dropdown — select your quantity column by name.
- Step 3Pick the quantity column and a numeric operator — Choose
less_thanfor a below-threshold shortlist,equals0for out-of-stock only, orgreater_than0for in-stock only. The numeric operators are the only ones that compare magnitudes — text operators likecontainswon't do a numeric comparison. - Step 4Enter the threshold number — Type a plain number —
10,5,0.less_than 10keeps quantities 0–9. To include the threshold itself (≤ 10), set the value to11withless_than, since there's noless_than_or_equaloperator. - Step 5Filter and check the shortlist size — Click Filter rows. The panel shows Rows matched (your reorder list size), Rows filtered out, and a preview of the first 10 matching SKUs. If the count looks low, check for non-numeric quantity cells that parsed to NaN and were skipped.
- Step 6Download the reorder shortlist — Download gives
<name>.filtered.csv— the header plus only the low-stock SKUs, ready to drop into a purchase order or hand to procurement. Sort it by quantity first with CSV Sorter if you want the most urgent items at the top.
Numeric operators for stock thresholds
greater_than / less_than use parseFloat() on the cell. A cell that doesn't parse to a number becomes NaN and never matches — the row is filtered out, not treated as 0.
| Goal | Operator + value | Keeps quantities |
|---|---|---|
| Below 10 (reorder shortlist) | less_than 10 | 0, 1, 2 … 9 |
| At or below 10 (inclusive) | less_than 11 | 0 … 10 (no <= operator, so bump the threshold) |
| Out of stock only | equals 0 | exactly 0 (matches the text 0; 0.0 would not unless typed) |
| Still in stock | greater_than 0 | 1 and above |
| Overstock review (above 500) | greater_than 500 | 501 and above |
| Missing quantity (data gap) | is_empty | blank cells only — a SKU with no quantity recorded |
What does and doesn't parse as a number
parseFloat() reads from the start of the string and stops at the first non-numeric character. This determines whether a row is even eligible to match a numeric filter.
| Cell value | parseFloat result | Matches less_than 10? |
|---|---|---|
7 | 7 | Yes (7 < 10) |
12 | 12 | No (12 not < 10) |
7 units | 7 (stops at the space) | Yes — parseFloat reads the leading 7 |
units: 7 | NaN (starts with a letter) | No — never matches any numeric filter |
1,200 | 1 (stops at the comma) | Yes (1 < 10) — but you meant 1200, so this is a trap |
| `` (blank) | NaN | No — filtered out of every numeric comparison |
Cookbook
Real before/after slices from inventory exports. Costs anonymised. Numeric operators parse cells with parseFloat.
Reorder shortlist — everything under 10 units
ExampleThe classic low-stock pass. less_than 10 on the quantity column keeps every SKU with 0–9 units on hand, dropping the well-stocked ones.
Input (WMS export): SKU,Name,Quantity,Reorder Point A-100,Widget,4,10 A-101,Gadget,55,20 A-102,Sprocket,0,5 A-103,Bolt,8,15 Config: column = Quantity, operator = less_than, value = 10 Output (.filtered.csv): SKU,Name,Quantity,Reorder Point A-100,Widget,4,10 A-102,Sprocket,0,5 A-103,Bolt,8,15 Rows matched: 3 · Rows filtered out: 1
Out-of-stock only with equals 0
ExampleFor an urgent stockout report, equals 0 isolates exactly the zero-quantity SKUs. This is a text-equals on the literal 0, so make sure the column stores 0, not 0.0 or blank.
Input: SKU,Quantity B-1,0 B-2,3 B-3,0 B-4, Config: column = Quantity, operator = equals, value = 0 Output: SKU,Quantity B-1,0 B-3,0 Rows matched: 2 (B-4 is blank, not '0', so it is NOT matched — use is_empty for those.)
At-or-below threshold — bump the value (no <= operator)
ExampleThere's no less_than_or_equal. To keep quantities of 10 OR below, filter less_than 11. The 10s are then included alongside everything under.
Input: SKU,Quantity C-1,10 C-2,11 C-3,9 C-4,15 Wanted: quantity <= 10 Config: column = Quantity, operator = less_than, value = 11 Output: SKU,Quantity C-1,10 C-3,9 Rows matched: 2
The thousands-comma trap
ExampleIf quantities are formatted with thousands separators, parseFloat stops at the comma and reads only the leading digits — silently corrupting the comparison. Strip the comma first with Find & Replace.
Input (formatted quantities):
SKU,Quantity
D-1,"1,200"
D-2,"8"
D-3,"2,050"
Config: column = Quantity, operator = less_than, value = 10
Wrong result — parseFloat('1,200') = 1, so D-1 matches!:
SKU,Quantity
D-1,"1,200"
D-2,"8"
Fix: run /tool/csv-find-replace (',' -> '') on the Quantity
column first, THEN filter. parseFloat('1200') = 1200 (no match).SKUs with a missing quantity for data cleanup
ExampleA blank quantity won't match any numeric filter (parseFloat('') is NaN). To find those gaps, switch to the is_empty operator — it keeps the rows you need to backfill before trusting the reorder list.
Input: SKU,Quantity E-1,5 E-2, E-3,40 E-4, Config: column = Quantity, operator = is_empty (no value) Output: SKU,Quantity E-2, E-4, Rows matched: 2 (These never appear in a less_than result — fix them first.)
Errors and edge cases
Real errors and silent failures sourced from each platform's own documentation. Match the wording to the row, fix what the row says to fix.
Quantity has units or text (`7 units`, `units: 7`)
Partially parsedparseFloat reads from the start and stops at the first non-digit. 7 units parses to 7 (works), but units: 7 parses to NaN (never matches). Strip non-numeric text first with CSV Find & Replace or CSV Special Char Stripper so every quantity is a bare number.
Thousands separators in the quantity (`1,200`)
Silently wrongparseFloat('1,200') is 1, not 1200, because it stops at the comma. A less_than 10 filter would wrongly KEEP a 1,200-unit SKU. Always strip thousands commas with CSV Find & Replace (, → empty) before a numeric filter on a column that may be formatted.
Blank quantity cells
Filtered outparseFloat('') is NaN, and every comparison with NaN is false, so blank-quantity rows never match less_than or greater_than. They're dropped from the shortlist silently. Run an is_empty pass first to find and fix them, otherwise a missing-data SKU that should be reordered won't appear.
No less-than-or-equal operator
By designThe operator set is greater_than and less_than only — no inclusive <= or >=. For at-or-below 10, filter less_than 11; for at-or-above 500, filter greater_than 499. Adjust the threshold by one to include the boundary value.
Per-SKU reorder points differ
Single threshold per passThe filter applies one threshold to the whole column — it can't compare each SKU's Quantity against its own Reorder Point column. For a true per-SKU comparison you need a spreadsheet formula or a database query. As a workaround, CSV Sorter the file by quantity ascending and review the top of the list, or filter category-by-category with different thresholds.
equals 0 misses blank and 0.0 cells
Exact text matchequals 0 is a literal text match (case-insensitive), so it matches the cell 0 but not 0.0, 0 (leading space), or a blank. For out-of-stock detection across formats, normalise the column first, or combine an equals 0 pass with an is_empty pass and merge the results.
Decimal quantities (`3.5`)
SupportedparseFloat handles decimals, so less_than 10 correctly keeps 3.5. Fractional stock (weight-based or partial units) compares as you'd expect. Just ensure the decimal separator is a dot, not a comma (3,5 parses to 3).
Free tier 500-row / 2 MB cap on a large inventory
Upgrade requiredFree accounts cap at 2 MB and 500 data rows. A full SKU catalogue usually exceeds both. Pro raises the limit to 100 MB and 100,000 rows. Slice with CSV Row Limiter to work within free limits, or upgrade.
Frequently asked questions
How do I build a low-stock reorder list?
Pick the quantity column, choose the less_than operator, and enter your threshold (e.g. 10). Click Filter rows and download <name>.filtered.csv — the header plus every SKU below the threshold. The result panel shows Rows matched (your shortlist size). Sort it by quantity with CSV Sorter if you want the most urgent SKUs first.
Can I filter for exactly zero stock?
Yes — use equals 0. Note this is a literal text match on 0, so it matches the cell 0 but not 0.0 or a blank cell. For SKUs with a missing (blank) quantity, run a separate is_empty pass — those won't show up in an equals 0 or less_than result because a blank parses to NaN.
How do I keep quantities at or below the threshold (inclusive)?
There's no less_than_or_equal operator. To include the threshold value, bump it by one: for ≤ 10, filter less_than 11. Likewise for ≥ 500, filter greater_than 499. The numeric operators are strict < and > only.
Why did a clearly low-stock SKU not appear in my results?
Almost always a parsing issue. The numeric operators use parseFloat(). If the quantity cell is blank, starts with text (units: 7), or has a thousands comma (1,200 parses to 1), the comparison either fails or is wrong. Clean the column first: strip commas and units with CSV Find & Replace, then re-filter. Run an is_empty pass to catch blank quantities.
What if different SKUs have different reorder points?
A single pass applies one threshold to the whole column — it can't compare each row's Quantity to its own Reorder Point. For per-SKU comparison you'd need a spreadsheet formula or database query. As a workaround, sort by quantity ascending with CSV Sorter and review the top, or filter category-by-category with appropriate thresholds.
Does the quantity comparison handle decimals?
Yes. parseFloat reads decimals, so less_than 10 correctly keeps 3.5. Make sure the decimal separator is a dot — 3,5 would parse to 3 because parseFloat stops at the comma.
Will a thousands separator in the quantity break the filter?
Yes, silently. parseFloat('1,200') returns 1, so a 1,200-unit SKU would wrongly match less_than 10. Always strip thousands commas with CSV Find & Replace (, → empty) before a numeric filter on a column that might be formatted.
Is the header row counted in the matched rows?
No. The header is always preserved separately and never counted. If Rows matched is 23, the downloaded file has 24 lines — the header plus 23 low-stock SKUs — so it imports cleanly into your purchasing system.
Can I find SKUs with no quantity recorded?
Yes — use is_empty on the quantity column (it needs no value). It keeps rows where the cell is literally blank. These never appear in less_than/greater_than results because a blank parses to NaN, so run this pass to catch data gaps before trusting the reorder list.
How large an inventory file can I filter?
Free tier caps at 2 MB and 500 data rows. Pro raises this to 100 MB and 100,000 rows. For very large SKU catalogues, slice with CSV Row Limiter first or upgrade. Processing runs in-browser, bounded by your machine's memory.
Is my inventory data uploaded?
No. All parsing and filtering run locally in your browser via PapaParse. SKU costs, supplier columns, and stock levels never reach a JAD Apps server — only an anonymous run counter is recorded for signed-in dashboard stats.
Can I run the low-stock filter on a schedule?
Yes. GET /api/v1/tools/csv-column-filter returns the schema (column, operator, value, caseSensitive). Pair the @jadapps/runner once and POST your inventory export to 127.0.0.1:9789/v1/tools/csv-column-filter/run. A nightly pipeline: WMS export → filter Quantity less_than threshold → email the reorder shortlist to procurement. The runner is on-device, so stock data stays local.
Privacy first
Processing runs locally in your browser with PapaParse. No file is uploaded — only metadata counters are saved for signed-in dashboard stats.