The Firebase Emulator Suite is must have for Firebase developers, it lets you develop locally without the fear of breaking your bank, if for example, you make an error in development that triggers an infinite loop on a Cloud Function.

But what happens when you want to test your app on real mobile devices while you’re using the emulator?

For that we can use the Ionic/Angular CLI to serve our app while making it accessible for other devices.

You do this by passing the --host flag to the serve command, for example:

ng serve --host=0.0.0.0

This servers your app while listening on outside devices, really helpful when you’re building something and want to see how it will look like in your phone as well as in your desktop.

When running like this, you can then go to your mobile device (connected to the same wifi network), open the browser, and instead of typing http://localhost:4200 you would type http://your-computer-ip:4200.

If you want to know your computer’s IP you can open your wifi settings and see it there, below an example of how it looks like on a mac

Wifi settings on a mac

You will then navigate to that URL in the mobile browser, for example: http://191.157.1.87:4200.

And there you’ll be able to access your app just as if it was deployed somewhere without much issue.

The problem comes when you try to access Firebase services in the app, since the app is on a phone, and the emulator is running on the computer, you get an error that reads:

Failed to load resource: Could not connect to the server

Wifi settings on a mac

To fix this, we need to also tell the emulators to listen on those devices, we do that in 2 steps.

First, we go to the firebase.json file and look for the emulator configuration, it should look something like this:

{
  "emulators": {
    "auth": {
      "port": 9099
    },
    "functions": {
      "port": 5001
    },
    "firestore": {
      "port": 8080
    },
    "storage": {
      "port": 9199
    },
    "ui": {
      "enabled": true
    },
    "singleProjectMode": true
  }
}

This configuration lets you know which ports each emulator is using, we need to change to also add the host, we pass 0.0.0.0

{
  "emulators": {
    "auth": {
      "port": 9099,
      "host": "0.0.0.0"
    },
    "functions": {
      "port": 5001,
      "host": "0.0.0.0"
    },
    "firestore": {
      "port": 8080,
      "host": "0.0.0.0"
    },
    "storage": {
      "port": 9199,
      "host": "0.0.0.0"
    },
    "ui": {
      "enabled": true
    },
    "singleProjectMode": true
  }
}

This tells our emulator to also listen to external devices when running, after we’ve done that, we go to out emulator initialization on our app, since I use @angular/fire for me it is usually inside the app.module.ts.

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [
    ...,
    provideFirebaseApp(() => initializeApp(environment.firebase)),
    provideAuth(() => {
      const auth = getAuth();
      connectAuthEmulator(auth, 'http://localhost:9099');
      return auth;
    }),
    provideFirestore(() => {
      const firestore = getFirestore();
      connectFirestoreEmulator(firestore, 'localhost', 8080);
      return firestore;
    }),
    provideFunctions(() => {
      const functions = getFunctions();
      connectFunctionsEmulator(functions, 'localhost', 5001);
      return functions;
    }),
  ],
  providers: [
    ...
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

In here, we’re going to change the URL our emulators are pointing to, to make it match the IP of our computer:

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [
    ...,
    provideFirebaseApp(() => initializeApp(environment.firebase)),
    provideAuth(() => {
      const auth = getAuth();
      connectAuthEmulator(auth, 'http://191.157.1.87:9099');
      return auth;
    }),
    provideFirestore(() => {
      const firestore = getFirestore();
      connectFirestoreEmulator(firestore, '191.157.1.87', 8080);
      return firestore;
    }),
    provideFunctions(() => {
      const functions = getFunctions();
      connectFunctionsEmulator(functions, '191.157.1.87', 5001);
      return functions;
    }),
  ],
  providers: [
    ...
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

And that’s it, after that your phone will be able to connect to the Firebase emulator and you’ll be able to quickly test your work without needing to deploy the app first.