SDKs
Small helpers for the Metrics Protocol. Each one checks theMosaicdeck-Signature signature and builds the JSON document, so your code only returns numbers. None of them has runtime dependencies, and all three are tested against the protocol's published test vectors.
Beta: the packages aren't on npm or PyPI yet. Until they are, ask support for the package files, or copy the short reference implementations in theprotocol, section 8: they work without any package.
Before you start
- On the site's Connections tab, turn on the metrics endpoint. Copy the secret (it's shown once) and store it as
MOSAICDECK_SECRET. - The default path is
/.well-known/mosaicdeck. If you choose another path, setMOSAICDECK_PATH(Node, Python) or passpath(Web) with the exact string shown in the app, because the signature covers it. - Deploy, then click Test connection. It shows the metrics it parsed and any it skipped, with the reason.
Workers and edge runtimes: @mosaicdeck/web
Uses WebCrypto, so it runs on Cloudflare Workers, Next.js (edge or Node), Deno, Bun and Node 20+.
import { counter, createHandler, gauge, status } from "@mosaicdeck/web";
export default {
async fetch(request: Request, env: Env) {
const url = new URL(request.url);
if (url.pathname === "/.well-known/mosaicdeck") {
return createHandler({
secret: env.MOSAICDECK_SECRET,
site: { name: "My app", kind: "saas" },
metrics: async () => [
counter("users_total", await countUsers(env), { unit: "users", primary: true }),
gauge("active_projects", await countProjects(env), { unit: "projects" }),
status("database", "ok"),
],
})(request);
}
// … the rest of your app
},
};Set the secret with wrangler secret put MOSAICDECK_SECRET. createHandler answers 401 to unsigned requests and 405 to anything but GET. Pass cacheSeconds (up to 60) to reuse the computed document between polls.
Node.js: @mosaicdeck/node
An Express/Connect handler that reads MOSAICDECK_SECRET and MOSAICDECK_PATH from the environment.
import express from "express";
import { counter, gauge, mosaicdeck, status } from "@mosaicdeck/node";
const app = express();
app.get("/.well-known/mosaicdeck", mosaicdeck({
site: { name: "My app", kind: "saas" },
metrics: async () => [
counter("users_total", await db.user.count(), { primary: true }),
status("database", "ok"),
],
}));Mount it on the path only. For Workers or edge runtimes, use @mosaicdeck/web instead.
Python: mosaicdeck
Standard library only. Works with Flask, Django, FastAPI or anything else that can read a header and return JSON.
from flask import Flask, request, jsonify, abort
import mosaicdeck as md
app = Flask(__name__)
@app.get("/.well-known/mosaicdeck")
def metrics():
if not md.verify(request.headers.get("Mosaicdeck-Signature")): # reads MOSAICDECK_SECRET
abort(401)
return jsonify(md.document(
[md.counter("users_total", User.query.count(), primary=True), md.status("database", "ok")],
site={"name": "My app", "kind": "saas"},
))Top-N lists use md.list_metric(...) in Python.
Metric helpers
| Helper | Use it for |
|---|---|
counter(key, value, options?) | A running total that only goes up, like users_total. Mosaicdeck works out the change per period. |
gauge(key, value, options?) | A current value that can go up or down, like active subscriptions. |
status(key, "ok" | "warn" | "down", options?) | A health check, such as the database or a job queue. Can raise alerts. |
list(key, items, options?) | A top-N list of up to 20 items with labels and values. |
Options include label, description, unit, format, group,primary (shown on the portfolio card) and higher-is-better. For example:
list("top_recipes", [
{ label: "Banana bread", value: 412, url: "/recipes/banana-bread" },
{ label: "Lentil soup", value: 377 },
], { window: "7d", label: "Most viewed recipes" })The full field list, limits and privacy rules are in the protocol. Never put personal data in labels.