There is a drawer in most mobile teams' offices. Mine had fourteen phones in it.
Two iPhones were frozen on old iOS versions with updates blocked, because you can't roll iOS back. An iPad nobody had charged in months. A few Android devices we kept around because one manufacturer had shipped an interesting bug.
And the drawer only helped people who could already build the app. Everyone else had to interrupt a mobile developer just to see a build running.
That's what we set out to fix. Carbon had nothing to do with it.
We looked at hosted device clouds first and stopped before signing up. The price scaled with the team, and our app binary would have to leave our network. So we built tapflow instead: an open-source, self-hosted tool that streams iOS simulators and Android emulators into the browser, so anyone on the team can test a build from a URL.
But while working on it, I realized that if the answer to "we don't have enough test devices" is "buy fewer test devices," there's another consequence besides the budget. Most of a phone's carbon footprint is already there before anyone starts using it.
Most of a device's carbon comes from manufacturing
| Device | Total LCA | Production share |
|---|---|---|
| iPhone 17 (256 GB) | 55 kg | 76% |
| iPad (A16, 128 GB) | 74 kg | 74% |
| Mac mini (M4) | 32 kg | 74% |
| MacBook Pro 14" (M2 Pro) | 243 kg | 79% |
Three quarters or more of each device's lifetime footprint comes from production.
That changes how I think about test hardware. Using a phone more often doesn't make its manufacturing footprint worse, and leaving it in a drawer doesn't make it better. That carbon was already emitted when the device was manufactured.
So a test phone used twice a month is particularly inefficient from a hardware-utilization perspective: almost the full manufacturing footprint, for very little actual use.
The two sides also age differently.
Test devices get replaced because of OS support windows and the need to validate new releases. That's the same reason two iPhones in my drawer had their updates permanently blocked.
A machine hosting simulators has less of that pressure. It's mostly memory-bound, runs headless, and can stay in service until its macOS version can no longer run the Xcode version you need.
Over eight years, replacing four test devices accounts for 444 kg of manufacturing carbon. One MacBook Pro accounts for 196.8 kg once.
So the question I became interested in wasn't how efficiently we test. It was how much hardware we had to buy to test at all.
The arithmetic
Take a team that needs coverage equivalent to four test devices — say three iPhones and an iPad.
They can buy those devices, or run four simulators on a Mac they already own. Four is about the practical ceiling on a 32 GB host.
For comparison, I annualised everything.
Manufacturing carbon comes from Apple's per-product environmental reports, divided by expected service life using Apple's own assumptions: three years for an iPhone, four years for an iPad and a Mac.
For electricity, I used Korea's grid factor of 417.3 gCO₂e/kWh.
The model assumes 1,000 session hours per year, with 30% of that time spent actively interacting with the app. The active power figure is measured rather than estimated; the commands to reproduce that measurement are near the end of this post.
| 4 physical devices | tapflow (Mac already owned) | |
|---|---|---|
| Manufacturing, annualised | 55.5 kg | 0 kg |
| Electricity | 12.7 kg (30.4 kWh) | 17.9 kg (42.9 kWh) |
| Total | 68.2 kg/yr | 17.9 kg/yr |
That's 3.8× less in this model.
Almost all of the difference is the manufacturing row: 55.5 kg versus zero. Not because simulators use less electricity, but because the Mac already exists.
Electricity actually goes the other way
A Mac left powered on uses more electricity over a year than charging four phones.
I think that's important to keep in the comparison. If I removed it, the result would look better, but it would also hide one of the more useful findings from the measurement.
It also doesn't change the result much.
About 86% of the Mac's 42.9 kWh comes from the machine simply being powered on, not from simulator activity. Even if I scale the measured per-simulator cost linearly to four simulators, the annual total only moves by about a kilogram of CO₂e.
So this isn't really an energy-efficiency argument.
It's a hardware-utilization argument, and most of the carbon in this comparison comes from manufacturing the hardware.
I tried changing the weak assumptions
There are two inputs I'm least confident about: how per-simulator power scales beyond one simulator, and how often a test device actually gets charged.
I varied both.
| Simulator increment | Device charging | tapflow | Devices | Ratio |
|---|---|---|---|---|
| ×1 | daily | 16.0 kg | 68.2 kg | 4.3× |
| ×2 | daily | 16.7 kg | 68.2 kg | 4.1× |
| ×4 (linear, most conservative) | daily | 17.9 kg | 68.2 kg | 3.8× |
| ×4 | 3×/week | 17.9 kg | 60.9 kg | 3.4× |
The result stays between 3.4× and 4.3× across those cases.
The 3.8× headline number uses linear scaling for four simulators, which is the conservative assumption here.
There are also a few reasons the measurement may overstate tapflow's actual cost.
I measured with the browser decoding the stream on the same Mac, while in normal use decoding happens on the tester's machine. The active measurement was sixty seconds of continuous scrolling, which is much heavier than typical QA. And I treated multi-simulator power as linear even though the measurements are dominated by idle power.
An earlier version of this calculation didn't measure the active cost at all. I guessed 30 W. The measurement came back at 4.52 W — wrong by more than a factor of six, in the direction that made our own case look worse. That's why the number in the table is measured rather than estimated.
Where this stops being true
If you buy a Mac for this, you've bought hardware.
The zero in the manufacturing row only applies when the Mac already exists. If you buy a host specifically for tapflow, its manufacturing carbon has to be included. Against the four devices' 55.5 kg/year, a Mac mini breaks even in roughly six months and a MacBook Pro in about three and a half years.
The difference is large because a laptop includes a display and battery that a simulator host doesn't need. Its manufacturing footprint is roughly seven times that of a Mac mini. If you're buying a dedicated host, the Mac mini is the better choice.
It doesn't replace every device.
tapflow can't test features that depend on device hardware such as cameras, NFC, or biometrics. Teams that need those still need real devices. The question is how many devices you need, not whether you can eliminate them entirely.
Grid factors are regional.
These numbers use Korea's electricity mix. On a cleaner grid, both electricity rows shrink while the manufacturing comparison stays the same.
Old Macs have a floor.
An iOS simulator needs a recent Xcode, and Xcode needs a recent macOS. A Mac that can't run the required versions can't be used as an iOS simulator host, even if the hardware itself still works.
And tapflow is v0.x.
We use it every day and it's under active development. Plan accordingly.
What I'm deliberately not claiming
This is not an SCI score.
The Software Carbon Intensity specification, now ISO/IEC 21031:2024, measures emissions attributable to software: the energy it consumes plus the embodied carbon of the hardware allocated to it. It doesn't include a term for hardware that was never purchased.
Avoided emissions are outside that model, and the specification explicitly doesn't allow offsets or market measures to reduce the score. So the comparison in this post and an SCI score answer different questions.
If you run tapflow, its own SCI score isn't zero. There's still a Mac consuming electricity and carrying a share of its manufacturing footprint. Whether avoided emissions should count is a separate question, and I don't want to hide that distinction by folding them into a metric that wasn't designed for it.
I also can't give you a number against hosted device clouds.
It's an obvious comparison to want to make. A hosted service runs cloud infrastructure plus Mac hosts, while a self-hosted relay and agent can share one machine and stay on the LAN.
But the providers I looked at don't publish the information I'd need to calculate it: PUE, regional grid mix, or sessions per host. Without those numbers, a kilogram-for-kilogram comparison would be made up, so I'm leaving that one qualitative.
Measure it on your own host
The per-session power cost is the one input above that I measured directly.
I ran the test on a MacBook Pro 14" with an M2 Pro and 32 GB of memory, running macOS 26.5.2. One iOS simulator, the relay, and the agent were all running on the same host.
Each point uses 60 one-second samples from Combined Power (CPU + GPU + ANE):
sudo powermetrics --samplers cpu_power -i 1000 -n 60 \
| grep 'Combined Power (CPU + GPU + ANE)'
| Point | State | SoC power | Increment |
|---|---|---|---|
| A | No session | 0.66 W (sd 0.14) | — |
| B | Session open, screen static | 0.64 W (sd 0.29) | ≈ 0 |
| C | Session open, continuous scrolling | 5.16 W (sd 1.99) | +4.52 W |
Keeping a stream open adds effectively nothing in this measurement. A and B differ by −0.02 W, which is well inside the noise. That's consistent with how the H.264 stream behaves when the screen isn't changing: we had already measured roughly 2 MB/s for a still screen and 12–16 MB/s while scrolling.
During continuous interaction, the measured increment was 4.52 W at the SoC, or about 5.05 W at the wall after accounting for adapter efficiency.
powermetrics reports SoC power rather than the display, SSD, fans, and the rest of the system. That's useful here because I'm measuring the increment between states. The platform draw is present in A, B, and C, so it cancels out. For absolute draw, I used Apple's published wall-power figures instead.
If you already run a host, tapflow's built-in Mac resource monitoring also exposes CPU and memory series you can compare against your own workload.
The full calculation — inputs, sources, measurement conditions, sensitivity analysis, and the assumptions I discarded — is in sustainability-carbon-math.md.
There's also a shorter summary in the sustainability section of the docs.
npm install -g tapflow
tapflow start
- Repo: https://github.com/jo-duchan/tapflow — MIT, self-hosted; builds and streams stay on your own network
- Docs: https://www.tapflow.dev
The carbon in that drawer was spent years ago. Using those devices carefully can't undo it.
What we can change is what happens when those devices need replacing.
So if your team has a drawer like this, I'm curious: how many devices are in it, and how many days a month does each one actually get used?
I only have my own numbers.
Top comments (0)