IMPORTXML not working? How to fix it, and an alternative when you can't

Updated

IMPORTXML reads the raw HTML Google's servers download, without JavaScript or your login. Find your value in View page source, in an incognito window. In normal tags: fix the XPath. In a script: extract it with REGEXEXTRACT. Missing: no built-in formula reaches it. BrowseWiz reads the page in your Chrome, after login and scripts, and fills a new Google Sheet.

Add to Chrome – it's free

Find the cause in 30 seconds

Open the page in an incognito window, so you see it signed out. Press Ctrl+U (Option+Cmd+U on a Mac) for View page source, not Inspect, and search for your value. Page source is what the server sends, which is what IMPORTXML sees Source 1. Inspect shows the page after scripts ran.

  • In the source, inside normal tags: the formula can reach it. Fix the XPath.
  • Only inside a script tag, often as JSON: IMPORTXML can return the whole script, and REGEXEXTRACT can cut your value out of it Source 2 Source 3. It breaks when the site changes its JSON, and one cell holds at most 50,000 characters Source 4, so a long script may not fit. Apps Script can parse the JSON properly, if you write code.
  • Not there at all: a script loads it later, or only signed-in visitors get it. No built-in formula will find it in the page. On a public page, open DevTools, go to Network > Fetch/XHR and reload. If a request returns your value as JSON, Apps Script can fetch that URL directly Source 4.

See the three cases on practice pages

Quotes to Scrape, a site made for scraping practice, serves the same ten quotes three ways, and the three pages look the same in your browser. Put each URL in A1 and try =IMPORTXML(A1, "//span[@class='text']").

  • Normal tags. With https://quotes.toscrape.com/ in A1, the formula returns the ten quotes.
  • Inside a script. With https://quotes.toscrape.com/js/, it returns #N/A. Page source shows why: the quotes sit as JSON in a <script>, in var data = [...], and a script draws them. =REGEXEXTRACT(IMPORTXML(A1, "//script[contains(.,'var data')]"), "\\u201c(.+?)\\u201d") returns the first quote. The JSON writes the curly quote marks as \u201c and \u201d. In the pattern, \\ matches one backslash, so it finds those codes and leaves them out. If the site changes its JSON, the formula breaks.
  • Not there at all. With https://quotes.toscrape.com/scroll, it returns #N/A, and page source has only an empty <div class="quotes">. Open DevTools, go to Network > Fetch/XHR and reload: a request to /api/quotes?page=1 returns the quotes as JSON. Apps Script can fetch that URL with UrlFetchApp.fetch and read it with JSON.parse Source 5.

Why IMPORTXML and IMPORTHTML fail

Each cause below ends with whether a change to the formula can fix it.

  • The page uses JavaScript. Import functions read the HTML the server sends and don't run scripts Source 4. The cell shows #N/A and says the imported content is empty Source 1. Google's help doesn't mention this. Fixable only when the data sits in a script on the page, as above.
  • The page needs a login. The request comes from Google's servers, without your browser session Source 4, so it sees what a signed-out visitor sees, usually a sign-in page. No formula fix.
  • The XPath doesn't match the raw HTML. This gives the same empty result Source 6, which is why the page source test comes first. XPaths copied from DevTools describe the page after the browser changed it Source 1. Browsers add a <tbody> to tables that lack one Source 7, so a copied /tbody/ path can match nothing. Fixable.
  • Could not fetch url. The URL must include the protocol, such as https:// Source 8. If it does, the site is probably refusing Google's requests, as some sites do when Sheets sends too many Source 9. No formula gets past a block.
  • Result too large, or Resource at url contents exceeded maximum size. For the first, Google's fix is an XPath that returns less Source 10. The second means the page itself is over a size limit Google doesn't publish Source 4. Look for a lighter URL with the same data, such as a JSON request from the Network tab, which Apps Script can fetch. Fixable sometimes.
  • Stuck on Loading: too many imports. When import functions create too much traffic, cells show "Loading data may take a while because of the large number of requests" Source 10. The quota is the creator's, shared across all the open spreadsheets they created, and Google's fix is to use fewer import functions Source 10. Guides often quote a 50-formula cap; Google's help gives no number. Fixable.
  • Stale numbers: the refresh is hourly. Imports check for updates every hour while the document is open. Re-entering the formula forces a refresh; reopening the file doesn't, and NOW() or RAND() can't speed it up, because import functions can't reference them Source 10. Partly fixable.

How to fix the formula

When the value is in the page source, outside any script, try these in order.

  • Test the fetch. With https://quotes.toscrape.com/ in A1, =IMPORTXML(A1, "//title") returns Quotes to Scrape. If //title fails on your page, the fetch is the problem, not your XPath.
  • Skip levels. //table[@id='prices']//tr/td[2] works with or without a <tbody>. Anchor on an id or class, not a long position path.
  • Match one class among several. //span[contains(@class,'price')] matches class="price sale", but also price-old and unit-price. For the exact class, use //span[contains(concat(' ', normalize-space(@class), ' '), ' price ')]. Use single quotes inside the XPath, because the formula wraps it in double quotes.
  • Return one value. =INDEX(IMPORTXML(A1, "//span[@class='text']"), 1) keeps only the first quote from the practice page.
  • IMPORTHTML counts from 1. =IMPORTHTML(A1, "table", 2) is the second table on the page. Tables and lists are numbered separately Source 11.

When to stop fixing the formula

If the formula works, keep it. It's free, it lives in the cell, it needs no extension, and it runs on Google's servers, so it doesn't depend on Chrome being open.

If the value isn't in the page source at all, or you sign in to see the data, no built-in formula can reach it. Switch then, or when the site blocks Google, or when you need fresh rows at a set time, not only while someone has the sheet open. For marketplace product pages on Amazon, Walmart and similar sites, one option is Amapulse, formerly ImportFromWeb: a Sheets add-on that pulls data even from JavaScript-rendered pages, with a one-month free trial that includes 200 credits Source 12.

One thing changes when you switch to BrowseWiz. It can't write into the sheet that holds your IMPORTXML formulas, or into any sheet it didn't create. It creates a new sheet in your Google Drive and keeps writing to it, on every plan. To see those rows next to your formulas, pull them in with IMPORTRANGE and click Allow access the first time Source 13.

IMPORTXML vs IMPORTHTML vs Apps Script vs BrowseWiz

Apps Script here means a script that fetches pages with UrlFetchApp. Google facts come from Google's documentation, and from Stack Overflow where Google's help is silent. Apps Script limits are for a personal Google account.

IMPORTXML vs IMPORTHTML vs Apps Script vs BrowseWiz. As of . The numbers link to the sources.
FeatureBrowseWizIMPORTXMLIMPORTHTMLApps Script
What you write Source 8 Source 11A sentenceA formula and an XPathA formula and a table or list numberJavaScript code
Where it runs Source 5Your Chrome, in the BrowseWiz Tabs groupGoogle's serversGoogle's serversGoogle's servers
Pages built with JavaScript Source 3 Source 4Yes, read as Chrome shows themNo, unless the data sits in a script on the page, with REGEXEXTRACTNoNot directly. It gets the raw HTML, but it can call the JSON URL the page loads
Pages behind your login Source 4 Source 5Yes, with your Chrome sign-inNoNoOnly if your code sends a cookie or token
Refresh Source 10 Source 14Daily on Free, up to hourly on Pro, while Chrome is openHourly, while the document is openHourly, while the document is openTime-driven triggers, as often as every minute
Usage limits Source 10 Source 15Free: 1 scheduled task, 10M credits a month. Pro: 10 tasks, 250M credits.A quota on the creator's account, no number publishedA quota on the creator's account, no number published20,000 fetches and 90 minutes of trigger runtime a day; 6 minutes per run
Where the data goesA new sheet BrowseWiz creates in your DriveAny cell in your sheetAny cell in your sheetWherever your code writes it
Price Source 10 Source 15Free, or Pro at $29/month (250M credits). Monthly billing only.Free with a Google account; usage quota unpublishedFree with a Google account; usage quota unpublishedFree with a Google account, within the quotas above

Which one to use

Keep IMPORTXML or IMPORTHTML if…

  • The value shows in page source, signed out, even if only inside a script.
  • Hourly updates while the sheet is open are enough.
  • You want it free, in the cell, with no extension.

Use Apps Script if…

  • You write JavaScript.
  • The data comes from a JSON request you can see in the Network tab.
  • Runs must happen with your computer off.
  • The page is public, or you can send its token.

Use BrowseWiz if…

  • The data appears only after scripts run or you sign in.
  • You'd rather describe columns than write XPath, regex or code.
  • Daily on Free, or hourly on Pro, while Chrome is open, is fresh enough.

Describe the data instead of writing XPath

BrowseWiz can't read the sheet that holds your formulas, so copy the URLs from the column that shows #N/A into your request:

What you type

Open each of these job postings and read the job title, the company and the date posted, as the page shows them: [paste the URLs from your IMPORTXML column]. Write them to a new sheet called Job postings, one row per URL, with the URL in a Source column, and note the date and time each was checked.

BrowseWiz shows a plan first. Approve it, grant tab access and sign in to Google once when it asks, and watch the sheet fill. Then click Update this sheet daily, or ask for weekdays at 8 AM, and approve the new plan. It becomes a scheduled task that keeps this sheet updated.

The rows it writes

The three career sites draw their job postings with JavaScript after the page loads, and their page source has no job data, not even in a script, so IMPORTXML returned #N/A. Google's job search reads postings from JobPosting structured data, which its guide puts in a <script type="application/ld+json"> tag Source 16. If your job pages carry it, try the REGEXEXTRACT route above first.

Example: Job postings from three fictional career sites
Job titleCompanyPostedSourceChecked at
Data AnalystLumenOct 6lumen.example/j/31Oct 7, 8:02 AM
Sales LeadOrbitOct 2orbit.example/j/88Oct 7, 8:03 AM
QA EngineerTallySep 29tally.example/j/54Oct 7, 8:04 AM
UX DesignerLumenSep 24lumen.example/j/27Oct 7, 8:04 AM

Where BrowseWiz is the wrong tool

  • Chrome has to be open. Schedules run only while Chrome is running. IMPORTXML and Apps Script don't need it.
  • Sign-ins expire. If a site signs you out, a scheduled run lands on the sign-in page until you sign in again in Chrome. You can ask BrowseWiz to write 'Signed out' in the row when that happens, so an old value doesn't pass for a fresh one.
  • Not for volume. For thousands of URLs, proxies or captchas, use a hosted scraping service.
  • Runs can differ. An AI agent reads the page each time, so values or rows can vary between runs. Ask for a source link per row, so you can check each value.
  • Hourly is the fastest schedule, on Pro ($29/month) or Max. Free runs one task up to once a day.
  • Site terms are yours. You're responsible for following each site's terms when you collect its data.

What BrowseWiz costs

Start on Free: it includes one daily scheduled task, one monitor and 10M credits a month. IMPORTXML is free; a BrowseWiz page read costs credits. On the pricing page's example, a 30,000-character page is about 7,500 input tokens and the reply about 500 output tokens, so one read costs 7,500 × 5 + 500 × 30 ≈ 52,500 credits. Each step of a run re-sends the chat, so credit use depends on how much page text each run reads.

  • Free

    $0 / month

    • 1 scheduled task, up to once a day
    • 1 page monitor
    • 10M credits a month
  • Pro

    $29 / month

    • Up to 10 scheduled tasks, as often as hourly
    • Up to 30 page monitors
    • 250M credits a month
  • Max

    $79 / month

    • Up to 10 scheduled tasks, as often as hourly
    • Up to 30 page monitors
    • 1B credits a month

Prices exclude VAT. See how credits are counted.

Questions

When the formula can't see the page, describe it

Add BrowseWiz to Chrome, paste your URLs and say which fields you want. Free includes one scheduled task.

Add to Chrome – it's free

Sources

  1. Stack Overflow: Google's IMPORTXML returns "Imported content is empty" error (opens in a new tab)stackoverflow.com, checked
  2. Stack Overflow: Text inside <div> does not appear in Google Sheets using IMPORTXML (opens in a new tab)stackoverflow.com, checked
  3. Stack Overflow: How can I get the value of a <script> tag in Google Sheets? (opens in a new tab)stackoverflow.com, checked
  4. Stack Overflow: Scraping data to Google Sheets from a website that uses JavaScript (opens in a new tab)stackoverflow.com, checked
  5. Google Apps Script reference: Class UrlFetchApp (opens in a new tab)developers.google.com, checked
  6. Stack Overflow: ImportXML return empty (opens in a new tab)stackoverflow.com, checked
  7. MDN Web Docs: <tbody>, the Table Body element (opens in a new tab)developer.mozilla.org, checked
  8. Google Docs Editors Help: IMPORTXML (opens in a new tab)support.google.com, checked
  9. Stack Overflow: IMPORTHTML and IMPORTXML "Could not fetch URL", only on a specific webpage (opens in a new tab)stackoverflow.com, checked
  10. Google Docs Editors Help: Learn more about Import functions (opens in a new tab)support.google.com, checked
  11. Google Docs Editors Help: IMPORTHTML (opens in a new tab)support.google.com, checked
  12. Google Workspace Marketplace: Amapulse, formerly ImportFromWeb (opens in a new tab)workspace.google.com, checked
  13. Google Docs Editors Help: IMPORTRANGE (opens in a new tab)support.google.com, checked
  14. Google Apps Script: Installable triggers (opens in a new tab)developers.google.com, checked
  15. Google Apps Script: Quotas for Google Services (opens in a new tab)developers.google.com, checked
  16. Google Search Central: Job posting (JobPosting) structured data (opens in a new tab)developers.google.com, checked
  17. Chrome Web Store: Instant Data Scraper (opens in a new tab)chromewebstore.google.com, checked