apiwren
Example Google Sheets

Google Sheets stock price formulas, without GOOGLEFINANCE

Live stock quotes and the closing price on any date in Google Sheets, using a short Apps Script and the Yahoo Finance Turbo API. No add-on to install.

By Terrell Louis · Updated

Short answer

GOOGLEFINANCE is free but can lag by up to 20 minutes and misses many tickers. To get Yahoo Finance prices without an add-on, paste the Apps Script below. It adds =STOCKPRICE("AAPL"), =STOCKQUOTES(A2:A20) and =STOCKCLOSE("AAPL", DATE(2026,1,2)), which call the Yahoo Finance Turbo API with your RapidAPI key.

When GOOGLEFINANCE is enough

CriterionGOOGLEFINANCEApps Script + Turbo
SetupNonePaste a script, add a key
CostFreeFree plan of 500 requests a month; paid from $9.95
Quote delayUp to 20 minutesThe latest price Yahoo publishes for the exchange
TickersGoogle’s coverageYahoo symbols: VOD.L, 7203.T, BTC-USD, ^GSPC
Close on a dateA 2×2 tableOne number

If GOOGLEFINANCE covers your tickers and a delay is fine, keep it.

Set it up

  1. Subscribe to Yahoo Finance Turbo on RapidAPI. The free plan works. Copy X-RapidAPI-Key from any code example on the listing.
  2. In your sheet, open Extensions → Apps Script, replace the code with the script below and save.
  3. Open Project Settings → Script properties and add RAPIDAPI_KEY with your key as the value. The key stays out of the cells, so people you share the sheet with can’t read it.
const HOST = 'yahoo-finance-turbo.p.rapidapi.com';

function turbo_(path, params) {
  const key = PropertiesService.getScriptProperties().getProperty('RAPIDAPI_KEY');
  if (!key) throw new Error('Add RAPIDAPI_KEY under Project Settings > Script properties');
  const qs = Object.keys(params).map((k) => k + '=' + encodeURIComponent(params[k])).join('&');
  const url = 'https://' + HOST + path + '?' + qs;
  const cache = CacheService.getScriptCache();
  const hit = cache.get(url);
  if (hit) return JSON.parse(hit);
  const res = UrlFetchApp.fetch(url, {
    headers: { 'X-RapidAPI-Key': key, 'X-RapidAPI-Host': HOST },
    muteHttpExceptions: true,
  });
  if (res.getResponseCode() !== 200) throw new Error('HTTP ' + res.getResponseCode() + ': ' + res.getContentText().slice(0, 150));
  try { cache.put(url, res.getContentText(), 300); } catch (e) {} // 5 min; values over 100 KB are not cached
  return JSON.parse(res.getContentText());
}

/**
 * Last price for one ticker.
 * @param {string} symbol Yahoo symbol, e.g. "AAPL" or "VOD.L"
 * @customfunction
 */
function STOCKPRICE(symbol) {
  const q = turbo_('/market/v2/get-quotes', { region: 'US', symbols: String(symbol).trim().toUpperCase() }).quoteResponse.result[0];
  if (!q) throw new Error('Unknown symbol ' + symbol);
  return q.regularMarketPrice;
}

/**
 * Price, change % and volume for up to 20 tickers in one request.
 * @param {A2:A20} symbols A column of Yahoo symbols
 * @customfunction
 */
function STOCKQUOTES(symbols) {
  const list = [].concat(symbols).flat().map((s) => String(s).trim().toUpperCase()).filter(Boolean);
  if (list.length > 20) throw new Error('Max 20 symbols per call');
  const rows = turbo_('/market/v2/get-quotes', { region: 'US', symbols: list.join(',') }).quoteResponse.result;
  const by = Object.fromEntries(rows.map((q) => [q.symbol, q]));
  return list.map((s) => (by[s] ? [by[s].regularMarketPrice, by[s].regularMarketChangePercent / 100, by[s].regularMarketVolume] : ['', '', '']));
}

/**
 * Closing price on a date (the last trading day on or before it).
 * @param {string} symbol Yahoo symbol
 * @param {date} date A date cell or DATE(2026,1,2)
 * @customfunction
 */
function STOCKCLOSE(symbol, date) {
  const tz = SpreadsheetApp.getActive().getSpreadsheetTimeZone();
  const want = Utilities.formatDate(new Date(date), tz, 'yyyy-MM-dd');
  const days = (Date.now() - new Date(date)) / 864e5;
  const range = days < 25 ? '1mo' : days < 175 ? '6mo' : days < 360 ? '1y' : days < 1820 ? '5y' : 'max';
  const r = turbo_('/stock/v3/get-chart', { symbol: String(symbol).trim().toUpperCase(), interval: '1d', range: range, region: 'US' }).chart.result[0];
  const ex = r.meta.exchangeTimezoneName;
  const close = r.indicators.quote[0].close;
  let best = '';
  r.timestamp.forEach((t, i) => {
    if (close[i] != null && Utilities.formatDate(new Date(t * 1000), ex, 'yyyy-MM-dd') <= want) best = close[i];
  });
  return best;
}

Use it

FormulaReturns
=STOCKPRICE("AAPL")Last price
=STOCKQUOTES(A4:A13)Price, change % and volume across three columns. Format the middle one as a percent.
=STOCKCLOSE("MSFT", DATE(2026,1,2))Close on 2 January 2026, or the last trading day before it

Stay inside the free plan

  • Use STOCKQUOTES for a watchlist. It fetches 20 tickers in one request. Twenty STOCKPRICE cells cost 20 requests.
  • Answers are cached for 5 minutes, so a recalculation inside that window costs nothing.
  • Refresh on demand. Sheets reruns custom functions only when an argument changes, and won’t accept NOW() as one. Add a checkbox, e.g. =STOCKQUOTES(A4:A13, Z1), and tick it to refresh.
  • A 30-ticker watchlist refreshed 5 times a trading day uses about 2 × 5 × 21 = 210 requests a month.

Yahoo Finance Turbo

Quotes, history, fundamentals and options. Free plan of 500 requests a month.

Get a free key on RapidAPI

FAQ

Is GOOGLEFINANCE real-time?
No. Google says quotes can be delayed up to 20 minutes, and some exchanges are not covered.
Can I use IMPORTXML on Yahoo Finance instead?
It breaks whenever Yahoo changes its page markup, and Yahoo often blocks Google’s fetchers. An API returns the same JSON fields every time.
Does this work for crypto, indices and non-US stocks?
Yes, with Yahoo’s symbol format: BTC-USD, ^GSPC, VOD.L, 7203.T.
Why don’t my prices update on their own?
Google Sheets does not rerun custom functions on a timer, only when an argument changes. Add a checkbox cell as an extra argument and tick it to refresh.
Is Yahoo Finance Turbo made by Yahoo?
No. It is a third-party API, not affiliated with or endorsed by Yahoo.