Watch your Mac's screen on your iPhone.
Beam connects to a Mac running Beacon and plays its screen and audio, over your local network. It supports Picture-in-Picture, media controls, viewport locking, and quality selection. No cables, no cloud, no account, and nothing leaves your network.
You will also need Beacon , the free macOS companion app, on the Mac you want to stream from.
Getting a Mac screen onto an iPhone is the one mirroring direction Apple has never supported, and the features people find while looking all run the other way:
- AirPlay — iPhones send AirPlay, they never receive it. A Mac can AirPlay to an Apple TV, a compatible TV, or another Mac, but not to a phone.
- Sidecar — iPad only, always has been.
- iPhone Mirroring — shows your iPhone on your Mac. The opposite of this.
So: no cables, no cloud, no account, and on your own WiFi nothing leaves your network.
One honest limitation — Beam is a viewer, not a remote control. You watch your Mac, you don't drive it. For clicking and typing on a Mac remotely, a remote desktop app is the right category.
More detail: can you AirPlay Mac to iPhone? · using an iPhone as a Mac monitor · streaming from away from home
Why the source is here. Beam is on the other end of a link that carries your Mac's screen and audio. Publishing the code means you do not have to take our word for what it does with that. For actually using it, the App Store build is the one you want: it is signed, it updates itself, and building it yourself requires a paid Apple Developer account.
| Discovery | Bonjour, browsing for _beam._tcp on the local network |
| Transport | Network.framework over TCP, LAN only |
| Video | AVSampleBufferDisplayLayer for low-latency rendering, which also drives PiP |
| Audio | AVAudioEngine, Float32 PCM, A/V sync via host clock comparison |
| Pairing | Device keys held in the iOS Keychain |
| Purchases | StoreKit 2 |
There is no server between your phone and your Mac. Beam talks to Beacon directly.
Beam has two dependencies, both MIT licensed and both compatible with the AGPL:
| Package | Why |
|---|---|
| posthog-ios | Anonymous product analytics |
| PLCrashReporter | Pulled in transitively by PostHog for crash reports |
Everything in the streaming path is Apple frameworks. There are no third-party networking, video, or audio libraries.
The entire analytics surface is one small file, Beam/Analytics.swift,
readable in a minute. What it does:
- It is anonymous. No accounts, no email, no device identifiers, no PII.
- Screen view capture is off (
captureScreenViews = false). - Events are product counters like
stream_startedandstream_ended, with properties such as session duration, quality preset, and whether the unlock was purchased. - Nothing about what you are streaming is collected. No screen contents, no audio, no filenames, no window titles. Those never leave your local network at all.
- Data goes to
w.beamscreen.app, a self-hosted endpoint, not to PostHog's cloud.
- iOS 16.0 or later (the optional home screen widget needs a newer iOS)
- A Mac on the same network running Beacon
- Xcode 15 or later, if you are building rather than installing
Beam is free to use for 30 minutes per session, with a 24 hour cooldown between sessions. A
one-time in-app purchase (com.beam.ios.unlimited) removes the limit permanently. It is a purchase
rather than a subscription, so you pay once and that is the end of it. Current pricing is on the
App Store listing.
Session timing is stored in the Keychain so that it survives a reinstall. That code is in
Store/SessionManager.swift and, like everything else here, you can read exactly what it does.
git clone https://github.com/kevinerikjs/beam-ios.git
cd beam-ios
open Beam.xcodeprojSelect the Beam scheme and a real device as the destination, then Run.
The simulator works for most development: it shares the host's network stack, so Bonjour discovery, streaming from a Beacon host, and audio playback all function. Test on a physical device before shipping anyway, since PiP behaviour, background audio, thermals, and real network conditions are where simulator and device diverge.
Note that running your own build on your own phone needs a paid Apple Developer account. With a free provisioning profile the app expires and has to be re-signed every seven days.
Info.plist declares BeamFeedbackSecret as $(BEAM_FEEDBACK_SECRET), which is empty unless you
supply it. That is expected, and your build works fine without it: the feedback endpoint accepts
unsigned reports and only uses this value to mark one as coming from an official build.
Official builds supply it two ways:
# local archive xcodebuild archive -scheme Beam ... BEAM_FEEDBACK_SECRET=<value>
On Xcode Cloud it comes from a secret workflow environment variable of the same name, which
ci_scripts/ci_post_clone.sh writes into Info.plist before the build. Xcode Cloud exposes
workflow variables to that script but not to xcodebuild's build settings, which is why the
script exists rather than the substitution just working.
Beam/
├── BeamApp.swift
├── Views/
│ ├── HomeView.swift # Connection screen + start button
│ ├── StreamView.swift # Full-screen streaming view
│ ├── StreamOverlay.swift # Controls overlay (media keys, PiP, disconnect)
│ ├── PairingView.swift # Device pairing flow
│ ├── PaywallView.swift # Free tier limit / upgrade prompt
│ └── OnboardingView.swift
├── Streaming/
│ ├── VideoRenderer.swift # AVSampleBufferDisplayLayer wrapper
│ ├── AudioPlayer.swift # AVAudioEngine playback
│ ├── StreamReceiver.swift # Packet reassembly + video/audio dispatch
│ ├── VideoMotionDetector.swift # Auto video region detection
│ ├── PiPController.swift # Picture-in-Picture management
│ └── Protocol.swift # Wire protocol, kept in sync with beam-macos
├── Network/
│ ├── BonjourBrowser.swift # Discover _beam._tcp
│ └── ConnectionManager.swift # TCP connection lifecycle + auth
├── Pairing/
│ ├── PairingManager.swift
│ └── KeyStore.swift # Keychain-stored pairing credentials
└── Store/
├── StoreManager.swift # StoreKit 2 IAP
└── SessionManager.swift # Free tier timer
Streaming/Protocol.swift must stay in sync with its counterpart in
beam-macos. Changing one side alone breaks streaming,
so protocol changes need to land in both repos together.
Issues and pull requests are welcome. Before you start:
- Apple frameworks for anything in the streaming path. No third-party networking, video, or audio libraries. The dependencies below are the complete list and the bar for adding another is high.
- Swift concurrency (
async/await, actors) for asynchronous work. - Test on a real device with a real Beacon host. A PR that only compiles has not been tested.
- User-facing strings should be localizable (
String(localized:)) from the start. - Discuss larger changes in an issue first.
Contributions require agreeing to a short Contributor License Agreement , which is one line in your PR description. That document explains why, and the short version is that it is what keeps the dual licensing below possible.
| Document | What it covers |
|---|---|
| SECURITY.md | How to report a vulnerability privately, and which parts of Beam are worth looking at |
| LICENSE | The AGPL-3.0 text |
| COMMERCIAL-LICENSE.md | Using Beam without the AGPL obligations, and how to arrange that |
| CLA.md | The one line contributors add to a PR, and why it is needed |
| CODE_OF_CONDUCT.md | How people are expected to behave here |
| CLAUDE.md | Architecture rules and coding conventions |
Found a security problem? Do not open an issue. Read SECURITY.md and mail support@beamscreen.app instead.
Beam is dual licensed.
By default it is AGPL-3.0. You can use it, study it, modify it, and redistribute it, including commercially. What the AGPL asks in return is that if you distribute Beam or something derived from it, you publish your source under the AGPL too.
A commercial license is available if you want to build on Beam without those source disclosure obligations, for instance inside a closed source product. Terms are negotiable.
If that is you, mail support@beamscreen.app with the subject
Commercial license and a paragraph on what you are building. See
COMMERCIAL-LICENSE.md for the full picture.
The Beam and Beacon names, logos, and icons are not covered by the AGPL grant. Fork the code freely, but please ship it under your own name.
Copyright © Kevin Erik Iin.
| Branch | Purpose |
|---|---|
main |
Production. Any push triggers an Xcode Cloud build. |
develop |
Active development. Feature work and fixes go here. |
The Xcode Cloud workflow has a single ARCHIVE action and no post-actions, so a build produces an
archive in App Store Connect and stops there. It does not submit anything for review, which
still takes a deliberate step in App Store Connect. Worth knowing before you push to main, since
the trigger is any ref change on that branch rather than a merge specifically.