Aditya Sharma

Get Data From a Website Into Google Sheets: Which Method Fits

On this page, 9 sections

To get data from a website into Google Sheets, choose the function by page type. IMPORTHTML reads an HTML table or list. IMPORTXML reads single elements with an XPath query. IMPORTDATA reads a CSV or TSV file, and IMPORTFEED reads RSS or Atom. For JSON, or anything that needs a header or a schedule, use Apps Script.

JSON is the gap. I read the help page for each of the four import functions on 11 October 2026, and none of them lists JSON as a format. That is why API data needs a script, and why most people hit a wall with a formula that was never built for it.

The sitemap post on this site covers one use of IMPORTXML. This one is the map around it: which tool for which page, and the limits that decide when to leave formulas behind.

Pick the function by page type

Page typeUseSyntax from Google’s help pageWatch for
An HTML table or listIMPORTHTMLIMPORTHTML(url, query, index) with query “table” or “list”Table and list indices are counted separately, both start at 1
One value, or a set of values, inside a pageIMPORTXMLIMPORTXML(url, xpath_query, locale)You must write the XPath yourself
A CSV or TSV file at a URLIMPORTDATAIMPORTDATA(url)Only .csv and .tsv are listed
An RSS or Atom feedIMPORTFEEDIMPORTFEED(url, [query], [headers], [num_items])Query defaults to “items”
A JSON APIApps Script with UrlFetchAppfetch(url) or fetch(url, params)Runs against quotas, below
Another Google SheetIMPORTRANGEImports a range of cells from a specified spreadsheetNot for websites

Google’s own samples are a good starting point: IMPORTHTML("https://en.wikipedia.org/wiki/Demographics_of_India","table",4) for the fourth table on a page, and IMPORTXML("https://en.wikipedia.org/wiki/Moon_landing","//a/@href") for every link.

Check what the page actually serves first

All of these fetch a URL and read what comes back. The help pages do not say whether the page’s JavaScript is run before the function reads it, so I treat that as not documented and test instead. Search the raw HTML for text you can see in the browser:

curl -s "https://example.com/page" | grep -c "text you see in the browser"

A count of 0 means the text is not in the HTML the server sends. A formula is then a gamble. Look for the JSON the page loads in your browser’s network tab, or an official API, and use the script route below.

Test your XPath before it goes in a cell

A wrong XPath gives an empty result and no explanation, so I test them outside the Sheet. I ran three against real files with xmllint, a command-line XPath engine. It is a stand-in for the Sheets engine, not the same code, so treat it as a sanity check.

  • //*[local-name()='sitemap']/*[local-name()='loc'] on my sitemap index returned 4 child sitemaps.
  • //*[local-name()='url']/*[local-name()='loc'] on one post sitemap returned 200 URLs.
  • //a/@href on my homepage HTML returned 70 links, and //h2 matched 8 headings.

The local-name() form matters on sitemaps because they declare an XML namespace. The URL-finding post explains where to get the sitemap in the first place.

When a formula is not enough: Apps Script

Apps Script’s UrlFetchApp.fetch(url) makes the request and returns an HTTP response object you can parse yourself. That is the route for JSON, for custom headers, and for writing results on a schedule. This importer reads a JSON array and writes two columns:

function importJson() {
  const url = "https://example.com/api/items.json";
  const res = UrlFetchApp.fetch(url, { muteHttpExceptions: true });
  if (res.getResponseCode() !== 200) {
    throw new Error("HTTP " + res.getResponseCode());
  }
  const items = JSON.parse(res.getContentText());
  const rows = items.map(i => [i.slug, i.link]);
  const sheet = SpreadsheetApp.getActiveSheet();
  sheet.clearContents();
  sheet.getRange(1, 1, 1, 2).setValues([["slug", "link"]]);
  sheet.getRange(2, 1, rows.length, 2).setValues(rows);
}

I syntax-checked it with node --check. I then ran it in Node with a stand-in for UrlFetchApp and SpreadsheetApp, feeding it 20 real records from my own site’s REST API. It wrote a header row and 20 rows of two columns. I have not run it inside Apps Script, so test it on a copy of your sheet first.

Replace slug and link with the keys in your JSON. If the response is an object rather than an array, items.map will throw, so open the URL in a browser and look at the shape first.

The limits that decide which route you use

These are from the Apps Script quotas page and the Drive file limits page, both read on 11 October 2026:

LimitConsumer accountGoogle Workspace
URL Fetch calls per day20,000100,000
Script runtime6 min per execution6 min per execution
Custom function runtime30 sec per execution30 sec per execution
Cells in a spreadsheetUp to 20 million cells or 100MBUp to 20 million cells or 100MB

The 6 minutes against 30 seconds is the practical rule. A custom function that fetches a page has 30 seconds. A script run from a menu or a trigger has 6 minutes, which is 360 seconds, twelve times as long. The cell limit is a Drive file limit for sheets created in or converted to Google Sheets.

What to use for common jobs

  • A price table on a page: IMPORTHTML, then check the index.
  • A list of links from a page or sitemap: IMPORTXML with //a/@href or the sitemap XPath above.
  • A published CSV: IMPORTDATA.
  • A blog’s latest posts: IMPORTFEED.
  • A JSON API such as YouTube’s: a script. The YouTube import post does this with the YouTube API.

If you want the opposite direction, a sheet that feeds a web page, see turning a Google Sheet into a website.

One rule for all of it: only pull from sites you own or have permission to read, and check robots.txt and the site’s terms before you schedule anything.

What I could not verify

  • JavaScript rendering: the four help pages do not say whether scripts on the page are run. I treat it as not documented.
  • Refresh timing: I did not find a refresh interval on the pages I read, so I do not give one.
  • Per-site rate limits: a site can block repeated requests. That is the site’s rule, not Google’s, and I did not test any third-party site for this post.
  • Behaviour inside Sheets: I could not open a spreadsheet from this session, so every formula in this post is Google’s own sample or was tested outside Sheets.

That list is also a to-do. Each item can be settled in ten minutes with a throwaway sheet before you build anything on top of it.

Questions people ask

Can Google Sheets import JSON?

Not through the four import functions: their help pages list HTML, XML, CSV, TSV, RSS and Atom, and none mention JSON. Use Apps Script.

Why does IMPORTXML return nothing?

The XPath matched nothing in the HTML the function received. Check the raw source with the curl line above and test the XPath in a command-line tool first. I did not find an error list in Google’s help page.

How many fetches can a script make per day?

20,000 URL Fetch calls on a consumer account and 100,000 on Google Workspace, per the quotas page read on 11 October 2026.

Do this today

Pick one page you copy data from by hand. Run the curl check on it. If the text is in the HTML, use the table above. If it is not, find the JSON behind it and adapt the script.

Resources

Tell me where I am wrong

Your email is not published and I do not add it to any list. Corrections with a source are the ones I act on fastest.