S&P 500
7,764.25
+14.75 (+0.19%)
Nasdaq
29,508.00
-107.00 (-0.36%)
Dow
54,654.00
+160.00 (+0.29%)
Bitcoin
64,786.20
+679.45 (+1.06%)
simul8or trading simulator logo

Alpha Vantage API +
Stock Charts

Fetch real-time and historical stock data from Alpha Vantage and render interactive candlestick charts in the browser. 100% client-side, zero backend required.

Try It Live

Interactive Demo

Enter your Alpha Vantage API key and a ticker symbol to fetch real market data. Use the chart's built-in timeframe selector to switch between intraday, daily, weekly, and monthly views — new data is automatically fetched from Alpha Vantage when you change timeframes.

Chart loaded with sample AAPL daily data. Enter your API key above to fetch live data from Alpha Vantage. Use the chart's built-in timeframe selector to switch views.
Free tier: 25 API calls per day. Alpha Vantage's free tier is very limited. Each timeframe switch or chart load uses one API call, so use them wisely. Sign up at alphavantage.co.
Step by Step

Implementation Guide

Everything you need to get Alpha Vantage data into a chart

01 Get Your Alpha Vantage API Key

Head to alphavantage.co/support/#api-key and claim your free API key. No account creation needed — just enter your name and email. The free tier gives you 25 API calls per day, which is quite limited. Premium plans are available for higher limits.

Rate limit: The free tier is capped at 25 requests per day. Plan your API calls carefully — each timeframe switch, ticker change, or infinite scroll fetch counts as one call.
02 Include the Chart Library

Add the JavaScript Stock Charts library to your HTML page via CDN. It's zero-dependency — just three script tags and one CSS link. No downloads or installs required.

HTML
<!-- CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/day-trading-simulator/javascript-stock-charts@main/stock-chart.css">

<!-- Chart container -->
<div id="chart" style="width: 100%; height: 500px;"></div>

<!-- JS (order matters) -->
<script src="https://cdn.jsdelivr.net/gh/day-trading-simulator/javascript-stock-charts@main/indicators.js"></script>
<script src="https://cdn.jsdelivr.net/gh/day-trading-simulator/javascript-stock-charts@main/patterns.js"></script>
<script src="https://cdn.jsdelivr.net/gh/day-trading-simulator/javascript-stock-charts@main/stock-chart.js"></script>
No downloads needed — the library is served via jsDelivr CDN directly from GitHub. Just include the script tags and you're ready to go.
03 Fetch Data from Alpha Vantage

Alpha Vantage uses different function parameters for different timeframes: TIME_SERIES_INTRADAY for 1min–60min, TIME_SERIES_DAILY for daily, TIME_SERIES_WEEKLY for weekly, and TIME_SERIES_MONTHLY for monthly. This works directly in the browser — Alpha Vantage supports CORS on their REST API. The API key is passed as a query parameter.

JavaScript
const API_KEY = 'YOUR_ALPHA_VANTAGE_API_KEY';
const ticker  = 'AAPL';

// Daily data
const url = `https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=${ticker}&outputsize=compact&apikey=${API_KEY}`;

// Intraday data (5min with extended hours)
// const url = `https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=${ticker}&interval=5min&outputsize=compact&extended_hours=true&apikey=${API_KEY}`;

const response = await fetch(url);
const json = await response.json();

Alpha Vantage returns data as an object keyed by datetime strings (not an array). The time series key name changes depending on the endpoint and interval. Field names have numbered prefixes like "1. open":

Alpha Vantage Response (Daily)
{
  "Meta Data": {
    "1. Information": "Daily Prices (open, high, low, close) and Volumes",
    "2. Symbol": "AAPL",
    "3. Last Refreshed": "2026-03-11",
    "4. Output Size": "Compact",
    "5. Time Zone": "US/Eastern"
  },
  "Time Series (Daily)": {
    "2026-03-11": {
      "1. open": "260.14",
      "2. high": "262.48",
      "3. low": "258.90",
      "4. close": "261.35",
      "5. volume": "45123456"
    },
    "2026-03-10": { ... }
  }
}
Alpha Vantage Field Description Chart Field
"1. open"Open price (string)open
"2. high"High price (string)high
"3. low"Low price (string)low
"4. close"Close price (string)close
"5. volume"Volume (string)volume
Watch out for these quirks: All values are strings (need parseFloat/parseInt). Data is an object keyed by datetime, not an array. The response key name changes per endpoint: "Time Series (Daily)", "Time Series (5min)", "Weekly Time Series", etc. Data comes in reverse chronological order (newest first).
04 Transform the API Response

Convert Alpha Vantage's datetime-keyed object into a sorted array of objects that the chart library expects. Use Object.keys().sort() to handle the reverse chronological order and parseFloat() to convert string values to numbers. The datetime strings from Alpha Vantage are already in US/Eastern timezone, so we use them directly as the date property:

JavaScript
function transformAlphaVantageData(json, seriesKey) {
    var series = json[seriesKey];
    if (!series) return [];
    return Object.keys(series).sort().map(function(datetime) {
        var bar = series[datetime];
        return {
            t: new Date(datetime).getTime(),
            date: datetime,
            open: parseFloat(bar['1. open']),
            high: parseFloat(bar['2. high']),
            low: parseFloat(bar['3. low']),
            close: parseFloat(bar['4. close']),
            volume: parseInt(bar['5. volume'])
        };
    });
}

const chartData = transformAlphaVantageData(json, 'Time Series (Daily)');
Alpha Vantage returns data with newest entries first. Object.keys().sort() sorts the datetime keys alphabetically, which gives chronological order since they use YYYY-MM-DD format. The date property uses the raw Alpha Vantage datetime string directly — it's already in US/Eastern timezone.
05 Render the Chart with Timeframe Switching & Infinite Scroll

Create a StockChart instance with an onReachingStart callback for infinite scroll. Then monitor the chart's built-in timeframe selector to re-fetch data when the user switches timeframes. Alpha Vantage uses different function parameters for each timeframe:

JavaScript
var chart = null;
var previousTimeframe = '1day';
var isLoadingMore = false;
var earliestTimestamp = null;
var hasMoreHistory = true;
var timeframeCheckInterval = null;

// Map chart timeframes to Alpha Vantage function + params
function mapTimeframeToAlphaVantageParams(tf) {
    var map = {
        '1min':   { fn: 'TIME_SERIES_INTRADAY', interval: '1min',  outputsize: 'compact', seriesKey: 'Time Series (1min)' },
        '2min':   { fn: 'TIME_SERIES_INTRADAY', interval: '5min',  outputsize: 'compact', seriesKey: 'Time Series (5min)' },
        '5min':   { fn: 'TIME_SERIES_INTRADAY', interval: '5min',  outputsize: 'compact', seriesKey: 'Time Series (5min)' },
        '15min':  { fn: 'TIME_SERIES_INTRADAY', interval: '15min', outputsize: 'compact', seriesKey: 'Time Series (15min)' },
        '30min':  { fn: 'TIME_SERIES_INTRADAY', interval: '30min', outputsize: 'compact', seriesKey: 'Time Series (30min)' },
        '1hour':  { fn: 'TIME_SERIES_INTRADAY', interval: '60min', outputsize: 'compact', seriesKey: 'Time Series (60min)' },
        '60min':  { fn: 'TIME_SERIES_INTRADAY', interval: '60min', outputsize: 'compact', seriesKey: 'Time Series (60min)' },
        '4hour':  { fn: 'TIME_SERIES_INTRADAY', interval: '60min', outputsize: 'compact', seriesKey: 'Time Series (60min)' },
        '1day':   { fn: 'TIME_SERIES_DAILY',    interval: null,    outputsize: 'compact', seriesKey: 'Time Series (Daily)' },
        '1week':  { fn: 'TIME_SERIES_WEEKLY',   interval: null,    outputsize: null,   seriesKey: 'Weekly Time Series' },
        '1W':     { fn: 'TIME_SERIES_WEEKLY',   interval: null,    outputsize: null,   seriesKey: 'Weekly Time Series' },
        '1month': { fn: 'TIME_SERIES_MONTHLY',  interval: null,    outputsize: null,   seriesKey: 'Monthly Time Series' },
        '1M':     { fn: 'TIME_SERIES_MONTHLY',  interval: null,    outputsize: null,   seriesKey: 'Monthly Time Series' }
    };
    return map[tf] || map['1day'];
}

// Initialize chart
chart = new StockChart('chart', {
    data:      chartData,
    ticker:    ticker,
    chartType: 'candlestick',
    darkMode:  true,
    timeframe: '1day',
    useAfterHoursStyling: true,
    onReachingStart: handleReachingStart
});
earliestTimestamp = chartData[0].t;

// Monitor chart's built-in timeframe selector
setupTimeframeMonitor();

function setupTimeframeMonitor() {
    if (timeframeCheckInterval) clearInterval(timeframeCheckInterval);
    timeframeCheckInterval = setInterval(function() {
        if (chart && chart.timeframe !== previousTimeframe) {
            previousTimeframe = chart.timeframe;
            loadChart(); // re-fetch with new timeframe
        }
    }, 500);
}

// Infinite scroll - fetch older data when user pans left
async function handleReachingStart() {
    if (isLoadingMore || !hasMoreHistory || !earliestTimestamp) return;
    isLoadingMore = true;
    var p = mapTimeframeToAlphaVantageParams(chart.timeframe || '1day');

    if (p.fn !== 'TIME_SERIES_INTRADAY') {
        // Daily/weekly/monthly with full output already has all data
        hasMoreHistory = false;
        chart.setLoadingHistoricalData(false);
        isLoadingMore = false;
        return;
    }

    // For intraday, fetch previous month
    var d = new Date(earliestTimestamp);
    d.setMonth(d.getMonth() - 1);
    var month = d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0');

    var url = 'https://www.alphavantage.co/query?function=' + p.fn
        + '&symbol=' + ticker
        + '&interval=' + p.interval
        + '&month=' + month
        + '&outputsize=compact'
        + '&extended_hours=true'
        + '&apikey=' + API_KEY;

    try {
        var resp = await fetch(url);
        var json = await resp.json();
        if (json['Error Message'] || json['Note']) {
            hasMoreHistory = false;
            chart.setLoadingHistoricalData(false);
        } else {
            var older = transformAlphaVantageData(json, p.seriesKey);
            if (older.length > 0) {
                earliestTimestamp = older[0].t;
                chart.prependHistoricalData(older);
            } else {
                hasMoreHistory = false;
                chart.setLoadingHistoricalData(false);
            }
        }
    } catch(e) {
        chart.setLoadingHistoricalData(false);
    } finally {
        isLoadingMore = false;
    }
}

The chart includes a built-in timeframe dropdown — when the user clicks it, we detect the change via setInterval polling on chart.timeframe and automatically re-fetch data from Alpha Vantage. For infinite scroll, intraday data uses the month parameter to fetch previous months, while daily/weekly/monthly data with outputsize=compact already includes 20+ years of history. Technical indicators, pan, zoom, crosshair, volume, and more are all built-in.

Full Example

Complete Working Code

Copy-paste this entire HTML file. Replace YOUR_ALPHA_VANTAGE_API_KEY with your key, open it in a browser, and you'll have a working stock chart in seconds.

alphavantage-stock-chart.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Alpha Vantage + JavaScript Stock Charts</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/day-trading-simulator/javascript-stock-charts@main/stock-chart.css">
    <style>
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body {
            padding: 20px;
            background: #0a0a0f;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
            color: #fff;
        }
        h1 { font-size: 1.4rem; margin-bottom: 4px; }
        .subtitle { color: #888; margin-bottom: 16px; }
        .subtitle a { color: #22d3ee; }
        .controls {
            display: flex; gap: 10px; margin-bottom: 12px;
            flex-wrap: wrap; align-items: flex-end;
        }
        .controls label {
            display: block; font-size: 0.7rem;
            text-transform: uppercase; letter-spacing: 1px;
            color: #888; margin-bottom: 4px;
        }
        .controls input {
            background: #16161f; border: 1px solid #333;
            color: #fff; padding: 8px 12px; font-size: 0.9rem;
            border-radius: 2px;
        }
        .controls button {
            background: #10b981; border: none; color: #fff;
            padding: 8px 24px; font-weight: 700; cursor: pointer;
            border-radius: 2px;
        }
        .controls button:hover { background: #059669; }
        .sc-chart-type-button.d-none { display: inline-flex !important; }
        #status { font-size: 0.85rem; color: #888; margin-bottom: 8px; }
        #status.error { color: #ef4444; }
    </style>
</head>
<body>
    <h1>Alpha Vantage + JavaScript Stock Charts</h1>
    <p class="subtitle">
        Powered by <a href="https://simul8or.com/Javascript-Stock-Chart.php">JavaScript Stock Charts</a>
        | Free tier: 25 API calls/day
    </p>

    <div class="controls">
        <div>
            <label>API Key</label>
            <input type="text" id="apiKey" placeholder="Your Alpha Vantage API key" style="width:280px">
        </div>
        <div>
            <label>Ticker</label>
            <input type="text" id="ticker" value="AAPL" style="width:100px">
        </div>
        <button onclick="loadChart()">Load Chart</button>
    </div>

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

    <script src="https://cdn.jsdelivr.net/gh/day-trading-simulator/javascript-stock-charts@main/indicators.js"></script>
    <script src="https://cdn.jsdelivr.net/gh/day-trading-simulator/javascript-stock-charts@main/patterns.js"></script>
    <script src="https://cdn.jsdelivr.net/gh/day-trading-simulator/javascript-stock-charts@main/stock-chart.js"></script>
    <script>
        var chart = null;
        var currentTicker = 'AAPL';
        var previousTimeframe = '1day';
        var timeframeCheckInterval = null;
        var isLoadingMore = false;
        var earliestTimestamp = null;
        var hasMoreHistory = true;

        // Map chart timeframes to Alpha Vantage function + params
        function mapTimeframeToAlphaVantageParams(tf) {
            var map = {
                '1min':   { fn: 'TIME_SERIES_INTRADAY', interval: '1min',  outputsize: 'compact', seriesKey: 'Time Series (1min)' },
                '2min':   { fn: 'TIME_SERIES_INTRADAY', interval: '5min',  outputsize: 'compact', seriesKey: 'Time Series (5min)' },
                '5min':   { fn: 'TIME_SERIES_INTRADAY', interval: '5min',  outputsize: 'compact', seriesKey: 'Time Series (5min)' },
                '15min':  { fn: 'TIME_SERIES_INTRADAY', interval: '15min', outputsize: 'compact', seriesKey: 'Time Series (15min)' },
                '30min':  { fn: 'TIME_SERIES_INTRADAY', interval: '30min', outputsize: 'compact', seriesKey: 'Time Series (30min)' },
                '1hour':  { fn: 'TIME_SERIES_INTRADAY', interval: '60min', outputsize: 'compact', seriesKey: 'Time Series (60min)' },
                '60min':  { fn: 'TIME_SERIES_INTRADAY', interval: '60min', outputsize: 'compact', seriesKey: 'Time Series (60min)' },
                '4hour':  { fn: 'TIME_SERIES_INTRADAY', interval: '60min', outputsize: 'compact', seriesKey: 'Time Series (60min)' },
                '1day':   { fn: 'TIME_SERIES_DAILY',    interval: null,    outputsize: 'compact', seriesKey: 'Time Series (Daily)' },
                '1week':  { fn: 'TIME_SERIES_WEEKLY',   interval: null,    outputsize: null,   seriesKey: 'Weekly Time Series' },
                '1W':     { fn: 'TIME_SERIES_WEEKLY',   interval: null,    outputsize: null,   seriesKey: 'Weekly Time Series' },
                '1month': { fn: 'TIME_SERIES_MONTHLY',  interval: null,    outputsize: null,   seriesKey: 'Monthly Time Series' },
                '1M':     { fn: 'TIME_SERIES_MONTHLY',  interval: null,    outputsize: null,   seriesKey: 'Monthly Time Series' }
            };
            return map[tf] || map['1day'];
        }

        function transformAlphaVantageData(json, seriesKey) {
            var series = json[seriesKey];
            if (!series) return [];
            return Object.keys(series).sort().map(function(datetime) {
                var bar = series[datetime];
                return {
                    t: new Date(datetime).getTime(),
                    date: datetime,
                    open: parseFloat(bar['1. open']),
                    high: parseFloat(bar['2. high']),
                    low: parseFloat(bar['3. low']),
                    close: parseFloat(bar['4. close']),
                    volume: parseInt(bar['5. volume'])
                };
            });
        }

        // Fetch data from Alpha Vantage and render chart
        async function loadChart() {
            var apiKey = document.getElementById('apiKey').value.trim();
            var ticker = document.getElementById('ticker').value.trim().toUpperCase();
            var status = document.getElementById('status');

            if (!apiKey) { status.textContent = 'Enter your Alpha Vantage API key.'; status.className = 'error'; return; }
            if (!ticker) { status.textContent = 'Enter a ticker symbol.'; status.className = 'error'; return; }

            var timeframe = (chart && chart.timeframe) ? chart.timeframe : '1day';
            var p = mapTimeframeToAlphaVantageParams(timeframe);

            status.textContent = 'Fetching ' + timeframe + ' data...';
            status.className = '';

            var url = 'https://www.alphavantage.co/query?function=' + p.fn + '&symbol=' + ticker;
            if (p.interval) url += '&interval=' + p.interval;
            if (p.outputsize) url += '&outputsize=' + p.outputsize;
            if (p.fn === 'TIME_SERIES_INTRADAY') url += '&extended_hours=true';
            url += '&apikey=' + apiKey;

            try {
                var resp = await fetch(url);
                var json = await resp.json();

                if (json['Error Message']) {
                    status.textContent = json['Error Message'];
                    status.className = 'error'; return;
                }
                if (json['Note'] || json['Information']) {
                    status.textContent = json['Note'] || json['Information'];
                    status.className = 'error'; return;
                }

                var chartData = transformAlphaVantageData(json, p.seriesKey);
                if (chartData.length === 0) {
                    status.textContent = 'No data returned for ' + ticker + '.';
                    status.className = 'error'; return;
                }

                if (chart) chart.destroy();
                if (timeframeCheckInterval) clearInterval(timeframeCheckInterval);

                currentTicker = ticker;
                chart = new StockChart('chart', {
                    data: chartData, ticker: ticker,
                    chartType: 'candlestick', darkMode: true,
                    timeframe: timeframe,
                    useAfterHoursStyling: true,
                    onReachingStart: handleReachingStart
                });

                isLoadingMore = false;
                hasMoreHistory = (p.fn === 'TIME_SERIES_INTRADAY');
                earliestTimestamp = chartData[0].t;
                previousTimeframe = chart.timeframe || timeframe;
                setupTimeframeMonitor();

                status.textContent = '';
                status.className = '';
            } catch (err) {
                status.textContent = 'Network error: ' + err.message;
                status.className = 'error';
            }
        }

        // Monitor chart's built-in timeframe selector for changes
        function setupTimeframeMonitor() {
            if (timeframeCheckInterval) clearInterval(timeframeCheckInterval);
            timeframeCheckInterval = setInterval(function() {
                if (chart && chart.timeframe !== previousTimeframe) {
                    previousTimeframe = chart.timeframe;
                    loadChart();
                }
            }, 500);
        }

        // Infinite scroll - fetch older data when user pans to start
        async function handleReachingStart() {
            if (isLoadingMore || !hasMoreHistory || !earliestTimestamp) return;
            isLoadingMore = true;
            var apiKey = document.getElementById('apiKey').value.trim();
            if (!apiKey) { isLoadingMore = false; return; }
            try {
                var p = mapTimeframeToAlphaVantageParams(chart.timeframe || '1day');

                if (p.fn !== 'TIME_SERIES_INTRADAY') {
                    hasMoreHistory = false;
                    chart.setLoadingHistoricalData(false);
                    isLoadingMore = false;
                    return;
                }

                var d = new Date(earliestTimestamp);
                d.setMonth(d.getMonth() - 1);
                var month = d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0');

                var url = 'https://www.alphavantage.co/query?function=' + p.fn
                    + '&symbol=' + currentTicker
                    + '&interval=' + p.interval
                    + '&month=' + month
                    + '&outputsize=compact'
                    + '&extended_hours=true'
                    + '&apikey=' + apiKey;

                var resp = await fetch(url);
                var json = await resp.json();

                if (json['Error Message'] || json['Note']) {
                    hasMoreHistory = false;
                    chart.setLoadingHistoricalData(false);
                } else {
                    var older = transformAlphaVantageData(json, p.seriesKey);
                    if (older.length > 0) {
                        earliestTimestamp = older[0].t;
                        chart.prependHistoricalData(older);
                    } else {
                        hasMoreHistory = false;
                        chart.setLoadingHistoricalData(false);
                    }
                }
            } catch(e) {
                chart.setLoadingHistoricalData(false);
            } finally {
                isLoadingMore = false;
            }
        }
    </script>
</body>
</html>
Important: Never commit your API key to a public repository. For production apps, use environment variables or a server-side proxy. Remember: the free tier only allows 25 API calls per day.
Get Started

Ready to build your own chart?

Download the library, grab your Alpha Vantage API key, and start charting.

See more tutorials: JavaScript Stock Charts Documentation  |  Finnhub API Tutorial  |  Twelve Data API Tutorial

Wait, here's a special offer

Complete your purchase now and save over 20%.

$19 $15
One-time payment · Unlimited forever
One-time offer — won't be shown again
Secure checkout · Instant access · 30-Day Money Back Guarantee
Stripe
PayPal
No thanks, maybe later