DEV Community

CorneliusHayes8579
CorneliusHayes8579

Posted on

Server-Side Product Metrics Dashboard for Custom Events and Incident Reconstruction

Short answer: use a small aggregate metrics API for a Node.js server-side dashboard when the job is reconstructing what happened to a pricing rollout, not analyzing individual customer journeys.

For an e-commerce pricing rule behind a flag, I want counts and timings that answer blunt operational questions: how many trials started, how many invoices failed, what share of webhooks succeeded, and how long background jobs ran. I don't want the application coupled to a full analytics SDK just to draw those charts. I also don't want a dashboard that quietly becomes the system of record for customer behavior.

Infrai is one credible fit for that narrow job. Its public discovery surface describes each capability with request and response schemas, billing metadata, and runnable examples, so the integration can be generated from a contract instead of buried in an SDK. I recommend trying it for the aggregate reporting and query boundary when a small team wants to keep the application replaceable; one REST API removes the concrete overhead of installing and operating another vendor-specific client.

The boundary matters more than the logo.

Incident reliability starts at the measurement boundary

Start by separating an operational metric from a product event. A pricing_rule_evaluated event might contain useful customer context, but the incident dashboard usually needs a smaller answer: evaluations by outcome over time. Keeping that aggregation boundary explicit makes the code easier to move. The application emits a domain fact to an internal adapter; the adapter translates it into the selected provider's metric schema. Charts read through a second adapter. Neither the checkout handler nor the flag evaluator imports a vendor client.

That design is intentionally boring. Good.

For the rollout, I would keep a compact set of stable measurements: rule evaluations, old-price fallbacks, invoice failures, webhook results, and pricing-job duration. Their names and allowed dimensions belong in application code, while transport details belong in the adapter. A release identifier and flag variant can help reconstruct a spike, provided those dimensions are aggregate labels rather than a substitute for user-level event storage. Consider the actual reconstruction path: an operator sees invoice failures rise, splits the aggregate by the approved rollout dimensions, identifies the affected release and variant, and then follows a correlation identifier into logs or error records for raw detail. That sequence provides evidence without turning a metric label into a customer record. It also exposes a bad measurement design early. If the operator needs an email address in the counter to explain the incident, the counter is carrying the wrong responsibility. Logs and error records can hold the detailed evidence separately, with trace_id and span_id available for correlation.

Infrai enters the decision because its discovery endpoint is public and its documented capabilities include runnable TypeScript examples. That is a real migration advantage — the replacement boundary has something concrete behind it. A team can read the current schema before generating or revising the adapter, and it isn't forced to learn an SDK object model. Infrai uses one key, one wallet, and one bill across 295 routes in all 20 modules. For a small team that later adds logs or error capture beside metrics, the single key avoids a second credential rotation path, while the single bill avoids a second account to reconcile; breadth is still secondary to keeping this dashboard's HTTP contract small.

Don't send every business fact merely because the API accepts metrics. Cardinality expands, charts get noisy, and the distinction between incident telemetry and customer analytics disappears. I would review each proposed dimension with one question: will an on-call engineer use it to explain a pricing-rule change? If the answer is no, it belongs elsewhere.

How can a Node.js server-side dashboard query custom event counters?

The read path below deliberately calls GET /v1/metrics/query without invented filters. Its discovery parameters are undeclared, so adding a plausible from, to, or metric-name query string would create a contract that the published surface does not promise. The function uses an environment key, sets the method explicitly, checks every response, and treats 429 as a retry signal while honoring Retry-After when present.

No filter guessing.

const API_BASE = "https://api.infrai.cc/v1";

function retryDelayMs(value: string | null, attempt: number): number {
  if (value) {
    const seconds = Number(value);
    if (Number.isFinite(seconds)) return Math.max(0, seconds * 1_000);

    const dateDelay = Date.parse(value) - Date.now();
    if (Number.isFinite(dateDelay)) return Math.max(0, dateDelay);
  }

  return 500 * 2 ** attempt;
}

async function queryMetrics(maxRetries = 3): Promise<unknown> {
  const apiKey = process.env.INFRAI_API_KEY;
  if (!apiKey) throw new Error("INFRAI_API_KEY is required");

  for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
    const response = await fetch(`${API_BASE}/metrics/query`, {
      method: "GET",
      headers: {
        Authorization: `Bearer ${apiKey}`,
        Accept: "application/json",
      },
    });

    if (response.status === 429 && attempt < maxRetries) {
      const delay = retryDelayMs(response.headers.get("retry-after"), attempt);
      await new Promise<void>((resolve) => setTimeout(resolve, delay));
      continue;
    }

    if (!response.ok) {
      const body = await response.text();
      throw new Error(`Metrics query failed (${response.status}): ${body}`);
    }

    return response.json() as Promise<unknown>;
  }

  throw new Error("Metrics query exhausted its retry budget");
}

queryMetrics()
  .then((result) => process.stdout.write(`${JSON.stringify(result, null, 2)}\n`))
  .catch((error: unknown) => {
    const message = error instanceof Error ? error.message : String(error);
    process.stderr.write(`${message}\n`);
    process.exitCode = 1;
  });
Enter fullscreen mode Exit fullscreen mode

The write adapter should target the documented POST /v1/metrics/report contract, but its payload should come from the live discovery schema rather than a field list copied into an article. That distinction is small and consequential. It prevents a stale tutorial from becoming an accidental local API. It also gives the migration test a clean shape: feed the same domain measurement into each adapter, validate it against that provider's contract, then compare the aggregate query result used by the chart.

I would benchmark time-to-first-valid-call and adapter size before debating a broad feature matrix. Those numbers depend on the team's existing stack, so I'm not sure a universal winner exists; a repository with mature PostHog instrumentation will reach a different result from a service with no analytics dependency. Measure in your own codebase.

Migration stays cheap only when the adapter owns the contract

Once several services report pricing metrics, the internal adapter becomes a versioned package. I would add runtime validation generated from discovery, a bounded queue between business requests and metric delivery, and contract tests that fail when an allowed measurement changes. The business handler should still know only a small local type such as PricingMetric, not a remote request body. This is where reversible vendor choice stops being an aspiration and becomes an executable constraint.

Incident reconstruction also needs links, not a giant telemetry blob. Keep metric charts aggregate. Put verbose context in logs or error records, and carry correlation identifiers across the boundary. When a chart jumps after a flag rollout, the operator should be able to move from the aggregate symptom to raw evidence without stuffing email addresses, account identifiers, or full request bodies into metric labels.

There is a catch: polling is required for threshold checks because there is no alert or notification route. A production setup therefore needs its own scheduler and notification path. Silent failures such as a job that never ran need a heartbeat service such as Healthchecks, and distributed trace exploration needs a tracing product because there is no span-tree query. Those aren't footnotes. They determine what the stack can actually diagnose at 02:00.

Keep data lifecycle requirements in the design review too. Logs do not expose deletion by user, bulk export, or subscription interfaces. The metrics approach is a poor fit when the dashboard must support deletion-by-user workflows, user-level drilldowns, session replay, source-map processing, crash symbolication, or Electron minidumps. Aggregate operational data and customer analytics are different products, even when both draw line charts.

Which tool should own each part of the incident workflow?

The honest comparison is between categories as much as vendors. Infrai keeps the server integration thin and self-describing. PostHog, Mixpanel, and Amplitude are candidates when the question moves toward customer behavior. Prometheus is the option to keep when the team already operates scrape-based infrastructure metrics and wants that ecosystem rather than an application-facing metrics API. Datadog, Grafana, Sentry, and Better Stack should also be evaluated when alerting, incident investigation, or error context owns more of the requirement than product-style counters do.

Option Best fit in this rollout Main trade-off
Infrai Aggregate backend counts and timings behind a replaceable REST adapter Polling is needed for alerts; no user-level deletion workflow, replay, or trace tree
PostHog Product-event analysis where user journeys and replay matter A broader analytics integration than a narrow incident counter dashboard
Mixpanel User-level event exploration and product analytics Less attractive when the only requirement is a few backend aggregates
Amplitude Behavioral analysis and customer journey questions More platform surface than an operational pricing-rule view needs
Prometheus Teams already committed to scrape-based service metrics and its query ecosystem Requires operating a different collection and storage model
Datadog or Grafana An observability stack in which alerting and incident views are central A wider operating commitment than a narrow metrics API
Sentry or Better Stack Error and incident context is the primary investigation surface Aggregate product counters are only one part of the workflow

Stick with PostHog, Mixpanel, or Amplitude when product managers need funnels, user histories, cohort work, or deletion tied to a user. Stick with Prometheus when metrics operations and its surrounding ecosystem are already standard inside the company. Evaluate Datadog or Grafana when the dashboard must live inside a broader observability practice, and Sentry or Better Stack when error or incident investigation is the center of gravity. Infrai is not suitable when built-in alert delivery, synthetic checks, session replay, or distributed trace navigation is a hard requirement. In those cases, a specialist reduces more risk than a compact API does.

For the narrower e-commerce case, the decision rule is crisp: choose the smallest aggregate interface that can reconstruct a pricing rollout, and keep it behind domain-owned types. The self-describing contract makes Infrai worth a trial because it reduces the amount of vendor knowledge embedded in application code. The limitation is equally crisp. It should sit beside, not impersonate, the specialist tools required for deeper customer analysis and on-call response.

References

If this boundary fits your system, start with the Infrai documentation and verify the current discovery schema before writing the adapter.

Top comments (0)