HTML Table Extractor: Web Tables to JSON and CSV
Pricing
from $0.50 / 1,000 table extracteds
HTML Table Extractor: Web Tables to JSON and CSV
Extract every HTML table from any list of web pages into clean JSON rows and CSV: headers detected, merged cells expanded, numbers parsed, with caption and nearest heading for context. Plain HTTP, obeys robots.txt. Built for AI agents.
Pricing
from $0.50 / 1,000 table extracteds
Rating
0.0
(0)
Developer
Itay Ozer
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Security
Limited permissionsShare
Give it web page URLs, get back every data table on those pages as clean JSON rows and CSV. Headers are detected, merged cells are expanded, numbers come out as numbers, and each table carries its caption and the nearest heading above it, so an AI agent knows what the table is about without reading the page.
Built for AI agents, RAG pipelines and anyone who needs a Wikipedia list, a stats page or a price list as data. It reads plain HTML over HTTP (no browser), obeys each site's robots.txt and Crawl-delay, and asks one host for one page at a time.
What you get
One dataset item per table:
headers: column names in page order. Two-row headers are joined (City proper / Population), repeated names get(2), missing ones becomecolumn1,column2rows: one object per data row, keyed by header.1,234,$99.90,12%and-3.5become numbers; ids like007stay text; empty cells arenullcsv: the same table as CSV text with a header line, original cell textcaption(the table's caption or its title row) andheading(the nearest h1 to h6 above it)tableIndex: which<table>on the page it is, counted from 1rowCount,columnCount,hasHeader,truncatedurl,finalUrl(after redirects),pageTitle,statusCode,fetchedAt
How tricky tables are handled:
- Merged cells:
rowspanandcolspanare expanded, so every row has every column (a merged value is copied into each cell it covers) - Group rows: a row that is one cell across the whole table (Paris, Rome; Asia, Europe) labels the rows under it and becomes a
sectioncolumn - Title rows: a single cell spanning the top of the table becomes the caption, not a header (Wikipedia infoboxes)
- Noise removed: footnote markers like
[1], hidden sort keys and edit links never reach your data - Layout tables skipped: navigation boxes,
role="presentation"tables, wrapper tables and tables of one row or one column are left out and never billed. Tables nested inside a wrapper are still read
Pages that give no table still get one free item with status and a plain error, so you always know what happened to every URL:
status | Meaning |
|---|---|
ok | A table (billed) |
no-tables | The page has no data tables, or builds them with JavaScript |
blocked-by-robots | The site's robots.txt does not allow it |
http-error | The site answered 4xx or 5xx |
fetch-failed | Timeout, DNS or connection error |
invalid-url, unsupported-content-type, too-many-redirects | Bad address, not an HTML page, redirect loop |
Input
| Field | Required | Example | Notes |
|---|---|---|---|
urls | yes | ["https://en.wikipedia.org/wiki/List_of_largest_cities"] | Up to 10,000 per run. Duplicates are read once |
maxTablesPerPage | no | 50 | 1 to 1000, default 50, in page order |
parseNumbers | no | true | Default true. Off: every value stays text |
{"urls": ["https://en.wikipedia.org/wiki/List_of_largest_cities","https://www.w3.org/WAI/tutorials/tables/irregular/"],"maxTablesPerPage": 50,"parseNumbers": true}
Output example
{"url": "https://www.w3.org/WAI/tutorials/tables/irregular/","finalUrl": "https://www.w3.org/WAI/tutorials/tables/irregular/","status": "ok","statusCode": 200,"error": null,"pageTitle": "Tables with Irregular Headers | Web Accessibility Initiative (WAI) | W3C","tableIndex": 1,"caption": null,"heading": "Table with two tier headers","headers": ["column1", "Mars / Produced", "Mars / Sold", "Venus / Produced", "Venus / Sold"],"rows": [{ "column1": "Teddy Bears", "Mars / Produced": 50000, "Mars / Sold": 30000, "Venus / Produced": 100000, "Venus / Sold": 80000 },{ "column1": "Board Games", "Mars / Produced": 10000, "Mars / Sold": 5000, "Venus / Produced": 12000, "Venus / Sold": 9000 }],"csv": "column1,Mars / Produced,Mars / Sold,Venus / Produced,Venus / Sold\nTeddy Bears,\"50,000\",\"30,000\",\"100,000\",\"80,000\"\nBoard Games,\"10,000\",\"5,000\",\"12,000\",\"9,000\"","rowCount": 2,"columnCount": 5,"hasHeader": true,"truncated": false,"fetchedAt": "2026-10-31T19:00:00.000Z"}
Column order is the order of headers. Some JSON tools sort number-like keys (such as 2024) to the front of an object, so use headers (or csv) when column order matters.
Pricing
You pay per table returned, nothing per page or per run beyond Apify's standard start fee:
| Event | Price | When |
|---|---|---|
| Table extracted | $0.0005 | Every table in your dataset |
Example: 1,000 tables cost $0.50. A Wikipedia page with 4 data tables costs $0.002.
Free: pages that fail, pages blocked by robots.txt, pages with no tables, and layout or navigation tables. The actor checks your run's maximum charge before each page and stops cleanly when it is reached, so a run never goes over the limit you set.
Limits
- Plain HTTP only: tables that a page draws with JavaScript after loading are not seen (you get
no-tables). Most Wikipedia, government, sports-reference, documentation and price-list pages serve their tables in the HTML - Pages are read up to 4 MB and 100,000 cells; a table cut at that point has
truncated: true. A single table too large for one dataset item (about 9 MB) keeps its rows, drops thecsvcopy and, if still too large, is cut - One host is read one request at a time, at least 0.25 s apart (longer when its robots.txt sets a Crawl-delay, up to 10 s). Many URLs on one site therefore take a while; different sites run in parallel
- Public http and https addresses only. No logins, no cookies, no proxies
- Numbers: European formats like
1.234,5and ranges like10-20stay text on purpose, so nothing is guessed
FAQ
Which pages work best? Any page whose tables are in the HTML: Wikipedia lists and infoboxes, government statistics, sports stats, exchange or rate tables, documentation reference tables, price lists.
How do I use it from an AI agent?
Call it through the Apify API or the Apify MCP server with a list of URLs. Each table comes back with its heading and caption, so the agent can pick the right table without the page.
Why did a page give no-tables when I can see a table in my browser?
The site builds that table with JavaScript, or the "table" is made of styled boxes rather than a real <table>. Use a browser-based scraper for those pages.
Do you respect robots.txt?
Yes. Every site's robots.txt is read before its pages (the bot name is TableExtractorBot). Disallowed pages are skipped, returned with blocked-by-robots and not charged.
Is there personal data in the results? The actor returns only what the tables on the pages you choose contain. You are responsible for the URLs you send and for how you use the data.
Something broke or a table looks wrong. What do I do? Open an issue on the Issues tab with your run link and the page URL. Issues are answered within a few days.