Live stock data in Google Sheets and Excel
Every figure on stockrow can be a live cell in your own spreadsheet: ten years of statements, any metric’s history, a grid of your companies, your watchlist and your saved screens. The recipes below are copy-and-paste; they refresh on their own, and they keep working as long as your Powerpack does.
First, your key
Make a key on your account’s API page and paste it into one cell of your
sheet — a sheet called Settings, cell B1. Every formula below reads it from there, so
changing the key is one edit.
Before you share a spreadsheet, make a copy (File → Make a copy) and delete the key from the copy. Anyone with the key can read your data feed — never your account — until you roll it on the API page.
Google Sheets
IMPORTDATA reads a CSV address into the cells below and to the right of the formula.
A company’s ten-year income statement
With the ticker in A1:
=IMPORTDATA("https://stockrow.com/api/v1/companies/"&A1&"/statements/income-statement.csv?period=annual&key="&Settings!B1)
Use balance-sheet, cash-flow or metrics-ratios for the others, and
period=quarterly or period=ttm for quarters and trailing twelve months.
One metric’s history
=IMPORTDATA("https://stockrow.com/api/v1/companies/AAPL/metrics/pe-ratio.csv?key="&Settings!B1)
A grid of your companies
With tickers in A2:A50, one request for the whole grid — which is kinder to Google’s limits than a
formula per cell:
=IMPORTDATA("https://stockrow.com/api/v1/metrics/latest.csv?tickers="&TEXTJOIN(",",TRUE,A2:A50)&"&metrics=price,market-cap,pe-ratio,dividend-yield&key="&Settings!B1)
The metric names are slugs; /api/v1/indicators lists them all, and any indicator’s lower-cased code works too. A ticker stockrow does not cover gets an empty row, so one delisted company does not break the sheet.
Your stockrow watchlist
=IMPORTDATA("https://stockrow.com/api/v1/watchlist.csv?key="&Settings!B1)
A saved screen
The screen’s address is on https://stockrow.com/api/v1/screens.csv — one row per saved screen, with its
results_url:
=IMPORTDATA("https://stockrow.com/api/v1/screens/<id>/results.csv?key="&Settings!B1)
One cell: the latest revenue
Look a line up by its code, never by its row number — rows can be added between others:
=INDEX(IMPORTDATA(Settings!B2), MATCH("REVENUE", INDEX(IMPORTDATA(Settings!B2),,1), 0), 4)
where Settings!B2 holds the statement’s address from the first recipe. Column 4 is always the newest period.
What Google does
Google refreshes IMPORTDATA about once an hour while the spreadsheet is open, fetches from its own
servers (which is why the key is in the address rather than a header), caps how many imports one spreadsheet
may hold and how large each may be, and asks you to allow access the first time. The exact limits are
Google’s and change; we are checking them against Google’s current help and will state them here.
Excel
Power Query is the way: Data → Get Data → From Web, paste a CSV address from above with your key, and Load. Then in Query Properties, tick “Refresh every 60 minutes” and “Refresh data when opening the file”.
To keep the key and the ticker in cells, name two cells ApiKey and Ticker and use this
query (Home → Advanced Editor):
let key = Excel.CurrentWorkbook(){[Name="ApiKey"]}[Content]{0}[Column1],
t = Excel.CurrentWorkbook(){[Name="Ticker"]}[Content]{0}[Column1],
src = Csv.Document(Web.Contents("https://stockrow.com/api/v1/companies/" & t &
"/statements/income-statement.csv", [Query=[period="annual", key=key]]),
[Delimiter=",", Encoding=65001])
in Table.PromoteHeaders(src)
Power Query’s From Web is in Excel for Windows and Microsoft 365; we are checking Excel for Mac and Excel on the web and will say here what works.
WEBSERVICE and FILTERXML are not supported: they work only in Excel for Windows, cut an
answer at 32,767 characters and cannot read CSV. Use Power Query.
The layout contract
The statement CSV and the Excel export (“layout 2”) are laid out the same way, and will stay so, so a model built on them does not break:
- Column A is the line’s code, B its label, C its unit, and D onwards a period each — D is always the latest period.
- Row 1 is the header:
code,label,unitand the period end dates. - Numbers are numbers: cash in raw dollars, percentages as fractions; a missing value is an empty cell.
-
A row is identified by its code. Codes are never renamed or reordered against each other, but new lines can
appear between them — so look lines up by code:
=INDEX(IS_A!$D:$D, MATCH("REVENUE", IS_A!$A:$A, 0)). -
The workbook’s sheets are always
Info,IS_A,IS_Q,IS_T,BS_A,BS_Q,CF_A,CF_Q,CF_T,MR_A,MR_QandMR_T, in that order, with the panes frozen at D2.Infosays the layout version,2.
Any change to this is a new layout version, asked for by a new parameter; layout 2 does not change.
Templates
Two ready-made workbooks: a ten-year model of one company — the statements, margins, growth, free cash flow and
its valuation against its own history — and a dashboard of up to fifty companies. Put your key in
Settings!B1 and they fill themselves in.
- Ten-year model — Make a copy in Google Sheets · Excel (.xlsx). One company’s statements, margins, growth, free cash flow and returns, and its P/E, EV/EBITDA and P/S against its own ten-year range. Change the ticker in Settings!B2.
- Watchlist dashboard — Make a copy in Google Sheets · Excel (.xlsx). Up to fifty companies side by side, sorted by size, each valuation set against the list’s median.