> For the complete documentation index, see [llms.txt](https://mercure-technologies.gitbook.io/expo-open-ota/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mercure-technologies.gitbook.io/expo-open-ota/deployment/local-testing.md).

# Local testing

To test **Expo Open OTA** locally, use the provided Docker Compose file. It runs the server locally and exposes it through a reverse proxy such as ngrok.

### Clone the repository <a href="#clone-the-repository" id="clone-the-repository"></a>

```shellscript
git clone https://github.com/mercuretechnologies/expo-open-ota
cd expo-open-ota
```

### Set up `.env` <a href="#setup-env" id="setup-env"></a>

Follow the [environment configuration guide](/expo-open-ota/references/environment-variables.md). Then create a `.env` file in the project root.

### Set up the local dashboard <a href="#setup-the-dashboard-local" id="setup-the-dashboard-local"></a>

The dashboard is not served at **/dashboard** locally. Start it in development mode:

```shellscript
cd apps/dashboard
npm install
npm run dev
```

### Run the server with Docker Compose <a href="#run-the-server-using-docker-compose" id="run-the-server-using-docker-compose"></a>

```shellscript
docker-compose build
docker-compose up
```

The server is now running on port **3000**.

### 🚀 Run the example app <a href="#running-the-example-app" id="running-the-example-app"></a>

The example app is in `apps/example-app`. Use it to test the update server locally.

{% hint style="warning" %}
The app must run in release mode to test OTA behavior correctly.
{% endhint %}

#### Set up certificates <a href="#setup-certificates" id="setup-certificates"></a>

**Control Plane mode**

1. Create an application in the dashboard.
2. Generate its certificates.
3. Move the generated `.txt` certificate to `apps/example-app/certs/certificate-dev.pem`.

**Stateless mode**

The certificates are already available at:

```shellscript
apps/example-app/certs/certificate-dev.pem
apps/example-app/certs/public-key.pem
```

Set the following values:

{% code overflow="wrap" %}

```dotenv
KEYS_STORAGE_TYPE=local
PUBLIC_LOCAL_EXPO_KEY_PATH=./apps/example-app/certs/public-key.pem
PRIVATE_LOCAL_EXPO_KEY_PATH=./apps/example-app/certs/private-key-dev.pem
```

{% endcode %}

Add them to your `.env` file.

#### Build the example app <a href="#build-the-example-app" id="build-the-example-app"></a>

```shellscript
yarn prebuild_production
# or
yarn prebuild_staging
```

#### Configure the Expo project <a href="#configure-the-expo-project" id="configure-the-expo-project"></a>

Create an Expo project in the Expo dashboard with two branches:

* `staging`
* `production`

Each branch needs its own release channel. Then copy the project ID.

#### Update `app.json` <a href="#update-appjson" id="update-appjson"></a>

In `apps/example-app/app.json`, replace `YOUR_PROJECT_ID` with your Expo project ID:

```json
{
  "extra": {
    "router": {
      "origin": false
    },
    "eas": {
      "projectId": "YOUR_PROJECT_ID"
    }
}
```

#### Update `app.config.ts` <a href="#android-setup" id="android-setup"></a>

In `apps/example-app/app.config.ts`, replace `updates.url` and `updates.requestHeaders.expo-app-id` with your values.

{% hint style="info" %}
For `updates.url`, use your ngrok forwarding URL.
{% endhint %}

#### Set up Android <a href="#android-setup" id="android-setup"></a>

```shellscript
yarn prebuild_production   # Prebuild the app with the 'production' config
cd android
./gradlew clean            # Clean previous builds
./gradlew assembleRelease  # Build the release APK
./gradlew installRelease   # Install the release APK on a connected device or emulator
```

#### Set up iOS <a href="#ios" id="ios"></a>

```shellscript
cd ios
pod cache clean --all
pod install
```

Then:

1. Open the iOS project in Xcode: `open ios/*.xcworkspace`.
2. Go to **Product** → **Scheme** → **Edit Scheme**.
3. Under **Run**, set **Build Configuration** to **Release**.

#### Test OTA updates <a href="#testing-ota-updates" id="testing-ota-updates"></a>

After installing the app in release mode, use these commands to test OTA updates:

```shellscript
yarn release_production   # Publish an update to the 'production' channel
yarn release_staging      # Publish an update to the 'staging' channel
```

The app switches channels at runtime when configured to do so.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://mercure-technologies.gitbook.io/expo-open-ota/deployment/local-testing.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
