Guides
Environments & build channels
Every way your app reaches a device already has a name — Xcode, an install link, TestFlight, the App Store. Pharen names who each build went to, maps each one to an environment for you, keeps test traffic out of your customer numbers by default, and flags the one mistake that ships silently: a test key baked into a store build.
The mapping
You never assign any of this. The environment follows the ingest key baked into each build configuration — wiring your tooling generates — and Pharen reads the channel from the build itself at runtime.
The channel answers one question: who was this build distributed to? debug — developers, as a debug, simulator or development-signed build; tester — your testers, whether a handful of teammates or a public TestFlight link; store — the public, through a storefront; enterprise — your organization's own people, through an in-house profile; sideload — whoever installed it directly, with no storefront behind it, such as from your website. Alongside it, the distributor says who supplied the build — apple for the App Store, testflight, or other for an alternative marketplace. Both are dimensions you can group and filter by.
| How the build reaches a device | Environment | Channel — who it went to | In your metrics |
|---|---|---|---|
| Run from Xcode — you, on a simulator or a cable | development | debug | Kept out of customer numbers automatically |
| Install link — teammates and test devices, many builds a day | staging | tester for an ad-hoc build; debug for a development-signed one | Never mixed into production; visible to your team in staging |
| TestFlight — your beta testers, release candidates | production | tester, supplied by testflight | In production, but excluded from customer-facing numbers by default — one filter away when you want testers included |
| App Store — your customers | production | store, supplied by apple | Your customer-facing numbers; the default everywhere |
TestFlight and the App Store ship the same Release artifact, so they share the same production key on purpose: a TestFlight crash is a production-code crash you get to see before the public does. What separates testers from customers in your metrics is the channel, not the environment — customer-facing metrics default to builds that actually reached the store, so TestFlight sessions never inflate them, and a single group-by shows testers when you want them.
Two witnesses, one guard
The environment and the channel come from different places, deliberately:
- The key asserts the environment. It's compiled into the build and resolved on the server — a build cannot claim its way into your production data at runtime, and a leaked test key can be revoked without touching production.
- The build confesses its channel. At runtime the SDK reads how the binary was actually distributed — a debug build, an ad-hoc profile, a TestFlight install, the App Store — and reports it with every event.
Because the two are independent, Pharen can check them against each other. That's the guard:
Honest edges
- Web has no install channel. A browser build carries no receipt and no profile, so your key's environment is the whole story there.
- Internal vs. external TestFlight isn't knowable on-device. Both install identical builds, so Pharen reports a
testerbuild supplied bytestflight— never which tester group. Nothing on this page promises that split, because no app can detect it. - A channel can be unknown. When a build carries no distribution signal at all, Pharen says so rather than guessing — an unknown channel never trips the guard and never masquerades as customers.