Last updated: 2026-06-08 ·
Effective date: 2026-06-08 ·
Contact: David Kaiser, fruitconnect@davidkaiser.dk Applications: FruitConnect for macOS (companion application) and FruitConnect for Meta Quest (Quest 2 / Pro / 3 / 3S)
Plain-language summary. FruitConnect streams your Mac's screen to a 2D panel inside Meta Quest. We do not collect analytics, telemetry, or behavioural data. We do not show ads. We do not sell, share, or rent your data. Your screen content, keystrokes, and files never reach any server we control.
What the app actually does:
Stores a per-installation device identifier and your paired Macs locally on the headset.
Relays encrypted pairing handshakes through a public mailbox endpoint when you pair over the internet (Remote Access).
Uses public STUN servers to negotiate a peer-to-peer WebRTC connection between Quest and Mac.
Communicates with Meta's In-App Purchase service if you upgrade to Pro.
Uploads a debug log only when you explicitly tap "Send debug log" in the macOS menu — never automatically and never on crash.
Meta Horizon Platform data we access (Data Use Checkup)
FruitConnect uses the following Meta Horizon Platform features, requested through Meta's Data Use Checkup. This section articulates, in Meta's own terms, every category of Developer User Data and User Data the app collects, uses, and processes; the numbered sections referenced below give the full technical detail.
Platform feature
Data we access
How we use it
Shared with third parties?
Retention
User ID
Your Meta user identifier.
Binds each paired Mac to your Meta account so a different account signed in on the same headset cannot inherit or access your saved pairings (anti-hijack security). See section 1.4.
No — never sent to any server we control.
Until you uninstall or switch Meta account (section 1.4).
User profile
Your Meta Horizon username (display name). This permission also exposes your profile photo, which FruitConnect does not access or use.
Shows your display name on your paired Mac(s) so you can see who is connecting; you can override it in Settings. See section 1.4.
No.
Same as User ID (section 1.4).
In-app purchases
A purchase request for the Pro SKU and a Meta-validated entitlement/receipt (Pro: yes/no).
Unlocks the optional Pro upgrade. See section 2.3.
No — billing details and purchase history are never sent to our servers.
Not stored by us.
Subscriptions
Your subscription status and billing-period start/end time for the Pro subscription, read from Meta.
Determines whether your Pro subscription is currently active so the app can unlock unlimited streaming. See section 2.3.
No.
Read at runtime; not stored on our servers.
FruitConnect does not use Meta's User age group data. The app serves a single audience rated 13+ (Teens & Adults) and applies no age-based logic in the app (see section 5, Children's privacy).
1. Data stored on your device
All data below is stored exclusively on your Quest headset. None of it leaves the device unless you take an action that requires it.
1.1 Device identifier
What: A randomly generated UUID created on first launch.
Where: Encrypted preferences on the headset.
Why: Identifies this Quest installation to a Mac it has paired with, so the Mac knows which device is reconnecting.
Retention: Until you uninstall the app. The app declares android:allowBackup="false", which means uninstalling permanently deletes this identifier.
1.2 Paired Macs
What: For each Mac you have paired: pairing ID, device name (your Mac's mDNS hostname), public key material, last-known transport (USB / Wi-Fi / internet), and capability flags.
Where:EncryptedSharedPreferences using AES-256-GCM for values and AES-256-SIV for keys, with a master key in the Android Keystore (hardware-backed where the headset supports it).
Why: Lets the app reconnect to a previously paired Mac without re-entering a code, and prove pairing identity using a zero-knowledge protocol.
Retention: Until you tap "Forget" on a Mac, "Forget All" in Settings, or uninstall the app.
Why: Restore your preferred settings between sessions.
Retention: Until you reset to defaults or uninstall.
1.4 Meta account identifier (v3.35+)
What: Your Meta user identifier (the User ID feature) and Meta display name (the User profile feature) as returned by the Meta Horizon Platform SDK on Quest.
Profile photo: The Meta User profile permission that returns your display name also grants access to your profile photo. FruitConnect reads and uses the display name only — it does not access, store, transmit, or display your profile photo.
Where: On Quest, in app-private storage. On Mac, alongside each paired-Quest record in macOS UserDefaults.
Why: Two reasons. (1) Security: each paired Mac record is bound to a specific Meta user so a different account logging into the same Quest hardware cannot inherit a previous user's pairings. On Quest, switching Meta accounts wipes the local paired-Macs list at next app launch. On Mac, every connect is gated on the incoming Quest's Meta user matching the stored value — mismatch automatically removes the pair. (2) UI: the Mac shows the Meta display name in its "Paired Quests" list so the Mac user can see who is connected, not just what device.
Wire-path: peer-to-peer ONLY. The Meta identifier never reaches any server controlled by the Licensor. It travels:
Over the encrypted LAN socket (ChaCha20-Poly1305-AEAD) directly between Quest and Mac, OR
Over the encrypted WebRTC DataChannel inside the rendezvous mailbox payload — which is itself ChaCha20-Poly1305-AEAD encrypted client-side BEFORE upload, so the rendezvous server only ever sees opaque ciphertext (zero-knowledge — see section 2.2.1).
Debug log redaction. The Meta identifier is explicitly excluded from every debug-log entry on both Quest and Mac. Diagnostic uploads (which only happen when you tap "Send debug log" — see section 2.4) therefore cannot leak the identifier even via the debug-log payload. Log entries say metaUser=(present) / metaUser=(absent) and (ids redacted from log) instead of the raw value.
Retention: On Quest, until you uninstall or switch Meta account (whichever comes first). On Mac, until you "Forget" the pair from the menubar, factory-reset the org, or uninstall the Mac app.
Permissions: This feature uses the OVR Platform SDK's logged-in-user API. On Meta Quest Store builds, the SDK returns the user info silently (entitlement-based access). On sideloaded / dev-mode builds without entitlement, the SDK returns no user info — the app continues to work with the legacy v3.34 device-only behavior (Mac shows "Quest 3" in the UI as before; no per-user security gate is applied to that pair).
2. Data sent over the network
2.1 Local network (LAN) pairing and streaming
When your Mac is on the same Wi-Fi or USB-tethered, all communication stays inside your local network.
Pairing: Bonjour / mDNS discovery; the pairing handshake (6-digit code or QR code) exchanges public keys directly between Quest and Mac.
Streaming: Encoded video frames sent from Mac to Quest over a direct TCP socket.
Input: Mouse and keyboard events sent from Quest to Mac over a separate TCP socket.
No server in this path. No traffic leaves your local network.
2.2 Internet pairing and streaming (Remote Access)
If your Mac is not on the same network, FruitConnect can connect over the internet.
Purpose: A zero-knowledge message-relay that lets Quest and Mac exchange short signaling payloads while neither side knows the other's IP yet.
What is sent: ChaCha20-Poly1305-encrypted signaling envelopes (WebRTC SDP offers/answers, ICE candidates), addressed by opaque mailbox keys derived locally on each device from your shared pairing token via HMAC-SHA-256. The pairing token itself never leaves your devices.
What the server stores: Up to 64 short encrypted messages per opaque mailbox key, automatically deleted after 120 seconds (whichever comes first). On disk, only a SHA-256 hash of the mailbox key is used as the filename — the raw key is never written to disk.
What the server cannot do: Cannot read the conversation, cannot impersonate either side, cannot link mailbox keys back to a specific user or device because keys rotate every 5 minutes.
Rate-limiting: Scoped per opaque mailbox key, not per IP — no IP address is hashed into rate-limit state.
Application-level logs: The application code does not write IP addresses or user identifiers to disk; rate-limiting state stores only SHA-256 hashes of opaque keys. Standard webserver access logs (containing IP, timestamp, and request path) are maintained automatically by the hosting provider's default rotation policy and used solely for abuse prevention; FruitConnect does not access, analyse, or export them.
2.2.2 STUN servers
Purpose: Help WebRTC determine each peer's public IP and negotiate a direct connection.
STUN endpoints used:
stun:stun.l.google.com:19302 (Google)
stun:stun1.l.google.com:19302 (Google)
stun:stun.cloudflare.com:3478 (Cloudflare)
stun:stun.1und1.de:3478 (1&1 IONOS)
stun:stun.t-online.de:3478 (Deutsche Telekom)
What STUN servers see: Your public IP and the source port of the STUN request. They cannot see media content. No third-party analytics are loaded from these endpoints.
2.2.3 TURN relay (optional, build-time)
If a TURN relay is enabled in this build (some networks behind symmetric NAT require it), encrypted media bytes may be relayed through the configured TURN provider. The TURN provider sees encrypted bytes only — they cannot decrypt video, audio, or input events.
2.2.4 Encrypted media stream
Once Quest and Mac have established a WebRTC connection (via the rendezvous mailbox and STUN), all video frames, input events, and control messages are end-to-end encrypted using DTLS-SRTP (the WebRTC standard). Neither we nor any third party can read the contents of this stream.
2.3 Meta Horizon Platform (In-App Purchases & Subscriptions)
If you tap the Pro upgrade button, or whenever the app checks whether your Pro subscription is active:
Endpoint: Meta's official In-App Purchase and Subscriptions service via the Meta Horizon Platform SDK.
What is sent (In-app purchases feature): A purchase request for the Pro SKU and your Meta Horizon entitlement.
What we receive (In-app purchases feature): A boolean entitlement (Pro yes/no) and a purchase receipt validated by Meta.
Subscriptions data (Subscriptions feature): Because Pro is a recurring subscription, the app reads your subscription status and billing-period start/end time from Meta to determine whether your Pro subscription is currently active and therefore unlock unlimited streaming. This is read at runtime on the device; it is not written to, aggregated by, or shared from any server we control.
What we send to our servers: Nothing. Your Meta account ID, billing details, subscription details, and purchase history are not shared with us.
2.4 Diagnostic and feedback uploads (opt-in, never automatic)
FruitConnect contains a "Send debug log" button (macOS menu) and a "Send Feedback" form (both platforms). These are the only ways the application transmits anything to a server controlled by the Licensor outside of the rendezvous mailbox described in section 2.2.
Trigger: A button tap by you. The application does not have a crash handler, an uncaught-exception handler, a scheduled background uploader, or any analytics/crash-reporting SDK that could collect or transmit data without an explicit tap. The presence or absence of crashes has no effect on what is sent.
Cross-device button: When sending a diagnostic from one device, you may opt in to also collecting the log from the other paired device. The other device receives the request over the established WebRTC DataChannel and uploads only after you confirmed the action that triggered the request — there is no out-of-band channel that lets the Licensor request a log from your device.
Trigger: Mac menu → "Send debug log" → fill in form → tap "Send".
What is sent:
Free-text fields you typed: name (≤100 chars), email (≤200 chars), message (≤8 000 chars), occurrence time/frequency.
Lifecycle counters: total app launches, number of unclean exits in the last 24 hours, a short description of how the previous session ended.
System info: macOS version, Mac model, locale, app version, screen resolution, and similar non-personal environment metadata (capped at 40 keys / 200 chars per value).
The contents of the rolling debug log file (plain text, capped at 5 MB on the client and 8 MB on the server). The log records what FruitConnect itself wrote — connection events, error messages, performance counters. It does not record screen content, keystrokes, mouse coordinates, clipboard data, file paths from outside the app sandbox, or anything you typed into other applications.
What the server stores: The metadata fields and the log file are written to a folder inside signal/diagnostic_inbox/, which is not exposed on the public web (HTTP access is denied by .htaccess); only the Licensor can retrieve submissions over an authenticated FTP channel. The application does not store your IP address with the submission — your IP is only used in-memory by the server to enforce rate limits, where it is hashed (SHA-256) and never written to disk in raw form. (The hosting provider keeps standard webserver access logs containing IP, timestamp, and request path on its own short rotation, used solely for abuse prevention; see section 2.2.1.)
Rate limiting: A maximum of 3 submissions per IP per 10 minutes is enforced to prevent abuse.
Retention: Each submission is automatically deleted 90 days after it is received. The exact deletion date is recorded in the metadata file alongside the submission as an expiresAt timestamp, and is also returned to the application in the upload response. Cleanup runs opportunistically on each new submission, so no separate scheduler is required. The Licensor does not aggregate, profile, or share these reports.
Trigger: "Send Feedback" form (Mac menu or Quest Settings) → fill in → tap "Send".
What is sent: Optional name (≤100 chars), optional email (≤200 chars), required message (≤8 000 chars), and a short string identifying which device sent it ("mac" or "quest"). No log file is attached.
What the server stores: A plain-text file with the four fields, inside signal/feedback_inbox/ (HTTP access denied; FTP-only retrieval). Your IP address is not stored with the submission (same handling as for diagnostic submissions: in-memory rate-limit hashing only).
Rate limiting: Max 5 submissions per IP per minute.
Retention: Each submission is automatically deleted 90 days after it is received. The deletion date is written into the file header as an Expires: line. Cleanup runs opportunistically on each new submission.
2.4.3 Your control
The buttons are clearly labelled. You can use FruitConnect indefinitely without ever tapping them, and nothing diagnostic-related leaves your devices.
Email and name fields in both forms are optional. If you leave them blank, the resulting submission contains only the technical content (log + system info for diagnostic; message text for feedback) — no information that ties it back to you personally.
All submissions auto-delete after 90 days regardless. To request earlier deletion of a previously sent submission (for example, under the GDPR right to erasure), email fruitconnect@davidkaiser.dk with the approximate time and a snippet of the message and it will be removed within 30 days.
3. Data we do not collect
To make this concrete, FruitConnect explicitly does not:
Track your usage, sessions, or session duration on a server we control.
Record, store, or transmit the contents of your Mac screen except as encrypted real-time frames in the active streaming connection.
Record, store, or transmit your keystrokes, mouse movements, or clipboard content except as encrypted real-time input events in the active streaming connection.
Read or transmit files, emails, or other documents from your Mac.
Use third-party analytics or crash-reporting SDKs (no Firebase, Crashlytics, Sentry, Bugsnag, Mixpanel, Amplitude, AppsFlyer, or Adjust). The "Send debug log" and "Send Feedback" buttons described in section 2.4 are the only mechanisms by which the application can transmit data outside the streaming session, and neither is invoked unless you explicitly tap it.
Show ads or use ad networks.
Sell, rent, license, or share any data with advertisers, data brokers, or third parties for marketing.
4. Permissions the app requests
Android permission
Why we request it
INTERNET
Required for Remote Access (internet pairing/streaming). Not used during LAN-only sessions.
ACCESS_NETWORK_STATE
Detect whether you are online before attempting Remote Access.
ACCESS_WIFI_STATE
Detect Wi-Fi changes to auto-upgrade from Remote Access to LAN when your Mac becomes reachable.
CAMERA (runtime prompt)
Scan the QR code shown on your Mac when pairing. The camera feed is processed locally on the headset by ML Kit's barcode scanner; no frames leave the device. Granted only when you open the QR-scan screen, and you can deny it and use the 6-digit code instead.
horizonos.permission.HEADSET_CAMERA
Quest-specific equivalent of the Android camera permission, required by the QR scanner.
com.oculus.permission.HAND_TRACKING
Allows the UI to respond to hand-tracking input as an alternative to controllers.
MODIFY_AUDIO_SETTINGS
Audio focus and volume control for Mac LAN audio playback (v4 protocol). Used for playback only — RECORD_AUDIO is intentionally not requested.
The app does not request microphone, location, contacts, calendar, storage, SMS, telephony, or any other permission.
5. Children's privacy
FruitConnect is not directed at children under 13. The Meta Horizon Store age rating for this app reflects this. We do not knowingly collect personal data from children. If you believe a child has used the app on your headset, uninstalling the app will permanently delete all locally stored data.
6. Your rights
You can at any time:
Delete a paired Mac — Settings → My Macs → "…" → Forget.
Delete all paired Macs — Settings → My Macs → "Forget All".
Reset all preferences — Settings → "Reset to defaults".
Permanently erase all locally stored data — Uninstall the app from Quest Home. Because allowBackup is disabled, no backup of FruitConnect data exists in your Meta account or any cloud.
For privacy questions or to exercise other rights, email fruitconnect@davidkaiser.dk and a response will be sent within 30 days.
If you are in the EU/EEA or UK, you have rights under GDPR including access, rectification, erasure, restriction, portability, and objection. Use the same email above to exercise these rights.
7. Data security
Paired Mac records are encrypted at rest using AES-256-GCM (values) and AES-256-SIV (keys), with a master key in the Android Keystore (hardware-backed where supported).
Pairing handshakes use X25519 (Curve25519) ECDH and HKDF-SHA-256 to derive session keys, with rendezvous-key addressing rotated every 5 minutes to prevent correlation attacks.
Signaling payloads exchanged through the rendezvous mailbox are encrypted client-side with ChaCha20-Poly1305 AEAD before upload.
Streaming media is end-to-end encrypted via DTLS-SRTP (the WebRTC standard).
The rendezvous mailbox enforces a 32 KB payload cap, a 64-message limit per opaque key, automatic deletion after 120 seconds, and per-key rate-limiting.
8. Open source attribution
FruitConnect is built on top of several open-source libraries (most notably WebRTC and its sub-components, plus Jetpack Compose, Kotlin, AndroidX, CameraX, and Google ML Kit on the Quest side). The complete list of components and their licenses is shipped with the application:
macOS: open the FruitConnect menu in the menu bar and click "Licenses" in the footer.
Quest: open Settings inside FruitConnect on the headset and tap "Open Source Licenses".
We may update this policy as the app evolves. The "Last updated" date at the top changes when we do. Material changes that affect what data is collected or how it is used will be highlighted in-app the next time you launch FruitConnect after the update is published.