Get started
Integrations

Stock prices in Google Sheets,
one formula away.

Add format=csv to any OHLC data endpoint and Google Sheets can load it with IMPORTDATA. For shared sheets, a ten-line Apps Script function keeps your API key out of the formulas.

IMPORTDATA ready

CSV with a header row fills the sheet from the formula's cell, one row per record.

Key in the URL

Sheets cannot send headers, so GET requests accept the key as the api_key query parameter.

Private key option

An Apps Script custom function reads the key from script properties, hidden from viewers.

Exact decimals

Prices arrive unrounded, nulls are empty cells, and formula-like text is escaped.

Daily prices with IMPORTDATA

  1. Create an API key, ideally one used only for this spreadsheet.
  2. In an empty cell, enter an IMPORTDATA formula with format=csv and api_key in the URL.
  3. The header row and data fill the cells to the right and below. Leave that range empty.
One year of daily barsText
=IMPORTDATA("https://api.ohlc.io/v1/eod?symbols=XNAS:AAPL&from=2026-01-01&limit=500&format=csv&api_key=YOUR_API_KEY")

To show just the latest close, look the column up by name so the formula keeps working if columns are added:

Latest end-of-day closeText
=LET(t, IMPORTDATA("https://api.ohlc.io/v1/eod?symbols=XNAS:AAPL&order=desc&limit=1&format=csv&api_key=YOUR_API_KEY"), INDEX(t, 2, MATCH("close", INDEX(t, 1, 0), 0)))

Keep the key private in a shared sheet

Anyone who can view a sheet can read its formulas, including a key inside an IMPORTDATA URL. For a shared sheet, keep the key in Apps Script instead: open Extensions → Apps Script, save the key under Project Settings → Script properties as OHLC_API_KEY, and add this function. Viewers cannot see script properties; editors can.

Apps Script custom functionJavaScript
function OHLC(path) {
  const key = PropertiesService.getScriptProperties().getProperty("OHLC_API_KEY");
  const url = "https://api.ohlc.io" + path + (path.includes("?") ? "&" : "?") + "format=csv";
  const response = UrlFetchApp.fetch(url, { headers: { Authorization: "Bearer " + key } });
  return Utilities.parseCsv(response.getContentText())
    .map((row) => row.map((v) => (v !== "" && !isNaN(v) ? Number(v) : v)));
}
Use it like any formulaText
=OHLC("/v1/eod?symbols=XNAS:AAPL&from=2026-01-01&limit=500")

Useful URLs for a stock spreadsheet

Any GET data endpoint works the same way. These cover most portfolio and research sheets; append &format=csv&api_key=YOUR_API_KEY to each, or pass the path to the OHLC function above.

Quotes are delayed at least 15 minutes; daily bars are end-of-day values.
What you wantPathCredits
Delayed latest price for a watchlist/v1/quotes?symbols=XNAS:AAPL,XNAS:MSFT,XNYS:JNJ5 per symbol
Price and change from the previous close/v1/snapshot?symbols=XNAS:AAPL,XNYS:JNJ5 per symbol
Split-adjusted daily history/v1/eod?symbols=XNAS:NVDA&from=2024-01-02&adjustment=split&limit=5005 per symbol
Dividend history/v1/dividends?symbols=XNYS:JNJ&from=2021-01-015 per symbol
Ratios, market cap and dividend yield/v1/financials/metrics?symbols=XNAS:AAPL50 per symbol

The Free plan covers AAPL, NVDA, JNJ, PEP, MSFT, SPY and QQQ, which is enough to build and test a sheet. Developer and above cover all U.S.-listed stocks and ETFs, and Pro and above add Canada, the UK, France, the Netherlands and Australia. List-valued fields, such as the legs of a dividend, arrive as JSON text in a single cell.

What to know before you build a dashboard

  • Google fetches the URL from its own servers, not your network, so a key restricted by an IP allowlist is refused. Use a key without one, scoped to the datasets the sheet needs.
  • Sheets re-fetches imports on its own schedule. Every fetch is a request that counts toward your plan's credits and rate limit: daily bars cost 5 credits per symbol.
  • A CSV response holds one page of up to 500 rows. Split long histories into several formulas by from and to; the Apps Script route can also read the X-Next-Cursor header to page.
  • Daily bars are end-of-day values. For a delayed intraday price use /v1/quotes and its last_price column, at least 15 minutes old.
  • Keep imports on one data tab and point charts, pivot tables and calculations at that range. One import per dataset is easier to audit and spends far fewer credits than an import in every cell.
  • Timestamps such as last_at are UTC. Daily bars carry the exchange-local trading date in date, so they line up with the dates on a stock chart.

If a sheet or URL containing a key is shared by mistake, revoke the key in the portal and create a new one. A separate key per spreadsheet keeps the damage to one sheet.

Questions, answered.

How do I get stock prices into Google Sheets?

Use IMPORTDATA with an OHLC API URL that includes format=csv and your api_key. The CSV rows fill the sheet from the formula's cell.

Is it safe to put an API key in a Google Sheets formula?

Only in a sheet nobody else can view. Anyone with view access can read formulas. For shared sheets, store the key in Apps Script properties and call a custom function.

Why does my IP-restricted key fail in Google Sheets?

IMPORTDATA and Apps Script requests come from Google's servers, not your network, so an IP allowlist rejects them.

Is this the same as the GOOGLEFINANCE function?

No. GOOGLEFINANCE is Google's own feed. IMPORTDATA with OHLC gives you documented bars, adjustments and fundamentals from an API you can also call from code.

How often does IMPORTDATA refresh?

Google decides when imports re-fetch. Each fetch spends credits, so avoid spreading the same import across many cells; import once and reference that range.

A little JSON.
A lot of possibility.

Explore the API