Skip to main content
Simul8or Chart Patterns
Get 12 free shares worth up to $3,600AD
Welcome backGuest Trader
MARKETSLoading…
Tutorial

Tiingo API + Stock Charts

Chart live and historical Tiingo data in an interactive candlestick chart. A small Node relay keeps your token off the browser and handles the connections Tiingo won't accept from a web page.

Data
Tiingo IEX + EOD
Live prices
WebSocket via relay
Dependencies
None
Relay
Node 22+
Try It

Live Demo

Real Tiingo data, no key needed. Switch timeframes from the chart's clock menu and drag left to load older bars. Prices stream in during market hours.

Loading...

Market data provided by Tiingo. Intraday bars are IEX prices, including extended hours.

How It Works

Why the Chart Needs a Relay

Tiingo is built for server-to-server use. A web page can't call it directly, so the kit puts a small relay between the two.

Your page

Draws the chart with tiingo-feed.js. It asks the relay for candles and listens for live prices. It never sees your Tiingo token.

The relay

relay.js holds your token, calls Tiingo's REST API for history, and keeps one Tiingo WebSocket open for every viewer.

Tiingo

Serves IEX intraday bars, end-of-day history, and a live price stream that every Tiingo plan includes.

If you try to connect from the browser, two things stop you:

Browser callWhat Tiingo does
WebSocket to wss://api.tiingo.com/iexRefuses the handshake from any web page: 403 Cross origin websockets not allowed
fetch() to the REST APIResponds without CORS headers, so the browser blocks your code from reading the response

A relay also means your token never ships to the browser, where anyone could copy it from the network tab.

Developer Guide

Set It Up in Ten Minutes

1Get a Tiingo API Token

Create a free account at tiingo.com and copy your token from the API token page. Every plan includes the IEX price stream the relay uses.

2Run the Relay

Download the kit and unzip it. It contains the relay, the chart library, tiingo-feed.js, and an example page. The relay has no dependencies, so there's nothing to install beyond Node 22 or newer.

Terminal (macOS / Linux)
cd stock-chart-tiingo-kit
TIINGO_TOKEN=your_token node relay.js
PowerShell (Windows)
cd stock-chart-tiingo-kit
$env:TIINGO_TOKEN = "your_token"
node relay.js

Open http://localhost:8787. The relay serves the example page itself, so you'll see a live AAPL chart right away.

3Add the Chart to Your Page

Include the chart library, then tiingo-feed.js, and point a TiingoFeed at your relay. The feed creates the chart, loads history for each timeframe, loads older bars as you pan left, and rolls live prices into the last candle.

index.html
<link rel="stylesheet" href="stock-chart.css">

<div id="chart" style="width: 100%; height: 560px;"></div>

<script src="indicators.js"></script>
<script src="patterns.js"></script>
<script src="stockchart.js"></script>
<script src="tiingo-feed.js"></script>
<script>
  const feed = new TiingoFeed('chart', {
    relay: 'http://localhost:8787',
    symbol: 'AAPL',
    timeframe: '5min',
    onStatus: (status) => console.log(status.state, status.text)
  });

  // Later: feed.setSymbol('MSFT'); feed.setTimeframe('1day');
</script>

Page on another origin? If your page isn't served by the relay, start the relay with ALLOWED_ORIGINS=http://localhost:3000 (comma-separate several). The relay only answers browser calls from origins on that list.

Relay Endpoints

Both endpoints work with any chart or framework, not only this library.

EndpointReturns
GET /candles?symbol=AAPL&timeframe=5min{ ok, data, error }, where data is [{ t, open, high, low, close, volume }], oldest first. Add &end=<ms> for the bars before that time.
GET /stream?symbols=AAPL,MSFTServer-Sent Events. Each message is { symbol, price, time }. A status event reports live, connecting, or error.
TimeframePer requestTiingo source
1min 5min 15min 30min 1hour3 to 90 daysIEX intraday prices, including extended hours. IEX volume is only a small slice of the market's, so volume is left out.
1day 1week 1month2 to 25 yearsEnd-of-day prices, adjusted for splits and dividends, with volume

Feed Options

OptionTypeDefaultDescription
relayString''Relay base URL. An empty string means the page's own origin.
symbolString'AAPL'Ticker to chart
timeframeString'5min'Any timeframe from the table above
chartOptionsObject{}Passed to new StockChart(): darkMode, indicators, movingAverages, and more
onStatusFunction—Called with { state, text }. State is loading, ready, live, reconnecting, or error.
loadCandlesFunctionrelayFetch history yourself. See below.
subscribeFunctionrelayBring your own live feed. See below.
feed.setSymbol('MSFT')Chart another ticker
feed.setTimeframe('1day')Reload at another timeframe
feed.chartThe StockChart instance
feed.destroy()Stop streaming and remove the chart

Use Your Own Backend

Already have a server that talks to Tiingo? Skip the relay and hand the feed two functions. The demo on this page works this way: it reads candles from simul8or's own endpoint and live prices from simul8or's existing Tiingo stream.

custom-feed.js
const feed = new TiingoFeed('chart', {
  symbol: 'AAPL',
  timeframe: '5min',

  // Return [{ t, open, high, low, close, volume }], oldest first.
  // `end` is set when the chart wants the bars before that time.
  loadCandles: async ({ symbol, timeframe, end }) => {
    const res = await fetch(`/my-api/candles?symbol=${symbol}&tf=${timeframe}&end=${end || ''}`);
    return res.json();
  },

  // Call onTick({ price, time }) for each update. Return a function that stops it.
  subscribe: (symbol, onTick, onState) => {
    const socket = new WebSocket('wss://my-server.example/prices?symbol=' + symbol);
    socket.onopen = () => onState('live');
    socket.onclose = () => onState('reconnecting');
    socket.onmessage = (e) => onTick(JSON.parse(e.data));
    return () => socket.close();
  }
});

Going Live

  • Lock it down. The relay has no login of its own. Anyone who can reach it is using your Tiingo token, so put it behind your app's authentication or a reverse proxy that checks it.
  • Serve it over HTTPS. Set HOST=0.0.0.0 and put it behind nginx, Caddy, or IIS. Disable response buffering for /stream so prices aren't held back.
  • Check your Tiingo plan. A personal token covers your own use. Showing Tiingo data to other people usually requires a redistribution license, so read Tiingo's plans before you launch.
  • Credit Tiingo. Put a "Market data provided by Tiingo" line near the chart, as this page does.
Full Example

The Example Page

This is index.html from the kit, the page the relay serves at http://localhost:8787.

index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Tiingo + Stock Charts</title>
    <link rel="stylesheet" href="stock-chart.css">
    <style>
        * { box-sizing: border-box; }
        body { margin: 0; padding: 20px; background: #0a0a0f; color: #fff; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; }
        h1 { font-size: 1.3rem; margin: 0 0 4px; }
        .sub { color: #8b8b99; margin: 0 0 16px; font-size: 0.9rem; }
        .sub a { color: #22d3ee; text-decoration: none; }
        form { display: flex; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; }
        form input { background: #16161f; border: 1px solid #333; color: #fff; padding: 8px 12px; font-size: 0.95rem; border-radius: 2px; width: 120px; text-transform: uppercase; }
        form button { background: #10b981; border: 0; color: #fff; padding: 8px 20px; font-weight: 700; border-radius: 2px; cursor: pointer; }
        #status { font-size: 0.85rem; color: #8b8b99; min-height: 1.3em; margin-bottom: 8px; }
        #status[data-state="live"] { color: #10b981; }
        #status[data-state="error"] { color: #ef4444; }
        #chart { width: 100%; height: 560px; }
        /* The chart hides tools it doesn't use with .d-none. */
        .d-none { display: none !important; }
    </style>
</head>
<body>
    <h1>Tiingo + Stock Charts</h1>
    <p class="sub">Market data provided by <a href="https://www.tiingo.com">Tiingo</a>. Chart by <a href="https://simul8or.com/Javascript-stock-chart.php">JavaScript Stock Charts</a>.</p>

    <form id="symbolForm">
        <input id="symbol" value="AAPL" aria-label="Ticker symbol" autocomplete="off">
        <button type="submit">Load</button>
    </form>
    <div id="status" role="status"></div>
    <div id="chart"></div>

    <script src="indicators.js"></script>
    <script src="patterns.js"></script>
    <script src="stockchart.js"></script>
    <script src="tiingo-feed.js"></script>
    <script>
        var statusEl = document.getElementById('status');

        var feed = new TiingoFeed('chart', {
            relay: '',               // '' = this page's origin. Use the relay's URL if the page lives elsewhere.
            symbol: 'AAPL',
            timeframe: '5min',
            chartOptions: { darkMode: true },
            onStatus: function (status) {
                var labels = { loading: 'Loading...', ready: 'Waiting for live prices', live: 'Live', reconnecting: 'Reconnecting...' };
                statusEl.textContent = status.text || labels[status.state] || '';
                statusEl.dataset.state = status.state;
            }
        });

        document.getElementById('symbolForm').addEventListener('submit', function (event) {
            event.preventDefault();
            feed.setSymbol(document.getElementById('symbol').value);
        });
    </script>
</body>
</html>
Get Started

Put live Tiingo data on a chart today

Download the kit, add your token, and run one command.