Stock Report Dashboard (Canva code)
From Canva to Cloud: Making a Functional Market Dashboard
I set out to build a simple, live-updating stock dashboard. Canva’s code apps allowed me to rapidly prototype and visually design the frontend, but I discovered a key limitation: You can’t directly connect to most real-time data APIs (like Finnhub or Yahoo Finance) from a Canva-hosted dashboard, or from Google Cloud Storage, due to CORS and API security restrictions.
Here’s the path I took to go from a Canva concept to a fully working, public dashboard.
Summary of Steps
1. Designed the dashboard frontend in Canva Code Apps.
Canva’s editor made it easy to create a professional-looking HTML/JavaScript dashboard and preview it instantly.
2. Exported the dashboard code to an HTML file.
Once the visual layout was right, I downloaded the HTML/JS to my computer for further work.
Create a Finnhub.io API
3. Discovered API call issues in deployment.
Static hosting platforms (like Canva, Google Cloud Storage, Squarespace, etc.) can’t make direct JavaScript calls to most market data APIs due to cross-origin (CORS) and security policies.
4. Set up a backend “proxy” API using Google Cloud Run.
Wrote a tiny Node.js server that forwards API requests to Finnhub.
Deployed this server to Google Cloud Run as a secure, scalable web API.
Now, my frontend code requests data from my own proxy endpoint—no CORS errors, and my API key is kept secret.
5. Updated the html code to call my proxy.
Changed all API calls in the JS to use the Cloud Run proxy URL.
Trimmed the stock list to avoid free-tier API rate limits.
Added clear labeling that index values shown are for ETF proxies (SPY, DIA, QQQ).
6. Deployed the HTML dashboard to Google Cloud Storage.
Uploaded the index.html to a public GCS bucket for free hosting.
Set permissions so anyone can view the dashboard.
7. Embedded or linked the dashboard on my main website.
Used an iframe to embed the live dashboard in the blog post.
Try the stock dashboard.
Refresh should function properly; however the request limits are low, so if it is refreshed two or three times in a minute it will return an error.