PRACTICAL GUIDE / Selenium Grid GraphQL dashboard

Build a Selenium Grid Capacity Dashboard with GraphQL

Build a Selenium Grid GraphQL dashboard for node health, sessions, queue depth, compatible slot capacity, stale-data handling, and actionable alerts.

By The Testing AcademyUpdated July 11, 20269 min read
All field guides
In this guide11 sections
  1. Start with the supported Grid schema
  2. Query Grid and Node capacity together
  3. Poll with transport and GraphQL validation
  4. Calculate concurrency without confusing slots
  5. Break capacity down by compatible stereotype
  6. Design panels around operational decisions
  7. Alert on sustained, fresh conditions
  8. Protect the GraphQL surface and its data
  9. Diagnose a broken dashboard by layer
  10. Capacity dashboard checklist
  11. Make the dashboard explain the queue

What you will learn

  • Start with the supported Grid schema
  • Query Grid and Node capacity together
  • Poll with transport and GraphQL validation
  • Calculate concurrency without confusing slots

A Selenium Grid GraphQL dashboard should answer three operational questions: can Nodes accept work, is compatible capacity available, and are new-session requests waiting? The endpoint already exposes Grid, Node, session, slot, stereotype, status, and queue fields. A focused poller can turn that model into evidence without scraping the Grid UI or querying every component independently.

Capacity is not one number. Configured slots describe browser choices, maxSession limits concurrent execution, sessionCount reports current use, Node status controls eligibility, and queue depth shows demand that has not yet been assigned. A useful dashboard preserves those distinctions instead of compressing them into a misleading green percentage.

Start with the supported Grid schema

The official Selenium GraphQL guide documents the /graphql endpoint and fields under grid, nodesInfo, sessionsInfo, and session(id: ...). Query only fields that drive a panel, calculation, alert, or diagnostic link.

Animated field map

Grid Capacity Dashboard Pipeline

Poll the GraphQL endpoint, validate its model, calculate bounded capacity, and alert only from fresh compatible-state evidence.

  1. 01 / dashboard poller

    Dashboard Poller

    Send a bounded authenticated request and timestamp the observation.

  2. 02 / graphql endpoint

    Grid GraphQL Endpoint

    Return selected Grid, Node, session, queue, and stereotype fields.

  3. 03 / slot model

    Node and Slot Model

    Validate statuses, concurrency limits, slot counts, and capabilities.

  4. 04 / utilization

    Utilization Calculation

    Separate active sessions, concurrency headroom, and compatible slots.

  5. 05 / capacity alert

    Capacity Alert

    Evaluate sustained fresh conditions with diagnostic dimensions.

Treat the schema as an external contract. Test the dashboard query against the exact Grid release in staging. GraphQL lets a client select fields, but requesting a field absent from that deployed schema returns a query error rather than silently omitting it.

Query Grid and Node capacity together

One request can retrieve the global summary and enough Node detail to explain it. The query below avoids complete session payloads and operating-system details because the main capacity panels do not need them.

GRAPHQL
query GridCapacity {
  grid {
    uri
    version
    nodeCount
    totalSlots
    maxSession
    sessionCount
    sessionQueueSize
  }
  nodesInfo {
    nodes {
      id
      uri
      status
      maxSession
      slotCount
      sessionCount
      stereotypes
    }
  }
}

Node status is an enum with states including UP, DRAINING, and UNAVAILABLE. Do not collapse those into an online boolean. A draining Node may continue existing sessions while correctly refusing new work, and an unavailable Node's configured slots should not count as immediately usable capacity.

Use a separate detail query when an operator opens a session or Node view. Fetching every capability and session field on every dashboard tick increases payload size and exposes more potentially sensitive metadata without improving the top-level signal.

Poll with transport and GraphQL validation

Set a request timeout shorter than the poll interval, allow only one in-flight poll, and retain the last good sample when a fetch fails. Mark it stale rather than replacing it with zeros. Zero sessions from a failed parser looks like a healthy idle Grid and can suppress the alert that matters.

TypeScript
type GraphQLError = { message: string };

type CapacityData = {
  grid: {
    nodeCount: number;
    totalSlots: number;
    maxSession: number;
    sessionCount: number;
    sessionQueueSize: number;
  };
  nodesInfo: {
    nodes: Array<{
      id: string;
      uri: string;
      status: "UP" | "DRAINING" | "UNAVAILABLE";
      maxSession: number;
      slotCount: number;
      sessionCount: number;
      stereotypes: unknown;
    }>;
  };
};

export async function fetchCapacity(
  endpoint: string,
  signal: AbortSignal,
): Promise<{ data: CapacityData; observedAt: string }> {
  const response = await fetch(endpoint, {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({ query: CAPACITY_QUERY }),
    signal,
  });

  if (!response.ok) throw new Error(`GraphQL HTTP ${response.status}`);
  const payload = (await response.json()) as {
    data?: CapacityData;
    errors?: GraphQLError[];
  };
  if (payload.errors?.length || !payload.data) {
    throw new Error(payload.errors?.map((e) => e.message).join("; ") ?? "Missing data");
  }
  return { data: payload.data, observedAt: new Date().toISOString() };
}

CAPACITY_QUERY should be the version-controlled GraphQL document shown above. Validate numeric fields as finite, non-negative values before calculating. A syntactically valid JSON object with an unexpected schema is not a healthy sample.

Calculate concurrency without confusing slots

At Grid level, current concurrency is sessionCount. The reported maxSession is the direct ceiling for the aggregate utilization calculation. Guard division by zero and present both numerator and denominator:

TypeScript
export function utilization(sessionCount: number, maxSession: number) {
  const used = Math.max(0, sessionCount);
  const limit = Math.max(0, maxSession);
  return {
    used,
    limit,
    available: Math.max(0, limit - used),
    ratio: limit === 0 ? null : Math.min(1, used / limit),
  };
}

Display totalSlots separately as configured slot inventory. A Node can expose several browser stereotypes while a lower Node-wide maximum restricts simultaneous sessions. Using total slots as the denominator can make a saturated Grid appear underused.

At Node level, calculate sessionCount / maxSession, then annotate status and slot count. Exclude unavailable Nodes from ready capacity. Treat draining capacity as currently occupied or retiring, not available for assignment.

Break capacity down by compatible stereotype

Global headroom cannot answer whether a Firefox-on-Linux request can start. Parse the documented stereotype representation defensively, normalize browser name, platform, and the approved scheduling capabilities, and group slots by that key. Keep the raw value for diagnostics when parsing fails.

For each group, show configured slots on UP Nodes, active matching sessions where the response model provides enough evidence, and Node-wide headroom. The usable value is bounded by both compatible free slots and the remaining Node maximum. Do not sum every stereotype independently when several share one Node concurrency cap.

Queue capabilities are the demand side of this calculation. Fetch sessionsInfo.sessionQueueRequests only for a protected diagnostic view or a targeted classifier, because request payloads may include names, URLs, provider options, and other sensitive values. Redact before storage.

Design panels around operational decisions

The first row should show fresh-sample time, Grid status, active sessions, concurrency limit, queue size, and unavailable or draining Node counts. A second view can group browser and platform capacity. A Node table should include status, active over maximum, slot count, URI or stable label, and last successful poll.

Avoid a decorative wall of gauges. Operators need to scan mismatches: queue growing while one browser group is full, a Node draining unexpectedly, advertised slots disappearing after a rollout, or session count staying high after jobs end.

Link a Node or session to its corresponding logs and traces using stable identifiers. The dashboard should lead into evidence, not reproduce every diagnostic system in one page.

Alert on sustained, fresh conditions

Choose thresholds from service objectives and measured session startup behavior rather than copying fixed numbers. Useful alert conditions include a queue that remains nonzero beyond the expected startup window, no UP Nodes for a required stereotype, sustained concurrency saturation, an unexpected fall in configured capacity, and samples stale beyond the poll policy.

Require multiple fresh observations or an explicit duration so one rollout tick does not page the team. Include Grid identity, affected stereotype, queue size, active and maximum sessions, Node statuses, first observed time, and dashboard link in the alert.

Do not claim a scheduler failure merely because global available capacity is positive. First prove that a queued request has a compatible free slot on an eligible Node. A dashboard that preserves this nuance shortens incident triage substantially.

Protect the GraphQL surface and its data

Expose GraphQL through the same authenticated, HTTPS-protected Router boundary as the rest of Grid. Do not publish it directly to an untrusted network. Apply a short request timeout and rate limits at the dashboard service so a broken poll loop cannot become control-plane load.

Node URIs, session metadata, capabilities, and queue requests can reveal internal topology or test data. Fetch the minimum schema, limit dashboard access, and define retention for derived metrics separately from raw responses. Never place Grid credentials in browser-delivered JavaScript; poll from a trusted backend.

Cache only briefly enough to absorb multiple dashboard viewers. Operational capacity must remain fresh, and each sample should carry both observation time and Grid identity to prevent cross-environment mixing.

Diagnose a broken dashboard by layer

An HTTP 404 usually points to the wrong Router, sub-path, or proxy route. A 401 or 403 is authentication or authorization. HTTP success with GraphQL errors indicates query-schema mismatch or invalid field selection. Valid data with impossible calculations indicates response validation or arithmetic defects.

If Node count drops, compare Grid deployment and registration logs before changing the dashboard. If counts disagree with the UI, make sure both are querying the same Grid endpoint and time. If polls overlap, abort or skip the older request; accepting a late response can move the dashboard backward in time.

When stereotype parsing fails, display that fact and retain the sanitized raw field. Silently assigning an unknown stereotype to "other" can hide the exact capacity a release removed.

Capacity dashboard checklist

  • Query only fields tied to panels, calculations, alerts, or drill-down.
  • Test the GraphQL document against the promoted Grid release.
  • Validate HTTP status, JSON, GraphQL errors, and required data.
  • Allow only one bounded poll in flight and timestamp every sample.
  • Keep the last good sample visible but clearly stale on failure.
  • Use maxSession, not total slot count, for concurrency utilization.
  • Preserve Node statuses instead of reducing them to online or offline.
  • Break demand and capacity down by compatible stereotypes.
  • Avoid double-counting stereotypes that share a Node-wide limit.
  • Protect GraphQL with server-side authentication, HTTPS, and rate controls.
  • Alert only on sustained conditions from fresh samples.

Make the dashboard explain the queue

The dashboard is complete when it can show not just that work is waiting, but whether the missing resource is concurrency, a compatible stereotype, an eligible Node, or fresh data. Query a narrow supported schema, validate every sample, and keep configured slots separate from executable capacity. That model gives operators a trustworthy starting point for scaling and failure analysis.

// LIVE COURSE / THE TESTING ACADEMY

Playwright Automation Mastery

Go beyond Selenium. Master Playwright with JS/TS in 90 days.

From the instructor behind this guide.

Playwright jobs are growing 8x faster than Selenium. 90 days / 75+ live hrs / Tue-Thu-Sat 7 AM IST.

Code PROMODE / 10% offJoin the batch

The Testing Academy editorial desk

Practical QA guidance built around test evidence, production tradeoffs, and interview-ready explanations.

Published July 11, 2026 / Reviewed July 11, 2026

PRIMARY REFERENCES

Verify the details at the source

QABattle guides are practical explanations. Product behavior, standards, and APIs can change, so use these primary references for the canonical details.

  1. 01
    Selenium documentation

    Selenium Project

    Canonical WebDriver, Grid, waits, element, and browser automation guidance.

  2. 02
    WebDriver standard

    W3C

    The browser automation protocol specification behind WebDriver implementations.

  3. 03
    GraphQL specification

    GraphQL Foundation

    The normative schema, operation, validation, and execution specification.

FAQ / QUICK ANSWERS

Questions testers ask

Where is the Selenium Grid GraphQL endpoint?

For a default local Grid it is commonly `/graphql` on the Router or Standalone address, such as `http://localhost:4444/graphql`. Account for any configured Grid sub-path or reverse-proxy route.

Which GraphQL fields show Grid utilization?

Use `grid.sessionCount` with `grid.maxSession` for current global concurrency, then inspect node-level `sessionCount`, `maxSession`, `slotCount`, status, and stereotypes for the distribution and compatibility detail.

Is totalSlots the same as maximum concurrent sessions?

Not necessarily. A Node can advertise multiple slot stereotypes while its `maxSession` limits simultaneous execution. Display both inventory and concurrency rather than using total slot count as the utilization denominator.

Can GraphQL return errors with HTTP 200?

Yes. A GraphQL response can contain an `errors` array even when the HTTP request succeeded. A poller must validate status, response shape, GraphQL errors, and required data before replacing the last good sample.

Why can the queue grow while Grid shows free capacity?

Global free capacity may belong to incompatible browser or platform stereotypes, a Node may be draining, or the sample may be stale. Compare queued capabilities with free compatible slots before declaring a scheduler fault.