Claude
Skills
Sign in
Back

expo-horizon

Included with Lifetime
$97 forever

Software Mansion's guide for migrating Expo SDK apps to Meta Quest using expo-horizon packages. Use when adding Meta Quest or Meta Horizon OS support to an existing Expo or React Native project. Trigger on: Meta Quest, Horizon OS, Quest 2, Quest 3, Quest 3S, VR app, expo-horizon-core, expo-horizon-location, expo-horizon-notifications, build flavors for Quest, panel sizing, VR headtracking, Horizon App ID, quest build variant, isHorizonDevice, isHorizonBuild, migrate expo-location to Quest, migrate expo-notifications to Quest, Meta Horizon Store publishing, or any task involving running an Expo app on Meta Quest hardware.

Web Dev

What this skill does


# Expo Horizon: Migrating Expo SDK to Meta Quest

Software Mansion's production guide for adding Meta Quest support to Expo apps using the [expo-horizon](https://github.com/software-mansion-labs/expo-horizon) packages.

**This skill does not bundle a copy of the docs.** For any task below, always webfetch the linked official README or Meta documentation page to get up-to-date installation steps, plugin options, API surface, and feature matrices. This skill only captures the decision tree, critical rules, and non-obvious gotchas that agents routinely miss.

## Decision Tree

```
What do you need to do?
│
├── Starting from scratch or adding Quest support to an existing Expo app?
│   └── Follow the "Setup Workflow" below (do NOT auto-install location or
│       notifications packages) and webfetch: expo-horizon-core README
│       ├── Install expo-horizon-core
│       ├── Configure the config plugin (horizonAppId, panel size, supportedDevices)
│       ├── Add quest/mobile build scripts
│       ├── Add runtime device detection (isHorizonDevice, isHorizonBuild)
│       └── Detect expo-location / expo-notifications, then ASK before migrating
│
├── Need location services on Quest?
│   └── Webfetch: expo-horizon-location README
│       ├── Replace expo-location with expo-horizon-location
│       ├── Review the feature support matrix
│       └── Guard unsupported calls (heading, geocoding, geofencing, background)
│
├── Need push notifications on Quest?
│   └── Webfetch: expo-horizon-notifications README
│       ├── Replace expo-notifications with expo-horizon-notifications
│       ├── Configure horizonAppId in expo-horizon-core
│       ├── Use getDevicePushTokenAsync (Expo Push Service is not supported)
│       └── Skip badge counts (not supported on Quest)
│
└── Need to build, run, or publish for Quest?
    └── Webfetch: expo-horizon-core README (build variants) + Meta docs below
        ├── Build variants: questDebug, questRelease, mobileDebug, mobileRelease
        ├── Meta Quest Developer Hub (device management, sideloading)
        └── Meta Horizon Store manifest requirements
```

## Setup Workflow (adding Quest support to an existing Expo app)

Follow these steps **in order** when the user asks to add Meta Quest support. Do not combine steps 2 and 3 into a single install command — the sibling packages require explicit user confirmation.

1. **Install and configure `expo-horizon-core`.**
   - Run `npx expo install expo-horizon-core`.
   - **Ask the user for the config plugin values before writing them.** Present all options in a single prompt so the user can paste custom values or accept defaults in one pass. Show each option on its own line with its default in brackets, e.g.:
     > I'll add the `expo-horizon-core` config plugin to `app.json`. Please confirm or override each value (press Enter / reply "default" to accept the bracketed default):
     >
     > - `supportedDevices` [`quest2|quest3|quest3s`] — pipe-separated Quest devices your app supports (**required** for Meta Horizon Store submission).
     > - `horizonAppId` [empty] — Meta Horizon application ID. Leave empty unless you plan to use push notifications; required by `expo-horizon-notifications` to issue device push tokens.
     > - `defaultWidth` [`1024dp`] — Default panel width. Leave blank to omit.
     > - `defaultHeight` [`640dp`] — Default panel height. Leave blank to omit. If you set width/height, make sure your Expo `orientation` matches (use `"landscape"` for wide panels).
     > - `disableVrHeadtracking` [`false`] — Set `true` to omit the `android.hardware.vr.headtracking` manifest entry.
     > - `allowBackup` [`false`] — Meta recommends `false` for sensitive data; set `true` only if you need Android backup in the Quest build.
   - Only write the plugin config after the user replies. Omit any option the user left blank so the package's own default applies (don't write empty strings for `horizonAppId`, `defaultWidth`, or `defaultHeight`).
   - Add `quest` / `mobile` build scripts to `package.json`.
   - Run `npx expo prebuild --clean`.
   - Webfetch the [expo-horizon-core README](https://github.com/software-mansion-labs/expo-horizon/blob/main/expo-horizon-core/README.md) for current option names and defaults before asking — the defaults above can change between releases.

2. **Detect existing location / notification packages. Do NOT install the horizon equivalents yet.**
   - Read the project's `package.json`.
   - Check `dependencies` and `devDependencies` for `expo-location` and `expo-notifications`.
   - If neither is present, skip the rest of this workflow — the user has no migration to do.

3. **For each detected package, ask the user before migrating.**
   - If `expo-location` is found, ask:
     > "I found `expo-location` in your project. Do you want me to replace it with `expo-horizon-location` so location works on Meta Quest? (Quest has no GPS, heading, geocoding, or geofencing — unsupported calls will need to be guarded with `ExpoHorizon.isHorizonDevice`.)"
   - If `expo-notifications` is found, ask:
     > "I found `expo-notifications` in your project. Do you want me to replace it with `expo-horizon-notifications` so push notifications work on Meta Quest? This requires a `horizonAppId` in the core config plugin, uses Meta's push service (not the Expo Push Service), and does not support badge counts or `getExpoPushTokenAsync`."
   - Present the questions together if both packages are present.
   - **Wait for an explicit answer before running any install or edit for these packages.**

4. **Only after the user confirms**, perform the migration for the approved package(s):
   - Install the horizon equivalent (`npx expo install expo-horizon-location` or `expo-horizon-notifications`).
   - Uninstall the original (`npm uninstall expo-location` or `expo-notifications`).
   - Update all `import` statements to the horizon package name.
   - For notifications: ensure `horizonAppId` is set in the `expo-horizon-core` plugin config and add `expo-horizon-notifications` to the plugins array.
   - Run `npx expo prebuild --clean` again.
   - Webfetch the relevant README (location or notifications) for the full feature support matrix and guard unsupported calls behind `ExpoHorizon.isHorizonDevice`.

5. **If the user declines a migration**, leave the original package untouched and note in the summary that feature X (location / notifications) will not work on the `quest` build until migrated.

## Critical Rules

- **Always install `expo-horizon-core` first.** It is required by all other expo-horizon packages and sets up the `quest`/`mobile` build flavors that other packages depend on.

- **Never auto-install `expo-horizon-location` or `expo-horizon-notifications`.** When adding Quest support, detect existing `expo-location` / `expo-notifications` dependencies in `package.json` and ask the user whether to migrate each one. Install and configure only the packages the user explicitly approves. See the Setup Workflow above.

- **Use `quest` build variants only on Meta Quest devices.** Running `questDebug` or `questRelease` builds on standard Android phones is unsupported and will behave unexpectedly.

- **Set `supportedDevices` in the config plugin.** This is required for Meta Horizon Store submission. Use pipe-separated values: `"quest2|quest3|quest3s"`.

- **Run `npx expo prebuild --clean` after any plugin config change.** The config plugin modifies native project files at prebuild time. Stale native projects will not reflect your changes.

- **Replace imports, not just packages.** When migrating from `expo-location` or `expo-notifications`, update all import statements to use the new package names (`expo-horizon-location`, `expo-horizon-notifications`).

- **Quest has no GPS, magnetic sensors, or Geocoder.** Features like heading, geocoding, reverse geocoding, and geofencing are unavailable on Quest. Guard these calls with `ExpoHorizon.isHorizonDevice` or `ExpoHorizon.isHorizonBuild`.

- *
Files: 1
Size: 11.0 KB
Complexity: 20/100
Category: Web Dev

Related in Web Dev