How to Add a Live Gold Price Widget to Your Website
Add a live gold price widget to WordPress, Shopify or plain HTML: build it in the MetalAPI dashboard, choose symbols, layout and theme, then paste two lines.
What you are embedding
A MetalAPI widget is a small price board that MetalAPI hosts for you. You configure it once in the dashboard, paste a two-line snippet into your page, and visitors see current prices for gold, silver, platinum, palladium, industrial metals, energy, currencies or crypto. The widget renders inside an iframe served from metalapi.com. There is no backend code to write, no API key in your HTML, and nothing on your side to update when prices move.
That makes a widget the fastest option for content sites, jewelry and bullion shops, news pages and blogs that want to show the current price next to their own content. If you need the price inside your own markup or in a calculation, the REST API is a better fit. The last section of this post covers that case.
Widget traffic is served by MetalAPI's widget endpoint, not through your API key, so page views do not use your monthly request quota. Your plan decides how many widgets you can save and how fresh their prices are; both are covered below.
Build the widget in the dashboard
Widgets are included in every plan, Free too. Create an account, open Widgets in the dashboard and click New widget. The builder shows a live preview next to the form, so you can try options before you save:
| Option | Values | Notes |
|---|---|---|
| Layout | cards, table, ticker, single | Cards for a few prices, a table for many, a ticker for a slim strip, single for one large price |
| Symbols | Up to 20 | Metals, energy, currencies and crypto, shown in the order you pick them |
| Currency | USD or any supported currency | Every price is converted into this currency |
| Metal unit | Troy ounce, gram, kilogram, ounce, pound | Applies to metals only |
| Theme | Auto, light, dark | Auto follows the visitor's light or dark mode |
| Accent colour | Any hex colour | Used for highlights and the large price in the single layout |
| Title | Optional, up to 80 characters | Shown above the prices |
| Daily change | On or off | Today's percentage change, coloured up or down |
| Bid / ask | On or off | Standard plan and above; shown in the single and table layouts |
Two details are easy to miss. If you leave the unit at troy ounce, industrial metals are shown in their usual market unit instead, so copper appears per pound while gold stays per troy ounce. And a gram or kilogram unit converts metals only: currencies, energy and crypto keep their own units. If you are unsure which weight unit your visitors expect, the unit conversion guide explains the differences.
Saving gives the widget a public ID such as w_abc123. The embed code refers only to that ID; the configuration stays on MetalAPI's servers. When you later change symbols, colours or the layout, every page that embeds the widget shows the new version on its next load, with no change to the snippet on your site. The widget list also has a Live switch to take a widget offline without deleting it, and a view counter per widget.
The embed code, line by line
After saving, the builder shows the embed code:
<div id="metalapi-widget-w_abc123"></div>
<script src="https://metalapi.com/js/widget.js" data-widget="w_abc123" async></script>The script is a small loader, about 4 KB before compression. It reads data-widget, looks for the element with the id metalapi-widget-<id> and fills it with an iframe that loads https://metalapi.com/embed/<id>. If the container is missing, the loader creates one directly before the script tag. The widget inside the frame reports its height with postMessage, and the loader resizes the iframe to match, so a table that grows from three rows to six never shows a scrollbar.
The loader runs only once per page, even if the script tag appears several times. To show several widgets on one page, include the script a single time and mark each container with a data-metalapi-widget attribute instead of an id:
<div data-metalapi-widget="w_abc123"></div>
<div data-metalapi-widget="w_def456"></div>
<script src="https://metalapi.com/js/widget.js" async></script>The loader looks for these containers once, when the page has loaded. It does not see containers that client-side JavaScript adds later, for example after a route change in a single-page app. In that case, or where you cannot add scripts at all, embed the frame directly:
<iframe
src="https://metalapi.com/embed/w_abc123"
title="Live gold price"
loading="lazy"
style="border:0;width:100%;height:220px"
></iframe>Without the loader, the iframe cannot resize itself, so give it a height that fits the layout you picked. Pages that still use the older new MetalAPIWidget({...}) snippet from the previous widget generator keep working: saved widgets render by their ID, and any API key left in an old snippet is ignored.
Plain HTML, WordPress and Shopify
Plain HTML. Paste the snippet where the widget should appear, for example in a sidebar or at the top of a price page. Because of the async attribute, the loader never blocks the rest of the page while it downloads.
WordPress. In the block editor, add a Custom HTML block and paste the snippet. To show the widget on every page, put it in a Custom HTML widget in a sidebar or footer widget area, or in your theme's template files. Some setups, such as multisite networks or restricted hosting plans, strip <script> tags from content. If the widget does not appear after you publish, view the page source. If the script tag is missing, use the iframe version, which needs no script.
Shopify. In the theme editor (Online Store → Themes → Customize), add a Custom Liquid section or block to the template where the widget belongs and paste the snippet. To show it on product pages only, add the block to the product template. You can also place the snippet directly in a section file when you edit the theme code.
Other site builders. Builders with an HTML or embed element work the same way, for example Webflow's code embed or a Squarespace code block. Some builders wrap custom HTML in an iframe of their own, and the automatic resizing cannot reach through it. In that case, give the embed element a fixed height.
If your site sends a Content-Security-Policy header, allow https://metalapi.com in script-src for the loader and in frame-src for the iframe. Otherwise the browser blocks the widget and reports the violation in the developer console.
Plan limits, freshness and branding
A saved widget shows prices as fresh as its owner's plan allows, and it polls for new data on its own. The polling interval follows the plan's update interval, but it is never shorter than 30 seconds and never longer than 15 minutes:
| Plan | Widgets | Price updates | Widget refresh | Branding |
|---|---|---|---|---|
| Free | 1 | Daily | 15 min | Powered by MetalAPI |
| Lite | 3 | 30 min | 15 min | Powered by MetalAPI |
| Standard | 10 | 10 min | 10 min | Powered by MetalAPI |
| Advanced | 25 | 1 min | 1 min | Powered by MetalAPI |
| Pro | 50 | 1 min | 1 min | Removed |
| Ultra | 100 | 15 s | 30 s | Removed |
| Business | 200 | 15 s | 30 s | Removed |
| Enterprise | 500 | 5 s | 30 s | Removed |
On Free and Lite, the widget checks for new data more often than prices change, so it picks up each update without a reload. Every widget prints the time of its data in UTC at the bottom, so visitors can see how current the prices are. The full feature list per plan is on the pricing page.
Performance and layout shift
A widget adds very little to a page:
- Non-blocking script. The loader is loaded with
asyncand served with a one-hour browser cache, so returning visitors usually do not download it again. - Lazy frames. The loader creates the iframe with
loading="lazy", so a widget far down the page is only fetched when the visitor scrolls near it. - Isolation. The widget runs inside its own frame. Your stylesheets cannot break it, and its code cannot touch your page.
- Page caching is safe. The snippet never changes and the prices are loaded inside the frame. WordPress caching plugins, Shopify's CDN or any other full-page cache can keep your HTML as long as they like without freezing the price.
The one thing to plan for is layout shift. The frame starts at 120 pixels and then grows to the widget's real height, which can push the content below it down. Reserve the space in advance with a minimum height on the container, using the height you see in the builder preview:
<div id="metalapi-widget-w_abc123" style="min-height:240px"></div>
<script src="https://metalapi.com/js/widget.js" data-widget="w_abc123" async></script>A ticker needs far less space than a table of eight metals, so use one value per widget rather than a site-wide default.
When to use the API instead
A widget is a finished component. Use the API when you need something a widget does not do:
- Prices in your own HTML. Text inside an iframe belongs to another document, so search engines may not treat it as part of your page. If the price should be part of your page content, render it on the server.
- Your own design. Widgets offer four layouts, a theme and an accent colour. For anything beyond that, write your own markup.
- Calculations. Product prices based on weight and purity, buyback quotes and conversions belong on your server. The jewelry price calculator tutorial walks through one.
- Data in your application. Charts, history and stored prices need the historical and timeframe endpoints described in the API docs.
Call the API from your server and cache each response for your plan's update interval. On WordPress, a shortcode with a transient cache does both in a few lines:
<?php
// In wp-config.php: define('METALAPI_KEY', 'mk_live_...');
add_shortcode('gold_price', function ($atts) {
$a = shortcode_atts(['currency' => 'USD', 'unit' => 'troy_oz'], $atts);
$currency = strtoupper(preg_replace('/[^A-Za-z]/', '', $a['currency']));
$unit = sanitize_key($a['unit']);
$cache_key = "metalapi_xau_{$currency}_{$unit}";
$data = get_transient($cache_key);
if ($data === false) {
$url = add_query_arg(
['base' => $currency, 'currencies' => 'XAU', 'unit' => $unit],
'https://metalapi.com/api/v1/latest'
);
$res = wp_remote_get($url, ['headers' => ['X-API-Key' => METALAPI_KEY], 'timeout' => 10]);
if (is_wp_error($res)) return '';
$data = json_decode(wp_remote_retrieve_body($res), true);
if (empty($data['success'])) return '';
set_transient($cache_key, $data, 10 * MINUTE_IN_SECONDS); // your plan's update interval
}
$price = $data['rates'][$currency . 'XAU'] ?? null;
if ($price === null) return '';
return sprintf(
'<span class="gold-price">%s %s / %s</span>',
esc_html(number_format_i18n($price, 2)),
esc_html($currency),
esc_html(str_replace('_', ' ', $unit))
);
});Use it in any post or page as [gold_price currency="EUR" unit="gram"]. The response key is the base currency followed by the symbol, so rates.EURXAU is the price of one gram of gold in euros. Each cache miss costs one request, so a 10-minute transient uses at most about 4,500 requests a month for each currency and unit you display, which fits the Standard plan.
If you have to call the API from the browser instead, restrict the key to your own domains first, as described in the authentication guide. For a plain price display, though, the widget remains the simpler choice: no key, no cache to manage and nothing to maintain when you change symbols later.
Try it with your own data
Create a free account and make your first request in under two minutes. 100 requests a month, no credit card.
Keep reading
Gold Price API: The Complete Developer Guide
How to use a gold price API: get a key, call it from curl, JavaScript and Python, read the rates correctly, and handle history, errors, quotas and caching.
Gold Karat Prices Explained: 24K, 22K, 18K and How to Calculate Them
What 24K, 22K and 18K mean, how fineness marks like 916 and 750 relate, how to calculate karat gold prices per gram and how to get them from a gold price API.
Build a Jewelry Price Calculator with Live Gold Prices
Build a server-side jewelry price calculator in TypeScript and Python with live gold prices per gram, karat purity, making charges, VAT and quota-safe caching.