Google Sheets Formulas

Pull Live Data Into Google Sheets With The IMPORT Functions

Bring another spreadsheet, a web list, an XPath match, an RSS feed or a CSV into a cell and keep it current, without a line of code. Every example reads this site, so nothing here breaks when somebody else redesigns theirs, and the index that makes IMPORTHTML unpredictable is walked in full.

August 14, 2026

The IMPORT functions bring data from somewhere else into a cell and keep it current. One reads another spreadsheet, the rest read the open web, and none of them needs a line of code or a download.

There are five worth knowing. IMPORTRANGE pulls a range from another Google Sheet, while IMPORTHTML, IMPORTXML, IMPORTFEED and IMPORTDATA pull a table or list, an XPath match, an RSS feed and a CSV from a URL.

Every example below points the IMPORT functions at a page on this site. That is deliberate: an article whose examples read somebody else’s page stops working the day they redesign it, and the formulas here should still run in a year.

This is the no-code counterpart to a job this site already covers with a script. Import An Excel File Into Google Sheets Using Google Sheets API PHP Client pushes a file up through the API. The IMPORT functions pull instead, which is less work right up to the point where they stop, and knowing where that point is decides which half you need.

One of those limits is a hard stop rather than a caveat, and nothing in the error message tells you so. It has its own section below, because it is the single most useful thing on this page.

The IMPORT functions reading this site into Google Sheets: the formula bar shows IMPORTHTML with list index 5 against the install article, and the shaded result block lists the four file formats xlsx, csv, json and html

Requirements for the IMPORT functions:

Step 1.

First, pull a range out of another spreadsheet. IMPORTRANGE takes the source spreadsheet’s id and a range written the usual way.

Sheet1!F1
=IMPORTRANGE("1FCmO9_AGo69opmqKV6lb8eIFVfWV8mbfZW62wJwOwzY", "Sheet1!A1:B3")

The id is the long string in the source sheet’s URL, between /d/ and /edit. You can paste the whole URL instead and it still works, although the id alone is shorter and survives a URL format change.

If the source sheet is private, the first attempt returns an error carrying an Allow access button. Click it once and the connection is remembered. A sheet that anyone with the link can already read needs no such step, which is worth knowing because it means the prompt everybody warns about does not always appear.

Step 2.

Next, read a list off a web page. IMPORTHTML takes a URL, the word table or list, and an index.

Sheet1!A1
=IMPORTHTML("https://spreadsheet-coding.com/phpspreadsheet/how-to-install-phpspreadsheet", "list", 5)

That returns the four file formats listed part-way down the article. Note the index, because it is the awkward part of this function and it deserves more suspicion than it usually gets.

Step 3.

Then find out what the other indexes are, since guessing wastes more time than checking. Run the same formula with 1, 2, 3 and 4 and the page gives up its structure.

Sheet1!A46, A91, A136 and A181
=IMPORTHTML("https://spreadsheet-coding.com/phpspreadsheet/how-to-install-phpspreadsheet", "list", 1)
=IMPORTHTML("https://spreadsheet-coding.com/phpspreadsheet/how-to-install-phpspreadsheet", "list", 2)
=IMPORTHTML("https://spreadsheet-coding.com/phpspreadsheet/how-to-install-phpspreadsheet", "list", 3)
=IMPORTHTML("https://spreadsheet-coding.com/phpspreadsheet/how-to-install-phpspreadsheet", "list", 4)

Index 1 is the site’s navigation menu. Indexes 2 and 3 are the sub-menus nested inside it. Only index 4 is content, and it holds the article’s Requirements. So the first three lists on the page are furniture that no reader would call a list at all.

Therefore the index counts every <ul> and <ol> in the page source, in document order, and a navigation menu almost always comes first. Consequently the number you want is rarely 1, and you cannot work it out by looking at the page.

Ask for a table on a page that has none and the answer is different again.

Sheet1!A226
=IMPORTHTML("https://spreadsheet-coding.com/phpspreadsheet/how-to-install-phpspreadsheet", "table", 1)

That returns #N/A with the message Imported content is empty. It is a useful distinction: an empty result means the page has no table, whereas a #REF! means something else entirely, as the section below explains.

Step 4.

Now reach a single element rather than a whole list. IMPORTXML takes a URL and an XPath expression.

Sheet1!A271
=IMPORTXML("https://spreadsheet-coding.com/phpspreadsheet/how-to-install-phpspreadsheet", "//h2")

This returns every second-level heading on the page, which is a quick way to pull an outline. Swap the expression for //title and you get the page title on its own.

XPath is the reason to prefer this over IMPORTHTML when the thing you want is not a list or a table. It addresses elements directly, so it does not depend on counting.

Step 5.

Then read a feed. IMPORTFEED takes the feed URL, what to pull out, whether to include headers, and how many items.

Sheet1!A361
=IMPORTFEED("https://spreadsheet-coding.com/feed/", "items title", FALSE, 5)

Five most recent article titles, refreshed by Google rather than by you. This is the tidiest of the five, because an RSS feed is a stable contract in a way that a page’s markup is not.

Step 6.

Then read a CSV. IMPORTDATA takes a URL and returns the whole file as a grid, which makes it the most useful of the five when an organisation publishes numbers rather than pages.

Sheet1!H1
=IMPORTDATA("https://spreadsheet-coding.com/sample-sales.csv")

That file exists so this example keeps working, and it holds the same eight rows the rest of this cluster uses. Commas separate the columns and the first line is a header, which is all the structure the function needs.

One detail is worth knowing because it looks like it should matter and does not. This site serves the file as application/octet-stream, since the web server has no MIME type registered for .csv. IMPORTDATA reads it anyway, so a source that downloads rather than displays in your browser is still a perfectly good target for the IMPORT functions.

It composes with QUERY as well, and here the column names have to be Col1 style, because a CSV arriving over HTTP is not a range on any sheet.

Sheet1!H45
=QUERY(IMPORTDATA("https://spreadsheet-coding.com/sample-sales.csv"), "select Col1, Col2 where Col2 > 100", 1)

Step 7.

Finally, combine an import with a query, which is where this stops being a copy and starts being a pipeline.

Sheet1!F25
=QUERY(IMPORTRANGE("1FCmO9_AGo69opmqKV6lb8eIFVfWV8mbfZW62wJwOwzY", "Sheet1!A1:D6"), "select Col1, Col2", 1)

The import runs first and QUERY reads its output, so the remote sheet is filtered before anything lands. Consequently you can pull one column out of a wide source without importing the rest of it.

Column naming here is worth a moment, because it is not what most people expect. Both styles work over an import, and they count differently. Import Sheet1!B1:D6 and the block keeps its original letters, so select B returns the first column you imported, while Col1 counts from the start of the import and refers to that same column. Ask for select A and you get NO_COLUMN: A, since column A was never imported. See the QUERY function article for the case where letters genuinely stop working.

The one-time click the IMPORT functions need.

Here is the hard stop. A web-fetching import written into a sheet by anything other than a person at a browser returns a bare #REF!, and the cell says nothing useful.

The real reason is only visible if you hover the cell, or read the error object through the API rather than the cell’s displayed value:

the message behind the #REF!
Please use a desktop web browser to allow access
to fetch data from external urls.

So Google requires a human to approve external fetching, once, in a desktop browser. Open the sheet, click the cell showing #REF!, and press Allow access.

Two details make this bearable. The approval covers the whole spreadsheet rather than one formula, and it holds afterwards: formulas written later by a script fetch normally, so only the first one ever needs a person. Meanwhile IMPORTRANGE is unaffected, because it reads another Google Sheet rather than the open web.

Above all, note that no amount of API access substitutes for that click. A service account can create the sheet, write the formula and read the result, and still cannot grant this. That is the moment to stop and fetch the data with a script instead.

Where the IMPORT functions stop.

Four more limits are worth knowing before you build on them.

They land as a block, and the block needs room. If anything sits in the cells the result needs, you get a message rather than data:

not a failed import
Array result was not expanded because it would
overwrite data in A50.

That reads like a broken fetch and is nothing of the kind. The import worked; the result simply had nowhere to go.

The IMPORT functions refresh on Google’s schedule, not yours, so a sheet can show yesterday’s number with no sign that it is stale. They need the source to be public or shared, because there is nowhere to put an API key. Finally, they are read-only, so nothing here writes anything back.

Complete code for the IMPORT functions.

Every formula from this article. Give each one clear space below and to the right.

Sheet1
// Another spreadsheet, by id.
=IMPORTRANGE("1FCmO9_AGo69opmqKV6lb8eIFVfWV8mbfZW62wJwOwzY", "Sheet1!A1:B3")

// A list from a page on this site. Index 5 is the file-format list.
=IMPORTHTML("https://spreadsheet-coding.com/phpspreadsheet/how-to-install-phpspreadsheet", "list", 5)

// The same page's other lists: 1 is the nav, 4 is the Requirements list.
=IMPORTHTML("https://spreadsheet-coding.com/phpspreadsheet/how-to-install-phpspreadsheet", "list", 1)
=IMPORTHTML("https://spreadsheet-coding.com/phpspreadsheet/how-to-install-phpspreadsheet", "list", 4)

// No table on the page, so this reports empty rather than failing.
=IMPORTHTML("https://spreadsheet-coding.com/phpspreadsheet/how-to-install-phpspreadsheet", "table", 1)

// Elements by XPath, which needs no counting.
=IMPORTXML("https://spreadsheet-coding.com/phpspreadsheet/how-to-install-phpspreadsheet", "//h2")
=IMPORTXML("https://spreadsheet-coding.com/phpspreadsheet/how-to-install-phpspreadsheet", "//title")

// This site's own feed, five most recent titles.
=IMPORTFEED("https://spreadsheet-coding.com/feed/", "items title", FALSE, 5)

// A CSV published on this site, and the same CSV filtered on the way in.
=IMPORTDATA("https://spreadsheet-coding.com/sample-sales.csv")
=QUERY(IMPORTDATA("https://spreadsheet-coding.com/sample-sales.csv"), "select Col1, Col2 where Col2 > 100", 1)

// Filter the remote sheet before it lands.
=QUERY(IMPORTRANGE("1FCmO9_AGo69opmqKV6lb8eIFVfWV8mbfZW62wJwOwzY", "Sheet1!A1:D6"), "select Col1, Col2", 1)

Test the IMPORT functions.

Paste a formula into an empty cell and press Enter. The web-fetching ones show Loading… for a moment first.

Google Sheets
Click A1  ->  paste the formula  ->  press Enter  ->  wait for Loading...

Result of the IMPORT functions.

Index 5 returns the four file formats, which is the list the article actually wanted.

Sheet1!A1
.xlsx
.csv
.json
.html

Walking the other indexes shows why that number was not 1. Three lists come before the content, and all three are navigation.

Sheet1!A46, A91, A136 and A181
list 1  ->  Excel / PhpSpreadsheet / Snippets / Google Sheets /
            Sheets API in PHP / Converter        (the site menu)
list 2  ->  PhpSpreadsheet
            Snippets                             (a sub-menu)
list 3  ->  Sheets API in PHP                    (another sub-menu)
list 4  ->  Composer
            PHP 7.2 or newer                     (the Requirements list)

Then the table request on the same page reports an empty import rather than an error, because this site’s code samples are marked up as code and not as tables.

Sheet1!A226
=IMPORTHTML(..., "table", 1)  ->  #N/A   Imported content is empty.

Meanwhile IMPORTXML returns the headings straight out of the page, in order.

Sheet1!A271
Requirements:
Step 1.
Step 2.
Test.
Convert Excel, CSV & JSON in seconds

IMPORTDATA returns the CSV as a grid, header row included.

Sheet1!H1
Item      Qty   Price   Region
Widget    120   9.99    North
Gadget    45    24.5    South
Widget    120   9.99    North
Doohick   300   1.75    North
Gizmo     12    99      South
Gadget    80    24.5    East
Sprocket  5     3.25    North

Wrapping that in QUERY filters the file before it lands, so only the rows over 100 units arrive.

Sheet1!H45
Item      Qty
Widget    120
Widget    120
Doohick   300

Finally the feed, which needs no index and no XPath at all.

Sheet1!A361
Delete Google Sheets Rows And Clear Ranges Using Google Sheets API...
Copy A Worksheet Into Another Excel File In PHP Using PhpSpreadsheet
Append Google Sheets Rows Using Google Sheets API PHP Client
Read Google Sheets Cells Using Google Sheets API PHP Client
Authenticate With A Service Account Using Google Sheets API PHP Client

When to use the IMPORT functions.

Use them when the source is public, the freshness requirement is loose, and the destination is a sheet somebody reads by eye. That covers a surprising amount of real reporting, and it costs nothing to set up.

Prefer a feed to a page, and prefer XPath to an index, since both remove a dependency on markup that somebody else can change. Where you must count lists, count them once and write the number down next to the formula.

Switch to a script when any of that stops being true. Authentication, a refresh you control, writing anything back, or a source that changes shape all point the same way, and that is where the Google Sheets API PHP client takes over. The honest way to read this page is as a map of the boundary rather than a recommendation for one side of it.

References: