Issues with flask API on vercel

Hi, I am having issues with a flask web api I deployed on Vercel. The deployment and upload works fine.

So if I go to the API url works and shows the JSON data (see below screenshot):

If I include the link into a JS code to show the data in an HTML file doesnt work:

In the FLask Python code I include the allow CORS, infact when I tested the flask api locally works fine and shows the data correctly. The python code I deployed on vercel is the following:

from flask import Flask, jsonify
from flask_cors import CORS
import yfinance as yf
from datetime import date, datetime, timedelta
import pandas as pd
import numpy as np

app = Flask(__name__)
CORS(app)


@app.route('/')
def home():
    return "Marcello Personal Portfolio Dashboard API"

@app.route('/stock-data')
def get_stock_data():
    tickers = ['VHYL.L', 'MSFT', 'SGLN.L', 'IMEU.L', 'BABA', 'SAAA.L', 'XYZ']
    
    # weights of the stocks
    
    weights = np.array([0.2164, 0.1797, 0.1536, 0.1304, 0.1289, 0.1275, 0.0635])
    
    today = date.today()
    data = yf.download(tickers, start='2021-01-19', end="2025-02-21", interval="1mo", auto_adjust = False)['Adj Close']
    
    # normalize the price
    normalized_data = data / data.iloc[0]
    
    # portfolio performance
    portfolio_performance = (normalized_data * weights).sum(axis=1) #  weighted sum of all shares in the portfolio
    
    # Calculate the percentage change
    pct_change = (portfolio_performance.pct_change().fillna(0) * 100).tolist()
    
    
      # Prepare JSON response
    response_data = {
        "labels": normalized_data.index.strftime("%Y-%m-%d").tolist(),
        
        
        
        # add the percentage change to the response
        "pct_change": pct_change, # percentage change
        
        # add the weights to the response to show the weights of the stocks showing also the ticker of the stock
        "portfolio_weights": {
            "tickers": tickers,
            "weights": weights.tolist()
        }
                     
        
    }
    
    return jsonify(response_data)

PORTFOLIO = ['VHYL.L', 'MSFT', 'SGLN.L', 'IMEU.L', 'BABA', 'SAAA.L', 'XYZ']


def calculate_performance(ticker_data, periods):
    """Calculate performance for different time periods"""
    
    results = {}
    latest_price = ticker_data.iloc[-1]
    
    for period_name, days in periods.items():
        if days > len(ticker_data):
            results[period_name] = None
            continue
            
        start_price = ticker_data.iloc[-days]
        performance = ((latest_price - start_price) / start_price) * 100
        results[period_name] = round(performance, 2)
        
    return results

@app.route('/portfolio-performance')
def portfolio_performance():
    today = datetime.now()
    
    # Define time periods in trading days (approximations)
    periods = {
        '1_month': 21,
        'ytd': max(1, (today - datetime(today.year, 1, 1)).days), # Year-to-date (from Jan 1st) excluding weekends
        '1_year': 252,
        '3_year': 756,
        '5_year': 1260
    }
    # Calculate start date for data retrieval (add some buffer)
    start_date = (today - timedelta(days=1900)).strftime('%Y-%m-%d')
    end_date = today.strftime('%Y-%m-%d')
    
    portfolio_data = []
    
    for ticker in PORTFOLIO:
        try:
            # Get historical data
            stock_data = yf.Ticker(ticker)
            hist = stock_data.history(start=start_date, end=end_date)
            
            # Skip if no data
            if hist.empty:
                continue
                
            # Get adjusted close prices
            adj_close = hist['Close']
            
            # Calculate performance for different periods
            performance = calculate_performance(adj_close, periods)
            
            # Get current price
            current_price = round(float(adj_close.iloc[-1]), 2)
            
            # Get company name
            info = stock_data.info
            company_name = info.get('shortName', ticker)
            
            portfolio_data.append({
                'ticker': ticker,
                'name': company_name,
                'current_price': current_price,
                'performance': performance
            })
            
        except Exception as e:
            print(f"Error processing {ticker}: {e}")
    
    return jsonify(portfolio_data)

if __name__ == '__main__':
    #app.run(debug=True) # run the app in debug mode locally
    app.run() # run the app in production mode

Hope someone can help thanks. Marcello

Hi @marcello-calabrese, welcome to the Vercel Community!

Thanks for posting your code here. It looks like you did not specify the allowed origins when configuring CORS. From the flask-cors docs, you need to use the origins options to allow a list of origins. I see you are using HTML files directly in the browser, I’d suggest adding a simple HTTP server in front of it and adding it’s URL in the origins list:

You might also find our post about all the ways of using CORS on Vercel. I highly recommend reading it.

Hi @anshumanb thanks a lot for your guidance.

When I tested the flask api locally worked fine without specifying the origins, probably this is why and then if the api is online needs the origins specifications.

Basically the html file is local because I use it in a .NET DC# desktop APP to retrieve the data from the flask API link and show and populate the Javas script charts. So I guess I should modify the python code (based on your suggestions):

app = Flask(__name__)
CORS(app, origins="C:///.....main.html")

Hope I understood correctly.

Thanks a lot

Hi @marcello-calabrese, you got it right. Locally both the frontend and backend are on the same origin so things work fine.

When you host your frontend and backend separately (different origins), then the browsers use the CORS specification to ensure that the server is allowing your frontend or not.

By design, CORS will be blocked on the local file so using origins="....main.html" will not work. You’ll need to use a simple http server. For example, local-web-server - npm to get it working. Then the origin will be localhost:[PORT].

I hope this was helpful.

Thanks again, Not sure if I understood about create a local http server. Do you mean to create a localhost server and spin the html page through the server? and then put it in the origins flag?

@anshumanb hi again, I was thinking, because I don’t want everytime to run a local server to allow the access to the html page. Could it make sense at this point to deploy the main.html file on vercel and then add in the origins="https://marcelloblahblah.vercel.app/main.html

I can '‘embed’ the ‘‘online’’ html page on the C# desktop app with Webview2. Please let me know if it makese sense. Thanks, Marcello

Hi @marcello-calabrese, I understand you don’t want to run it locally.

The reason I suggested a local server was that I assumed you’re developing the frontend (main.html and the related JS code) locally. If that’s not the case, yes you can host your frontend code on Vercel and add https://marcelloblahblah.vercel.app as the origin to the CORS config. Just ensure that you follow the flask-cors docs on the syntax for the change.

Great thanks a lot @anshumanb . Happy to close the ticket now. Marcello