Skip to content
UsageRail
How it works / Usage widget

Usage widget

The usage widget shows one customer their usage inside your own dashboard: how much of this period's plan they've used, up to 30 days of history (7 days on the Free plan), and which endpoints they called. You put it in an iframe. Your server signs a short-lived token for that customer, and the widget shows nothing without it.

Set it up

  1. In the console, open your app's Portal page and find Usage widget. Create an embed key. It's shown once: put it in your server's environment as USAGERAIL_EMBED_KEY.
  2. When a signed-in customer opens the page with the widget, sign a token for them on your server.
  3. Put the widget in an iframe, with the token after the #.
usage-widget.js
import { createHmac, randomUUID } from "node:crypto";

// One customer's usage widget link, valid for an hour. Sign it on your server only.
export function usageWidgetToken(consumerId) {
  const now = Math.floor(Date.now() / 1000);
  const part = (value) => Buffer.from(JSON.stringify(value)).toString("base64url");
  const claims = { app_id: "app_...", consumer_id: consumerId, iat: now, exp: now + 3600, jti: randomUUID() };
  const unsigned = `${part({ alg: "HS256", typ: "JWT" })}.${part(claims)}`;
  const signature = createHmac("sha256", process.env.USAGERAIL_EMBED_KEY).update(unsigned).digest("base64url");
  return `${unsigned}.${signature}`;
}
usage_widget.py
import base64, hashlib, hmac, json, os, time, uuid

# One customer's usage widget link, valid for an hour. Sign it on your server only.
def usage_widget_token(consumer_id: str) -> str:
    def part(data: bytes) -> str:
        return base64.urlsafe_b64encode(data).rstrip(b"=").decode()
    now = int(time.time())
    claims = {"app_id": "app_...", "consumer_id": consumer_id, "iat": now, "exp": now + 3600, "jti": str(uuid.uuid4())}
    unsigned = part(json.dumps({"alg": "HS256", "typ": "JWT"}).encode()) + "." + part(json.dumps(claims).encode())
    signature = hmac.new(os.environ["USAGERAIL_EMBED_KEY"].encode(), unsigned.encode(), hashlib.sha256).digest()
    return unsigned + "." + part(signature)
dashboard.html
<iframe src="https://your-app.usagerail.app/embed#token=TOKEN" title="Usage" width="100%" height="560" style="border: 0"></iframe>

The console's copy of this code has your app's ID and portal address filled in. Any JWT library that signs HS256 works too.

The token

ClaimWhat it is
app_idYour app's ID. It has to match the portal the widget is loaded from.
consumer_idThe customer's ID in UsageRail, such as cons_.... Your backend gets it from the console, or from the server API: POST /v1/consumers with your own user ID returns that customer.
iatWhen you signed it, in Unix seconds.
expWhen it stops working, at most 24 hours after iat.
jtiAny unique string, such as a UUID.

The header must say HS256; tokens signed with any other algorithm are refused. A token that's expired, signed with the wrong key, missing a claim, or made for another app or for a customer being deleted gets the same answer: the widget says the link has expired or isn't valid. A suspended customer can still see their usage.

Who can see it

Anyone who has the link can see that customer's usage until the token expires. Forwarding the link shares it, so keep tokens short-lived: an hour is plenty for a dashboard page, and you sign a fresh one each time the page loads.

The token sits after the #. Browsers don't send that part of a URL to servers, so it doesn't end up in access logs. The widget's own script reads it and sends it with each request for data. The widget uses no cookies, so it works in browsers that block third-party cookies.

There's no way yet to cancel a single link before it expires. Rotating the embed key cancels all of them at once.

Rotating the embed key

Rotate the key from the same place in the console. The old key stops working at once, and so does every token signed with it, including widgets that are already open: their next request for data is refused. Put the new key on your servers straight away.

Options

Add these before the #:

OptionWhat it does
?theme=light or ?theme=darkFixes the theme. Without it, the widget follows the visitor's system setting.
?days=7How many days of history to show, from 1 to 30. The default is 30, and your UsageRail plan's analytics retention caps it: 7 days on Free.

For example: https://your-app.usagerail.app/embed?theme=dark&days=14#token=TOKEN.

What it shows

The top of the widget answers how much of this period the customer has used. The wording follows their plan:

  • Stops at the limit: usage against the limit and the date it resets, with a bar. A mark on the bar shows how far through the period today is, so a customer can see whether they're on pace to run out. Once the limit is used up, the bar turns red and says requests are refused until the reset.
  • Billed for overage (not live yet): usage this period and how much the plan includes.
  • Prepaid credits (not live yet): the credits left.
  • No cap: usage this period.

Below that, a daily chart splits each day into requests that counted toward the plan and requests that didn't, such as refused ones, and a list shows the units each endpoint used. Dates follow your app's time zone.

The widget uses your portal's name, color and footer setting. "Powered by UsageRail" follows the same rule as in the portal: it can't be hidden on the Free plan.