MetalAPI
XAU3,997.89−1.54%XAG53.936−1.51%XPT1,554.47−0.83%XPD1,047.03−0.44%XCU6.5080+2.29%WTI103.27+3.82%BRENT111.70−1.30%EUR1.120400−0.01%GBP1.337500−0.01%JPY0.0063761+0.14%CHF1.213445−0.25%TRY0.020125−0.12%BTC80,329.75−0.55%ETH2,329.36−1.13%
All articles
WidgetsTutorialE-commerce

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.

By MetalAPI Team··8 min read

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:

OptionValuesNotes
Layoutcards, table, ticker, singleCards for a few prices, a table for many, a ticker for a slim strip, single for one large price
SymbolsUp to 20Metals, energy, currencies and crypto, shown in the order you pick them
CurrencyUSD or any supported currencyEvery price is converted into this currency
Metal unitTroy ounce, gram, kilogram, ounce, poundApplies to metals only
ThemeAuto, light, darkAuto follows the visitor's light or dark mode
Accent colourAny hex colourUsed for highlights and the large price in the single layout
TitleOptional, up to 80 charactersShown above the prices
Daily changeOn or offToday's percentage change, coloured up or down
Bid / askOn or offStandard 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:

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:

Several widgets on one page
<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 only
<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:

PlanWidgetsPrice updatesWidget refreshBranding
Free1Daily15 minPowered by MetalAPI
Lite330 min15 minPowered by MetalAPI
Standard1010 min10 minPowered by MetalAPI
Advanced251 min1 minPowered by MetalAPI
Pro501 min1 minRemoved
Ultra10015 s30 sRemoved
Business20015 s30 sRemoved
Enterprise5005 s30 sRemoved

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 async and 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:

Reserve space to avoid layout shift
<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:

functions.php
<?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