iOS Simulator · Free

A working camera in the iOS Simulator

Updated August 2026

AVCaptureDevice returns nothing in the Simulator, so every camera screen you build — QR scanners, ID capture, avatar pickers — gets stubbed out or forces you onto a real device. Buoy fabricates a camera the Simulator does not have. Point it at your Mac screen, a webcam, an image, a video, or a barcode it generates for you, and your app sees an ordinary camera. Your code does not change, and there is nothing to install in your app.

Pick what the camera should show. That is the whole setup.

Open Buoy Desktop, choose Simulator Camera, and click a source. That click turns the camera on for that simulator — so anything it launches afterwards has one, whether you start your app with npx expo start, react-native run-ios, Xcode or a test runner. Then run your app the way you always do.

There is no second confirm step and no launcher to choose. The panel then answers the only question worth asking — “Your app is receiving it” — so you are never left guessing whether it worked or whether you are staring at a camera pointed at something dark.

One caveat, and it is a property of the platform rather than of Buoy: a camera is attached when a process starts. An app that is already running will not suddenly have one, and a Fast Refresh reload is not enough — the process has to be new. Changing the source afterwards is instant and needs no relaunch at all.

Six things it can be

A region of your Mac screen

Drag a rectangle onto anything on your desktop — a QR code in your browser, a photo of a licence, an invoice in Preview — and that is what the phone’s camera sees. Resize it from its handles, move it, and the framing follows on the next frame.

A webcam

Your Mac camera, straight through. The right one for testing a selfie flow, face detection or anything that needs a real moving human in frame.

A generated barcode

Type a payload, pick QR, PDF417, Aztec or Code 128, and it is on the camera a moment later. Swap the text to test the next case — no printing, no finding a fixture.

An image

Any file on disk, held steady in frame. Fixtures that never drift, which is what makes a scanner test repeatable.

A video

A recorded clip on loop, for flows that need motion rather than a still.

A test pattern

A generated pattern, for proving the pipeline works before you blame your own code.

Point the phone at your own screen

This is the part that has no equivalent on a real device. Choose the screen source and your own Mac becomes the viewfinder: point it at a QR code on a web page, a driver's licence in Preview, a boarding pass in your email — and your app scans it. No printing, no second device, no holding a phone up to a webcam.

You aim it with a region: a dashed rectangle you drop anywhere on your desktop, above every window, with eight handles to resize it — the same gesture as a Mac screenshot, except it stays there and streams. Drag its middle to move it, press Escape to dismiss it. Turn on click-through and you can keep scrolling the page it is pointed at while it films.

Resizing snaps to 16:9, because that is the only shape the camera has — the fabricated device advertises a single 1280×720 format, so a region of any other shape arrives centred inside a 16:9 frame with black bars. Hold Shift while resizing for a free-form region anyway.

That rectangle is the only screen target the panel offers, on purpose: aiming at a whole display or a named window meant the camera was rarely looking at the thing you actually wanted. The CLI still takes them — behind, display and window:<id> — for CI, where nobody is there to drag anything.

Buoy's own windows and the Simulator are excluded from the capture. That is not cosmetic: include the Simulator and it films itself, include Buoy and the live preview appears inside the frame it is previewing. Either one is an infinite mirror. It is also what keeps the region's dashed border and handles out of the shot.

Barcodes, not just QR

Anything read through AVCaptureMetadataOutput works: QR, PDF417 — the barcode on the back of a US driver's licence — Aztec, DataMatrix, EAN-8/13, UPC-E, Code 128, Code 39, Code 93 and ITF. Your onBarcodeScanned fires exactly as it would on a device.

Detection runs on your Mac rather than inside your app, and that is a deliberate consequence of a real limitation: Vision's barcode detector cannot create an inference context inside the iOS Simulator, so an in-process decoder could only ever manage QR. Doing it host-side gets the whole family and keeps the per-frame cost out of your app's process entirely.

Nothing goes into your app

This is the one Buoy tool with no npm package. There is no provider to mount, no config plugin, no prebuild — and it works on any booted simulator app, including apps that have never heard of Buoy. You can point it at a build from another team, or at a release binary, and it still has a camera.

Buoy loads a small library into the simulator at launch. It fabricates two capture devices and implements enough of the AVFoundation capture graph that real camera libraries build a session around them; a helper on your Mac captures the source you picked and publishes frames into shared memory. Because the fabrication happens at the system framework level, what you build on top of it does not matter — React Native, Flutter, UIKit or SwiftUI all go through the same API.

What has actually been verified

Framework-level fabrication means most things are expected to work. This table lists only what has actually been run, because expected and tested are not the same claim:

LibraryVerifiedWhat was exercised
expo-cameraYesPreview, takePictureAsync, barcode scanning
react-native-vision-cameraYesDevice list, preview, its hand-built capture graph (v5)
AVCaptureSessionYesUIKit and SwiftUI — exercised by the test suite on every run
cameraYesFlutter's plugin — preview, frame stream, photo capture, video recording
WebRTC / AgoraNoNot attempted. Both need live infrastructure to test honestly

Libraries that refuse to look

A few camera libraries decide at compile time that a simulator has no camera, so they never ask for one — a fabricated device is invisible to them however well it works. buoycam patch finds them and, where the fix is purely mechanical, applies it:

buoycam patch          # what is installed, and what is affected
buoycam patch apply    # fix what can be fixed safely

expo-camera was fixed upstream in 55.0.11 and react-native-vision-camera in 5.0, so for those the answer is usually just to upgrade. Only the mechanical case is rewritten automatically, only when the guard matches exactly, and the original is kept alongside — where upstream restructured the file, Buoy says so and points at the release instead of improvising inside your node_modules.

For terminals, CI and coding agents

Everything the panel does is also a command, with --json on all of it:

buoycam source barcode "hello"       # or: camera, image, video, screen, pattern
buoycam source barcode "DL@ANSI…" --format pdf417
buoycam codes                        # what it is decoding right now
buoycam diagnose                     # why isn't this working

diagnose exists because “it is not working” has several very different causes, and it names which one: nothing is publishing, something is publishing but your app is not reading it, the library never loaded into that process, or another tool has claimed the simulator. It exits non-zero when something is broken, so it works as a CI gate rather than as something to read.

In CI there is no licence to activate and no token to store. The generated barcode, image, video and test-pattern sources all work without a logged-in desktop session; the webcam and screen sources do not, because both need a real session and a permission a headless runner cannot grant. For scanner tests — which is most of what CI wants a camera for — the generated barcode source is the right one anyway.

Buoy's MCP server exposes the same four actions, so an agent can set up a scanner test without being told how: camera_source, camera_status, camera_launch and camera_diagnose.

Limits, stated plainly

  • iOS Simulator only. Not physical devices — an app's camera access there is outside any debugging tool's reach. The Android emulator already supports webcams natively.
  • No video recording. AVCaptureMovieFileOutput is not implemented; preview and still capture are.
  • Front and back cameras show the same feed.
  • GS1 DataBar and the Micro symbologies are not mapped, though the rest of the family is.
  • Only one tool can own the simulator's injection at a time. If another simulator-camera app is running, quit it first.

Can the iOS Simulator use a camera?

Not on its own — AVCaptureDevice returns no devices, which is why camera screens have to be stubbed or tested on hardware. Buoy fabricates one by loading a small library into the simulator at launch, so your app sees an ordinary capture device and your code does not change.

Can I scan a QR code or a driver’s licence in the Simulator?

Yes. Either generate the code from text you type, or point the camera at your own Mac screen and drag the simulator window over a code in your browser or a licence photo in Preview. QR, PDF417, Aztec, DataMatrix, EAN/UPC, Code 128, Code 39, Code 93 and ITF all decode.

Do I have to install anything in my app?

No. This is the one Buoy tool with no npm package — no provider, no config plugin, no prebuild. It works on any booted simulator app, including apps that have never heard of Buoy.

Does it work with expo-camera and react-native-vision-camera?

Yes — both are verified, including preview, still capture and barcode scanning. Some versions of those libraries decide at compile time that a simulator has no camera; expo-camera fixed that in 55.0.11 and vision-camera in 5.0, and `buoycam patch` handles older ones.

Does it work in CI?

Yes, for the generated barcode, image, video and test-pattern sources — there is no licence to activate and no token to store. The webcam and screen sources need a real logged-in session, so they cannot run on a headless runner.

Is it free?

The camera itself is free: the Mac camera, image, video and test-pattern sources, and generating and scanning QR codes, all work with no licence. Buoy Pro adds the screen region, the non-QR symbologies (PDF417 for driving licences, Aztec, DataMatrix, Code 128) and driving the camera from a coding agent over MCP.

Give your Simulator a camera

No package, no config plugin, nothing in your app. Free on any booted simulator app; Pro adds the screen region, ID barcodes and agent control.

Quick startbuoycam source barcode "hello"