HTML Table Extractor: Web Tables to JSON and CSV avatar

HTML Table Extractor: Web Tables to JSON and CSV

Pricing

from $0.50 / 1,000 table extracteds

Go to Apify Store
HTML Table Extractor: Web Tables to JSON and CSV

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

Itay Ozer

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

Security

Limited permissions

Share

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 become column1, column2
  • rows: one object per data row, keyed by header. 1,234, $99.90, 12% and -3.5 become numbers; ids like 007 stay text; empty cells are null
  • csv: the same table as CSV text with a header line, original cell text
  • caption (the table's caption or its title row) and heading (the nearest h1 to h6 above it)
  • tableIndex: which <table> on the page it is, counted from 1
  • rowCount, columnCount, hasHeader, truncated
  • url, finalUrl (after redirects), pageTitle, statusCode, fetchedAt

How tricky tables are handled:

  • Merged cells: rowspan and colspan are 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 section column
  • 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:

statusMeaning
okA table (billed)
no-tablesThe page has no data tables, or builds them with JavaScript
blocked-by-robotsThe site's robots.txt does not allow it
http-errorThe site answered 4xx or 5xx
fetch-failedTimeout, DNS or connection error
invalid-url, unsupported-content-type, too-many-redirectsBad address, not an HTML page, redirect loop

Input

FieldRequiredExampleNotes
urlsyes["https://en.wikipedia.org/wiki/List_of_largest_cities"]Up to 10,000 per run. Duplicates are read once
maxTablesPerPageno501 to 1000, default 50, in page order
parseNumbersnotrueDefault 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:

EventPriceWhen
Table extracted$0.0005Every 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 the csv copy 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,5 and ranges like 10-20 stay 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.