Build an India Gold Price App with JavaScript
Build a live India gold-rate app from INR per-gram 24K and 22K prices, with server-side caching, Indian number formatting, GST estimates, and clear limits.
Read →The gold-price-API errors developers hit on Stack Overflow, fixed: 401 auth, 400 invalid_symbol, 429 rate limits, CORS from the browser, reading the response, and pulling historical data.
When an integration breaks, developers paste the error into Stack Overflow. The questions that come up for a gold price API are almost always the same handful: an auth rejection, a malformed symbol, a rate-limit wall, or a CORS error from the browser. This post fixes each one directly, using goldprice.dev as the worked example. Every snippet below is a real, working call against https://api.goldprice.dev.
The key goes in the Authorization header as a bearer token, and the word Bearer (with a trailing space) has to be there:
curl https://api.goldprice.dev/v1/prices?symbol=XAU-USD-SPOT \
-H "Authorization: Bearer ga_live_YOUR_KEY"
The three things that actually cause a 401: the Bearer prefix is missing, the key has a stray newline or quote from a copy-paste, or the key is being read from an env var that is not loaded. Keys are prefixed ga_live_. You do not strictly need a key to start — anonymous calls work but are capped at 100 requests per hour per IP, so for anything past a quick test, authenticate.
The symbol parameter is not a bare metal code. It is BASE-QUOTE-CONTRACT. Passing symbol=XAU returns 400 invalid_symbol; the value you want for live gold spot is XAU-USD-SPOT:
# wrong — 400 invalid_symbol
curl "https://api.goldprice.dev/v1/prices?symbol=XAU"
# right
curl "https://api.goldprice.dev/v1/prices?symbol=XAU-USD-SPOT"
Silver spot is XAG-USD-SPOT and copper is HG-USD-FUTURES. Futures use the FUTURES contract, for example XAU-USD-FUTURES — note that gold futures need the Basic tier, and silver and copper need Pro, so on the free tier those symbols return 403 plan_gated. Omitting symbol entirely returns the default allowed rows for your tier, which is also a valid way to avoid the error.
Every response carries an X-RateLimit-Remaining header. Read it and back off before you hit zero rather than polling blind and catching 429s. The free tier is 30 requests per minute; Physical is 120; Pro and Realtime Pro are 500. For most apps a short client-side cache, sized to how often the price actually moves, keeps you well clear of the limit — the spot price does not change meaningfully every second, so caching for a few seconds is usually correct.
Do not call the API directly from front-end JavaScript with your key. Two reasons: it exposes ga_live_... to anyone who opens devtools, and browser CORS will block it. Proxy the call through your own backend, keep the key server-side, and have the browser hit your endpoint:
// your backend route — the key never reaches the browser
const r = await fetch(
"https://api.goldprice.dev/v1/prices?symbol=XAU-USD-SPOT",
{ headers: { Authorization: `Bearer ${process.env.GOLDPRICE_API_KEY}` } },
);
const data = await r.json();
If the goal is simply to display a live price rather than process the JSON, use the free gold price widget. Its hosted iframe needs no API key and avoids the browser CORS path entirely.
The default response, anonymous or authenticated, gives you price, bid, ask, computed_at, and is_stale — nothing else. Everything richer is opt-in via ?include=: ?include=sources adds a sources[] array, ?include=karat adds a per-gram karat breakdown, and ?include=stats (authenticated only) adds open_price, high_price, low_price, prev_close_price, the change fields, and divergence_bps / divergence_flag. ?include=all returns everything your auth level permits. Two fields matter for correctness:
is_stale — true when the value is older than its expected refresh window. Check it before you display a price.sources[] (with ?include=sources) — one row per upstream, each with its own price and timestamp. When sources disagree, divergence_bps (with ?include=stats) tells you by how much, so you can set your own tolerance instead of trusting a single blended number.Daily close history is GET /v1/prices/history, available on every tier — what changes is how far back you can go. The free tier returns the last 30 days, Basic the last year, and Pro the full history. So if a historical query comes back shorter than you expected, that is the window for your tier, not an auth error.
No key, correct symbol:
curl "https://api.goldprice.dev/v1/prices?symbol=XAU-USD-SPOT"
That returns a live, honest gold price with a staleness flag. Add ?include=sources for the contributing sources. When you want the full response shape and higher limits, a free key takes a minute. If you prefer a language-specific walkthrough, Fetch live gold prices in JavaScript covers the REST path end to end, and Caching gold prices and staying inside rate limits covers doing it at volume.
related guides
Build a live India gold-rate app from INR per-gram 24K and 22K prices, with server-side caching, Indian number formatting, GST estimates, and clear limits.
Read →Build a gold jewelry price calculator from live per-gram karat prices, with exact decimal math, caching, margins, and clear valuation limits.
Read →Build a reproducible local-currency gold backtest from settled XAU/USD bars and dated FX observations, without inserting future rates into historical rows.
Read →goldprice.dev
Live gold prices, historical OHLC, and multi-source aggregation — available via REST and SSE.