On Runtime the CPU metric is the same reading the bill is made from. The host measures each running sandbox's CPU time at least every half minute, and Runtime charges $0.025 per active vCPU-hour of that measured CPU, with a floor of 50 millicores (pricing). So the chart that shows a sandbox idling also shows why it costs little: a 2 vCPU, 4 GiB sandbox that waits costs $0.03125 an hour, and $0.08 with both CPUs busy. Metrics, events and export cost nothing extra (metrics and webhooks).
Read them
TypeScriptimport { Sandbox } from "withruntime";await using sbx = await Sandbox.create();await sbx.exec("python3 -c 'sum(i * i for i in range(10**8))'", { timeoutMs: 120_000 });const m = await sbx.metrics({ range: "15m" });console.log(m.latest?.cpuPercent, m.latest?.memoryBytes);for (const p of m.points) console.log(p.at, p.cpuCores, p.cpuPeakPercent, p.memoryPeakBytes);Pythonfrom withruntime import Sandboxwith Sandbox.create() as sbx: sbx.exec("python3 -c 'sum(i * i for i in range(10**8))'", timeout_ms=120_000) m = sbx.metrics(range="15m") latest = m["latest"] if latest: print(latest["cpuPercent"], latest["memoryBytes"]) for point in m["points"]: print(point["at"], point["cpuCores"], point["memoryPeakBytes"])Terminalnpx withruntime sandboxes metrics <id> --range 6hThe same readings appear as charts on the Metrics tab of a sandbox's page in
your account, under Sandboxes. The
sandbox list also shows each sandbox's current CPU and memory. An agent reads
them with the runtime_sandboxes_metrics MCP tool.
What each field means
| Field | Meaning |
|---|---|
cpuPercent |
CPU in use as a percent of all the sandbox's vCPUs, 0 to 100 |
cpuCores |
The same, as a number of cores |
cpuPeakPercent |
The busiest interval between two readings inside the bucket |
memoryBytes |
Memory the sandbox's machine holds, as its host measures it |
memoryPeakBytes |
The most it held inside the bucket |
diskUsedBytes |
Bytes used on the root file system, as df / in the sandbox reports |
latest |
The newest reading while the sandbox runs; null when it is not running |
Each point also has the disk's reads and writes (diskReadBytesPerSecond,
diskWriteBytesPerSecond, diskReadOpsPerSecond, diskWriteOpsPerSecond)
and the network's traffic (networkReceivedBytesPerSecond,
networkSentBytesPerSecond). Each is null where it was not measured
(all the fields).
range sets the window. Each point sums one bucket:
range |
Bucket | Kept for |
|---|---|---|
15m |
10 seconds | 24 hours |
1h |
20 seconds | 24 hours |
6h |
2 minutes | 24 hours |
24h |
8 minutes | 24 hours |
7d, 30d |
1 hour | 30 days |
Size a sandbox from its readings
You choose a sandbox's size with vcpu and memoryMiB. The readings show
whether you chose well:
- Memory. Memory is billed on the amount you reserve, at $0.0075 per
GiB-hour. If the largest
memoryPeakBytesover a week of runs is 1.2 GiB, a 2 GiB sandbox can run the same work as a 4 GiB one, at half the memory charge. The response also includesmemoryLimitBytesfor comparison. - CPU. CPU is billed on use, so extra vCPUs cost nothing while idle. A
cpuPeakPercentnear 100 during builds or tests means that morevcpuwould finish the work sooner. The bill follows the work done.
TypeScriptimport { Sandbox } from "withruntime";const sbx = await Sandbox.connect("<sandbox id>");const week = await sbx.metrics({ range: "7d" });const peak = Math.max(0, ...week.points.map((p) => p.memoryPeakBytes));console.log( `peak ${(peak / 2 ** 30).toFixed(2)} GiB of ${(week.memoryLimitBytes / 2 ** 30).toFixed(0)} GiB`,);To see what you were charged, per resource, runtime usage and
GET /v1/usage both return the settled figures.
Send them to your own dashboards
An OpenTelemetry export sends every sandbox's readings as OTLP gauges, about every 30 seconds, to Grafana, Honeycomb, Datadog, New Relic, or any endpoint that accepts OTLP over HTTP:
TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();await runtime.otel.create({ endpoint: "https://api.honeycomb.io", headers: { "x-honeycomb-team": process.env.HONEYCOMB_KEY ?? "" }, signals: ["metrics"],});The gauges are runtime.sandbox.cpu.utilization, runtime.sandbox.cpu.usage,
runtime.sandbox.memory.usage, runtime.sandbox.memory.limit,
runtime.sandbox.disk.usage and runtime.sandbox.disk.limit. The disk's and
the network's traffic are the sums runtime.sandbox.disk.io,
runtime.sandbox.disk.operations and runtime.sandbox.network.io. Each
sandbox is one resource, with its id, name, vCPUs and region. Add "traces"
to signals for a span of every API call. An account can have three exports
(OpenTelemetry export).
Mistakes and how Runtime handles them
- Reading
cpuPercentas per core. It is a share of all the sandbox's vCPUs. On a 2 vCPU sandbox, 50 means one core busy;cpuCoressays 1. - Expecting readings from a paused sandbox. A paused or stopped sandbox
has no new readings, and its earlier ones stay.
latestis null while it is not running. - Looking for last month's detail. Each reading is kept 24 hours, and hourly averages and peaks 30 days. Export them to keep more.
- Code written for E2B. Its
getMetrics()works throughwithruntime/e2band reads these same values,diskUsedincluded.
Related
- Receive webhooks to hear when a sandbox stops.
- Pause and resume a sandbox when the readings show it waiting.
- The sandbox cost calculator.
Start
Terminalprintf '%s\n' 'print(sum([125, 250, 375]))' > invoice.pynpx withruntime sandboxes run --keep -- python3 - < invoice.pyA new account gets 100 free hours of a 1 GB machine in its first 30 days, with no card. Then run
runtime sandboxes metrics <id> on the kept sandbox.
Facts on this page were checked on 26 October 2026.