---
description: Learn how to build a simple heart rate monitor app with Capacitor and the Bluetooth Low Energy plugin in just 15 minutes.
title: How to Build a Heart Rate Monitor with Capacitor - Capawesome
image: https://capawesome.io/docs/assets/images/social/blog/how-to-build-a-heart-rate-monitor-with-capacitor.png
---

<!doctype html> 

[Skip to content ](#how-to-build-a-heart-rate-monitor-with-capacitor) 

[🖥️ Introducing the **Capacitor Electron Platform** — build desktop apps for macOS, Windows, and Linux. Free & open source. ](/blog/announcing-the-capacitor-electron-platform/) 

* [ SDKs ](/docs/sdks/)
* [ Formbricks ](/docs/sdks/capacitor/formbricks/)
* [ Geocoder ](/docs/sdks/capacitor/geocoder/)
* [ Google Sign-In ](/docs/sdks/capacitor/google-sign-in/)
* [ Grafana Faro ](/docs/sdks/capacitor/grafana-faro/)
* [ Gyroscope ](/docs/sdks/capacitor/gyroscope/)
* [ Haptics ](/docs/sdks/capacitor/haptics/)
* [ Home Indicator ](/docs/sdks/capacitor/home-indicator/)
* [ In-App Browser ](/docs/sdks/capacitor/in-app-browser/)
* [ Install Referrer ](/docs/sdks/capacitor/install-referrer/)
* [ Intercom ](/docs/sdks/capacitor/intercom/)
* [ Intune ](/docs/sdks/capacitor/intune/)
* [ Keep Awake ](/docs/sdks/capacitor/keep-awake/)
* [ libSQL ](/docs/sdks/capacitor/libsql/)
* [ Light Sensor ](/docs/sdks/capacitor/light-sensor/)
* [ Live Update ](/docs/sdks/capacitor/live-update/)
* [ Localization ](/docs/sdks/capacitor/localization/)
* [ Mail Composer ](/docs/sdks/capacitor/mail-composer/)
* [ Managed Configurations ](/docs/sdks/capacitor/managed-configurations/)
* [ Maps Launcher ](/docs/sdks/capacitor/maps-launcher/)
* [ Media Session ](/docs/sdks/capacitor/media-session/)
* [ ML Kit ](/docs/sdks/capacitor/mlkit/)
* [ Navigation Bar ](/docs/sdks/capacitor/navigation-bar/)
* [ Network ](/docs/sdks/capacitor/network/)
* [ NFC ](/docs/sdks/capacitor/nfc/)
* [ Node.js ](/docs/sdks/capacitor/nodejs/)
* [ OAuth ](/docs/sdks/capacitor/oauth/)
* [ Passkeys ](/docs/sdks/capacitor/passkeys/)
* [ Password Autofill ](/docs/sdks/capacitor/password-autofill/)
* [ PDF Generator ](/docs/sdks/capacitor/pdf-generator/)
* [ PDF Viewer ](/docs/sdks/capacitor/pdf-viewer/)
* [ Pedometer ](/docs/sdks/capacitor/pedometer/)
* [ Permissions ](/docs/sdks/capacitor/permissions/)
* [ Phone Dialer ](/docs/sdks/capacitor/phone-dialer/)
* [ Photo Editor ](/docs/sdks/capacitor/photo-editor/)
* [ Photo Manipulator ](/docs/sdks/capacitor/photo-manipulator/)
* [ PixLive ](/docs/sdks/capacitor/pixlive/)
* [ PostHog ](/docs/sdks/capacitor/posthog/)
* [ Printer ](/docs/sdks/capacitor/printer/)
* [ Privacy Screen ](/docs/sdks/capacitor/privacy-screen/)
* [ Proximity Sensor ](/docs/sdks/capacitor/proximity-sensor/)
* [ Purchases ](/docs/sdks/capacitor/purchases/)
* [ RealtimeKit ](/docs/sdks/capacitor/realtimekit/)
* [ Root Detection ](/docs/sdks/capacitor/root-detection/)
* [ Screen Brightness ](/docs/sdks/capacitor/screen-brightness/)
* [ Screen Orientation ](/docs/sdks/capacitor/screen-orientation/)
* [ Screen Reader ](/docs/sdks/capacitor/screen-reader/)
* [ Screenshot ](/docs/sdks/capacitor/screenshot/)
* [ Secure Preferences ](/docs/sdks/capacitor/secure-preferences/)
* [ Settings Launcher ](/docs/sdks/capacitor/settings-launcher/)
* [ Shake ](/docs/sdks/capacitor/shake/)
* [ Silent Mode ](/docs/sdks/capacitor/silent-mode/)
* [ SIM ](/docs/sdks/capacitor/sim/)
* [ SMS Composer ](/docs/sdks/capacitor/sms-composer/)
* [ Speech Recognition ](/docs/sdks/capacitor/speech-recognition/)
* [ Speech Synthesis ](/docs/sdks/capacitor/speech-synthesis/)
* [ Share Target ](/docs/sdks/capacitor/share-target/)
* [ Square Mobile Payments ](/docs/sdks/capacitor/square-mobile-payments/)
* [ SQLite ](/docs/sdks/capacitor/sqlite/)
* [ Superwall ](/docs/sdks/capacitor/superwall/)
* [ System WebView ](/docs/sdks/capacitor/system-webview/)
* [ Tauri ](/docs/sdks/capacitor/tauri/)
* [ Text Interaction ](/docs/sdks/capacitor/text-interaction/)
* [ Text Zoom ](/docs/sdks/capacitor/text-zoom/)
* [ Thermal State ](/docs/sdks/capacitor/thermal-state/)
* [ Toast ](/docs/sdks/capacitor/toast/)
* [ Torch ](/docs/sdks/capacitor/torch/)
* [ Vault ](/docs/sdks/capacitor/vault/)
* [ Volume ](/docs/sdks/capacitor/volume/)
* [ Wallet ](/docs/sdks/capacitor/wallet/)
* [ Wifi ](/docs/sdks/capacitor/wifi/)
* [ YouTube Player ](/docs/sdks/capacitor/youtube-player/)
* [ Zip ](/docs/sdks/capacitor/zip/)
* [ Cordova ](/docs/sdks/cordova/)
* [ Cloud ](/docs/cloud/)
* [ Integrations ](/docs/cloud/live-updates/integrations/)
* Concepts
* Reference
* [ Troubleshooting ](/docs/cloud/live-updates/troubleshooting/)
* [ FAQ ](/docs/cloud/live-updates/faq/)
* [ Native Builds ](/docs/cloud/native-builds/)
* [ Set Up Environments ](/docs/cloud/native-builds/environments/)
* [ Overwrite Native Configurations ](/docs/cloud/native-builds/native-configurations/)
* [ Auto-Increment Build Numbers ](/docs/cloud/native-builds/auto-incrementing-build-numbers/)
* [ Configure the Web Build Script ](/docs/cloud/native-builds/web-build-script/)
* [ Build from a Monorepo ](/docs/cloud/native-builds/monorepo/)
* [ Use pnpm, Yarn, or bun ](/docs/cloud/native-builds/package-managers/)
* [ Install Private npm Packages ](/docs/cloud/native-builds/npm-private-registry/)
* [ Override the Java Version ](/docs/cloud/native-builds/override-java-version/)
* [ Custom iOS Provisioning Profiles ](/docs/cloud/native-builds/custom-ios-provisioning-profiles/)
* [ Build without Git ](/docs/cloud/native-builds/build-without-git/)
* [ Access Git Behind a Firewall ](/docs/cloud/native-builds/firewall-access/)
* [ Integrations ](/docs/cloud/native-builds/integrations/)
* Reference
* [ Troubleshooting ](/docs/cloud/native-builds/troubleshooting/)
* [ FAQ ](/docs/cloud/native-builds/faq/)
* [ App Store Publishing ](/docs/cloud/app-store-publishing/)
* [ Submit a Build ](/docs/cloud/app-store-publishing/submit-a-build/)
* [ Submit Automatically After a Build ](/docs/cloud/app-store-publishing/submit-automatically/)
* [ Troubleshooting ](/docs/cloud/app-store-publishing/troubleshooting/)
* [ FAQ ](/docs/cloud/app-store-publishing/faq/)
* [ Automations ](/docs/cloud/automations/)
* [ Reference ](/docs/cloud/automations/reference/)
* [ Troubleshooting ](/docs/cloud/automations/troubleshooting/)
* [ FAQ ](/docs/cloud/automations/faq/)
* [ Assist ](/docs/cloud/assist/)
* [ CLI ](/docs/cloud/cli/)
* APIs and SDKs
* [ Webhooks ](/docs/cloud/webhooks/)
* [ Integrations ](/docs/cloud/integrations/)
* Account
* [ Organization ](/docs/cloud/organizations/)
* [ Two-Factor Enforcement ](/docs/cloud/organizations/two-factor-authentication/)
* [ Audit Logs ](/docs/cloud/organizations/audit-logs/)
* [ Billing ](/docs/cloud/organizations/billing/)
* [ License Keys ](/docs/cloud/license-keys/)
* [ AI ](/docs/ai/)
* [ Insiders ](/docs/insiders/)
* [ Billing & Plans ](/docs/insiders/billing-and-plans/)
* [ FAQ ](/docs/insiders/faq/)
* [ License ](https://capawesome.io/legal/eula/)
* [ Support ](/docs/support/)
* [ Contributing ](/docs/contributing/)
* Contributing code
* [ Code of Conduct ](/docs/contributing/code-of-conduct/)
* [ Questions ](https://docs.github.com/en/discussions/collaborating-with-your-community-using-discussions/participating-in-a-discussion#creating-a-discussion)
* [ Blog ](/blog/)
* Categories

* [ Prerequisites ](#prerequisites)
* [ Create a new app ](#create-a-new-app)
* [ Implement the Heart Rate Monitor ](#implement-the-heart-rate-monitor)
* [ Run the app ](#run-the-app)
* [ Reading the Device's Built-In Sensors ](#reading-the-devices-built-in-sensors)
* [ FAQ ](#faq)
* [ Conclusion ](#conclusion)

* Related links

# How to Build a Heart Rate Monitor with Capacitor[¶](#how-to-build-a-heart-rate-monitor-with-capacitor "Permanent link")

Capacitor makes building a cross-platform app with one codebase easier than ever before. Today we will use the Ionic Framework and Capacitor to create a simple heart rate monitor app for Android and iOS in just 15 minutes. For this, we will use the [Capacitor Bluetooth Low Energy plugin](/docs/sdks/capacitor/bluetooth-low-energy/) to connect to a heart rate sensor.

The heart rate sensor we use in this tutorial is the [Polar H9 Heart Rate Sensor](https://www.polar.com/en/sensors/h9-heart-rate-sensor), but any other Bluetooth heart rate sensor should work as well. You can find the complete app code referenced in this guide on [GitHub](https://github.com/capawesome-team/capacitor-heart-rate-monitor-app).

![Capacitor Heart Rate Monitor App](/docs/assets/images/gifs/capacitor-heart-rate-monitor.gif) 

Capacitor Heart Rate Monitor App

## Basics[¶](#basics "Permanent link")

### Bluetooth Low Energy[¶](#bluetooth-low-energy "Permanent link")

First, let's talk about Bluetooth Low Energy (BLE) and how it works. BLE is a wireless communication technology that is designed to reduce power consumption while maintaining a similar communication range to classic Bluetooth. BLE is used in many devices, such as heart rate sensors, fitness trackers, smartwatches, and more.

#### Centrals and Peripherals[¶](#centrals-and-peripherals "Permanent link")

BLE devices are divided into two categories: peripherals and centrals. Peripherals are devices that provide data, such as heart rate sensors, while centrals are devices that consume data, such as smartphones. In our case, the heart rate sensor is the peripheral, and the smartphone is the central.

#### Services and Characteristics[¶](#services-and-characteristics "Permanent link")

BLE communication is based on the concept of services and characteristics. A service is a collection of characteristics, and a characteristic is a piece of data that can be read, written, or notified. For example, a heart rate sensor has a service that contains a characteristic for the heart rate measurement. Each service and characteristic is represented by a unique UUID (Universally Unique Identifier). The UUIDs are standardized and defined by the Bluetooth SIG (Special Interest Group).

## Prerequisites[¶](#prerequisites "Permanent link")

Before we start, download and install the following tools to ensure an optimal developer experience:

* [Node.js](https://nodejs.org/en/download) to install the required dependencies
* A code editor for... writing code! **Tip**: Visual Studio Code supports the new [Ionic VS Code Extension](https://ionicframework.com/docs/intro/vscode-extension)
* [Android Studio](https://developer.android.com/studio) to build the Android app
* [Xcode](https://apps.apple.com/de/app/xcode/id497799835) to build the iOS app (only available on macOS)

## Create a new app[¶](#create-a-new-app "Permanent link")

To create a new project, we simply use the [Ionic CLI](https://ionicframework.com/docs/cli). For this, first install the CLI globally:

`[](#%5F%5Fcodelineno-0-1)npm install -g @ionic/cli
`

Then you can create a new project with the `ionic start` command:

`[](#%5F%5Fcodelineno-1-1)npx ionic start heart-rate-monitor-app blank --type=angular --capacitor
`

In this case, the app is called `heart-rate-monitor-app`, the starter template is `blank`, and the project type for the purposes of this guide is Angular. You can also choose Vue or React, for example. Additionally, we enable the Capacitor integration with `--capacitor`.

Once everything is ready, you should see this output:

`[](#%5F%5Fcodelineno-2-1)Your Ionic app is ready! Follow these next steps:
[](#%5F%5Fcodelineno-2-2)
[](#%5F%5Fcodelineno-2-3)- Go to your new project: cd .\heart-rate-monitor-app
[](#%5F%5Fcodelineno-2-4)- Run ionic serve within the app directory to see your app in the browser
[](#%5F%5Fcodelineno-2-5)- Run ionic capacitor add to add a native iOS or Android project using Capacitor
[](#%5F%5Fcodelineno-2-6)- Generate your app icon and splash screens using cordova-res --skip-config --copy
[](#%5F%5Fcodelineno-2-7)- Explore the Ionic docs for components, tutorials, and more: https://ion.link/docs
[](#%5F%5Fcodelineno-2-8)- Building an enterprise app? Ionic has Enterprise Support and Features: https://ion.link/enterprise-edition
`

### Add the Android platform[¶](#add-the-android-platform "Permanent link")

If you want to build the app for Android, you need to add the Android platform. For this, first install the `@capacitor/android` package:

`[](#%5F%5Fcodelineno-3-1)npm install @capacitor/android
`

Then add the Android platform using the following command:

`[](#%5F%5Fcodelineno-4-1)npx cap add android
`

### Add the iOS platform[¶](#add-the-ios-platform "Permanent link")

If you want to build the app for iOS, you need to add the iOS platform. For this, first install the `@capacitor/ios` package:

`[](#%5F%5Fcodelineno-5-1)npm install @capacitor/ios
`

Then add the iOS platform using the following command:

`[](#%5F%5Fcodelineno-6-1)npx cap add ios
`

## Implement the Heart Rate Monitor[¶](#implement-the-heart-rate-monitor "Permanent link")

### Install the Bluetooth Low Energy plugin[¶](#install-the-bluetooth-low-energy-plugin "Permanent link")

In order to connect to the heart rate sensor, we need to install the [Capacitor Bluetooth Low Energy plugin](/docs/sdks/capacitor/bluetooth-low-energy/). Please note that the plugin is currently only available to [Insiders](/docs/insiders/). See [Getting started with Insiders](/docs/insiders/getting-started/?plugin=capacitor-bluetooth-low-energy) and follow the instructions to install the plugin.

On **Android**, this plugin requires the following permissions be added to your `AndroidManifest.xml` before or after the `application` tag:

`[](#%5F%5Fcodelineno-7-1)<!-- Needed only if your app looks for Bluetooth devices.  -->
[](#%5F%5Fcodelineno-7-2)<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
[](#%5F%5Fcodelineno-7-3)<!-- Needed only if your app communicates with already-paired Bluetooth devices. -->
[](#%5F%5Fcodelineno-7-4)<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
[](#%5F%5Fcodelineno-7-5)<!-- Needed only if your app uses Bluetooth scan results to derive physical location. -->
[](#%5F%5Fcodelineno-7-6)<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
[](#%5F%5Fcodelineno-7-7)<!-- Needed only if your app uses the foreground service. -->
[](#%5F%5Fcodelineno-7-8)<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
[](#%5F%5Fcodelineno-7-9)<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" />
[](#%5F%5Fcodelineno-7-10)<uses-permission android:name="android.permission.WAKE_LOCK" />
`

You can read more about Bluetooth permissions in the [Android documentation](https://developer.android.com/develop/connectivity/bluetooth/bt-permissions).

You also need to add the following service **inside** the `application` tag in your `AndroidManifest.xml` (usually `android/app/src/main/AndroidManifest.xml`):

`[](#%5F%5Fcodelineno-8-1)<service android:name="io.capawesome.capacitorjs.plugins.bluetoothle.BluetoothLowEnergyService" android:foregroundServiceType="connectedDevice" />
`

On **iOS**, add the `NSBluetoothPeripheralUsageDescription` and `NSBluetoothAlwaysUsageDescription` keys to the `Info.plist` file (usually `ios/App/App/Info.plist`), which tells the user why the app needs access to Bluetooth peripherals:

`[](#%5F%5Fcodelineno-9-1)<key>NSBluetoothAlwaysUsageDescription</key>
[](#%5F%5Fcodelineno-9-2)<string>The app needs access to Bluetooth peripherals to communicate with Bluetooth devices.</string>
`

The plugin is now ready to use.

### Build the page[¶](#build-the-page "Permanent link")

Let's start with the actual implementation. Since the app already has a blank page called `home`, we can use this page to display the heart rate. The page consists of a title and the current heart rate. For reason of simplicity, there will be no interactive elements. The app will try to establish a connection to the heart rate sensor via BLE **directly after the page is loaded** and display the current heart rate.

The following code goes to your `src/app/home/home.page.ts` file:

`` [](#%5F%5Fcodelineno-10-1)import { Component, OnInit, signal } from '@angular/core';
[](#%5F%5Fcodelineno-10-2)import { Capacitor } from '@capacitor/core';
[](#%5F%5Fcodelineno-10-3)import { BluetoothLowEnergy } from '@capawesome-team/capacitor-bluetooth-low-energy';
[](#%5F%5Fcodelineno-10-4)import { IonHeader, IonToolbar, IonTitle, IonContent, IonButton } from '@ionic/angular/standalone';
[](#%5F%5Fcodelineno-10-5)
[](#%5F%5Fcodelineno-10-6)@Component({
[](#%5F%5Fcodelineno-10-7)  selector: 'app-home',
[](#%5F%5Fcodelineno-10-8)  templateUrl: 'home.page.html',
[](#%5F%5Fcodelineno-10-9)  styleUrls: ['home.page.scss'],
[](#%5F%5Fcodelineno-10-10)  standalone: true,
[](#%5F%5Fcodelineno-10-11)  imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonButton],
[](#%5F%5Fcodelineno-10-12)})
[](#%5F%5Fcodelineno-10-13)export class HomePage implements OnInit {
[](#%5F%5Fcodelineno-10-14)  public heartRate = signal<undefined | number>(undefined);
[](#%5F%5Fcodelineno-10-15)
[](#%5F%5Fcodelineno-10-16)  constructor() {}
[](#%5F%5Fcodelineno-10-17)
[](#%5F%5Fcodelineno-10-18)  public async ngOnInit() {
[](#%5F%5Fcodelineno-10-19)    // 1. Initialize the Bluetooth Low Energy plugin
[](#%5F%5Fcodelineno-10-20)    if (Capacitor.getPlatform() === 'ios') {
[](#%5F%5Fcodelineno-10-21)      await BluetoothLowEnergy.initialize();
[](#%5F%5Fcodelineno-10-22)    } else {
[](#%5F%5Fcodelineno-10-23)      await BluetoothLowEnergy.requestPermissions();
[](#%5F%5Fcodelineno-10-24)    }
[](#%5F%5Fcodelineno-10-25)    // 2. Add a listener for the `deviceScanned` event
[](#%5F%5Fcodelineno-10-26)    await BluetoothLowEnergy.addListener('deviceScanned', async (event) => {
[](#%5F%5Fcodelineno-10-27)      if (event.name?.startsWith('Polar H9')) {
[](#%5F%5Fcodelineno-10-28)        // 4. Stop scanning for devices
[](#%5F%5Fcodelineno-10-29)        void BluetoothLowEnergy.stopScan();
[](#%5F%5Fcodelineno-10-30)        // 5. Connect to the device
[](#%5F%5Fcodelineno-10-31)        await BluetoothLowEnergy.connect({
[](#%5F%5Fcodelineno-10-32)          deviceId: event.id,
[](#%5F%5Fcodelineno-10-33)        });
[](#%5F%5Fcodelineno-10-34)        // 6. Discover services
[](#%5F%5Fcodelineno-10-35)        await BluetoothLowEnergy.discoverServices({
[](#%5F%5Fcodelineno-10-36)          deviceId: event.id,
[](#%5F%5Fcodelineno-10-37)        });
[](#%5F%5Fcodelineno-10-38)        // 7. Add a listener for the `characteristicChanged` event
[](#%5F%5Fcodelineno-10-39)        await BluetoothLowEnergy.addListener('characteristicChanged', (event) => {
[](#%5F%5Fcodelineno-10-40)          let byteArray = new Uint8Array(event.value);
[](#%5F%5Fcodelineno-10-41)          let firstBitValue = byteArray[0] & 0x01;
[](#%5F%5Fcodelineno-10-42)          if (firstBitValue === 0) {
[](#%5F%5Fcodelineno-10-43)            this.heartRate.set(byteArray[1]);
[](#%5F%5Fcodelineno-10-44)          } else {
[](#%5F%5Fcodelineno-10-45)            this.heartRate.set((byteArray[1] << 8) | byteArray[2]);
[](#%5F%5Fcodelineno-10-46)          }
[](#%5F%5Fcodelineno-10-47)        });
[](#%5F%5Fcodelineno-10-48)        // 8. Start notifications for the Heart Rate Measurement characteristic
[](#%5F%5Fcodelineno-10-49)        await BluetoothLowEnergy.startCharacteristicNotifications({
[](#%5F%5Fcodelineno-10-50)          deviceId: event.id,
[](#%5F%5Fcodelineno-10-51)          serviceId: '0000180D-0000-1000-8000-00805F9B34FB',
[](#%5F%5Fcodelineno-10-52)          characteristicId: '00002A37-0000-1000-8000-00805F9B34FB',
[](#%5F%5Fcodelineno-10-53)        });
[](#%5F%5Fcodelineno-10-54)      }
[](#%5F%5Fcodelineno-10-55)    });
[](#%5F%5Fcodelineno-10-56)    // 3. Start scanning for devices
[](#%5F%5Fcodelineno-10-57)    await BluetoothLowEnergy.startScan();
[](#%5F%5Fcodelineno-10-58)  }
[](#%5F%5Fcodelineno-10-59)}
 ``

Let's break down the code:

1. **Initialize the Bluetooth Low Energy plugin**: First, we need to initialize the plugin. For iOS, we need to call [initialize()](/docs/sdks/capacitor/bluetooth-low-energy/#initialize), and for Android, we need to request the necessary permissions with `requestPermissions()`.
2. **Add the `deviceScanned` listener**: We need to add a listener for the [deviceScanned](/docs/sdks/capacitor/bluetooth-low-energy/#addlistenerdevicescanned) event before we start scanning for devices. This listener will be called whenever a BLE device is found.
3. **Start scanning for devices**: To start scanning for devices, we call [startScan()](/docs/sdks/capacitor/bluetooth-low-energy/#startscan). As soon as a device is found, the [deviceScanned](/docs/sdks/capacitor/bluetooth-low-energy/#addlistenerdevicescanned) event is emitted.
4. **Stop scanning for devices**: After we found the heart rate sensor, we stop scanning for devices. This is important to save battery life.
5. **Connect to the device**: To connect to the heart rate sensor, we call [connect()](/docs/sdks/capacitor/bluetooth-low-energy/#connect) with the device ID.
6. **Discover services**: After connecting to the device, we need to discover the services. This is necessary to find the service that contains the heart rate measurement characteristic. For this, we call [discoverServices()](/docs/sdks/capacitor/bluetooth-low-energy/#discoverservices).
7. **Add the `characteristicChanged` listener**: We need to add a listener for the [characteristicChanged](/docs/sdks/capacitor/bluetooth-low-energy/#addlistenercharacteristicchanged) event to receive the heart rate measurements. This event is emitted whenever the heart rate measurement characteristic changes. The value of the characteristic is a byte array that contains the heart rate measurement. Depending on the first bit of the first byte, the heart rate is either a single byte or two bytes. If the heart rate is a single byte, the heart rate is the second byte. If the heart rate is two bytes, the heart rate is the second byte shifted left by 8 bits and combined with the third byte.
8. **Start notifications for the Heart Rate Measurement characteristic**: To receive the heart rate measurements, we need to start notifications for the heart rate measurement characteristic. For this, we call [startCharacteristicNotifications()](/docs/sdks/capacitor/bluetooth-low-energy/#startcharacteristicnotifications). The service ID and characteristic ID are standardized and defined by the Bluetooth SIG. The service ID for the heart rate service is `0000180D-0000-1000-8000-00805F9B34FB`, and the characteristic ID for the heart rate measurement is `00002A37-0000-1000-8000-00805F9B34FB`.

Next, we need to create the HTML and CSS for the page. As mentioned earlier, we will keep it simple and only display a title and the current heart rate. The following code goes to your `src/app/home/home.page.html` file:

`[](#%5F%5Fcodelineno-11-1)<ion-header>
[](#%5F%5Fcodelineno-11-2)  <ion-toolbar>
[](#%5F%5Fcodelineno-11-3)    <ion-title>
[](#%5F%5Fcodelineno-11-4)      Heart Rate Monitor
[](#%5F%5Fcodelineno-11-5)    </ion-title>
[](#%5F%5Fcodelineno-11-6)  </ion-toolbar>
[](#%5F%5Fcodelineno-11-7)</ion-header>
[](#%5F%5Fcodelineno-11-8)
[](#%5F%5Fcodelineno-11-9)<ion-content>
[](#%5F%5Fcodelineno-11-10)  <div class="title">Current heart rate</div>
[](#%5F%5Fcodelineno-11-11)  <div class="body">{{ heartRate() ?? '--' }}</div>
[](#%5F%5Fcodelineno-11-12)</ion-content>
`

The following code goes to your `src/app/home/home.page.scss` file:

`[](#%5F%5Fcodelineno-12-1)ion-content {
[](#%5F%5Fcodelineno-12-2)  text-align: center;
[](#%5F%5Fcodelineno-12-3)}
[](#%5F%5Fcodelineno-12-4)
[](#%5F%5Fcodelineno-12-5).title {
[](#%5F%5Fcodelineno-12-6)  font-size: 32px;
[](#%5F%5Fcodelineno-12-7)  margin-top: 36px;
[](#%5F%5Fcodelineno-12-8)}
[](#%5F%5Fcodelineno-12-9)
[](#%5F%5Fcodelineno-12-10).body {
[](#%5F%5Fcodelineno-12-11)  font-size: 64px;
[](#%5F%5Fcodelineno-12-12)  font-weight: bold;
[](#%5F%5Fcodelineno-12-13)  margin-top: 48px;
[](#%5F%5Fcodelineno-12-14)}
`

That's it! Now everything is set up to build and run the app. 🎉

## Run the app[¶](#run-the-app "Permanent link")

To run your app on Android, use the following command:

`[](#%5F%5Fcodelineno-13-1)npx ionic cap run android
`

To run your app on iOS, use the following command:

`[](#%5F%5Fcodelineno-14-1)npx ionic cap run ios
`

## Reading the Device's Built-In Sensors[¶](#reading-the-devices-built-in-sensors "Permanent link")

The heart rate monitor above reads data from an external sensor over [Bluetooth Low Energy](/docs/sdks/capacitor/bluetooth-low-energy/). But every phone also ships with a set of built-in sensors you can read directly, no pairing required. If your app needs motion, orientation, or environmental data, these plugins expose them behind the same simple, listener-based API:

* **[Compass](/docs/sdks/capacitor/compass/)** — read the device heading and listen for live updates, including true north on iOS.
* **[Gyroscope](/docs/sdks/capacitor/gyroscope/)** — real-time rotation rate measurements for motion-based interactions.
* **[Proximity Sensor](/docs/sdks/capacitor/proximity-sensor/)** — detect nearby objects, for example to blank the screen during a call.
* **[Light Sensor](/docs/sdks/capacitor/light-sensor/)** — read ambient illuminance in lux to adapt your UI to the surroundings (Android).
* **[Barometer](/docs/sdks/capacitor/barometer/)** — obtain static air pressure and altitude from the barometer sensor.
* **[Thermal State](/docs/sdks/capacitor/thermal-state/)** — react to the device thermal state before the OS throttles your app during heavy work.

## FAQ[¶](#faq "Permanent link")

### Do I need a physical device to build this heart rate monitor?[¶](#do-i-need-a-physical-device-to-build-this-heart-rate-monitor "Permanent link")

Yes. Bluetooth Low Energy talks to real hardware, so you need to run the app on a physical Android or iOS device — the iOS Simulator and Android emulator don't expose Bluetooth. You also need an actual BLE heart rate sensor, such as a chest strap or a compatible smartwatch.

### Does the Capacitor Bluetooth Low Energy plugin work on both Android and iOS?[¶](#does-the-capacitor-bluetooth-low-energy-plugin-work-on-both-android-and-ios "Permanent link")

Yes, on both. Each platform requires the appropriate Bluetooth permissions in its native configuration; see the [Installation](/docs/sdks/capacitor/bluetooth-low-energy/#installation) section of the plugin documentation for the exact setup.

### My app can't find the heart rate sensor — what's wrong?[¶](#my-app-cant-find-the-heart-rate-sensor-whats-wrong "Permanent link")

The usual causes are missing Bluetooth (and, on Android, location) permissions, a sensor that isn't in pairing mode, or scanning for the wrong service. Double-check the permissions and confirm you're filtering for the Heart Rate service (`0x180D`).

### Can I read sensors that don't use Bluetooth?[¶](#can-i-read-sensors-that-dont-use-bluetooth "Permanent link")

Yes. The phone's built-in sensors — compass, gyroscope, proximity, ambient light, barometer, and thermal state — are available directly without pairing. See [Reading the Device's Built-In Sensors](#reading-the-devices-built-in-sensors) above.

## Conclusion[¶](#conclusion "Permanent link")

In this guide, we learned how to build a simple heart rate monitor app with Capacitor. We used the [Capacitor Bluetooth Low Energy plugin](/docs/sdks/capacitor/bluetooth-low-energy/) to connect to a heart rate sensor and receive the heart rate measurements. If you have any questions, just [create a discussion](https://github.com/capawesome-team/capacitor-plugins) in the GitHub repository. Make sure you follow Capawesome on [X](https://twitter.com/capawesomeio) so you don't miss any future updates.

July 15, 2026 

Back to top

```json
{
      "@context": "https://schema.org",
      "@type": "BlogPosting",
      "headline": "How to Build a Heart Rate Monitor with Capacitor",
      "description": "Learn how to build a simple heart rate monitor app with Capacitor and the Bluetooth Low Energy plugin in just 15 minutes.",
      "image": "https://capawesome.io/assets/banners/cloud-build-and-deploy-capacitor-apps.png",
      "datePublished": "2024-08-05T00:00:00+00:00",
      "dateModified": "2026-07-14T00:00:00+00:00",
      "author": [
        {
          "@type": "Person",
          "name": "Robin Genz",
          "url": "https://github.com/robingenz"
        }
      ],
      "publisher": {
        "@type": "Organization",
        "name": "Capawesome",
        "url": "https://capawesome.io",
        "logo": {
          "@type": "ImageObject",
          "url": "https://capawesome.io/assets/images/logo.svg"
        }
      },
      "articleSection": "Capacitor",
      "keywords": ["Capacitor", "Guides", "SDKs"],
      "isPartOf": {
        "@type": "Blog",
        "@id": "https://capawesome.io/blog/#blog"
      },
      "mainEntityOfPage": "https://capawesome.io/blog/how-to-build-a-heart-rate-monitor-with-capacitor/",
      "url": "https://capawesome.io/blog/how-to-build-a-heart-rate-monitor-with-capacitor/"
    }
{
      "@context": "https://schema.org",
      "@type": "BreadcrumbList",
      "itemListElement": [
        {
          "@type": "ListItem",
          "position": 1,
          "name": "Home",
          "item": "https://capawesome.io/"
        },
        {
          "@type": "ListItem",
          "position": 2,
          "name": "Blog",
          "item": "https://capawesome.io/blog/"
        },
        {
          "@type": "ListItem",
          "position": 3,
          "name": "How to Build a Heart Rate Monitor with Capacitor",
          "item": "https://capawesome.io/blog/how-to-build-a-heart-rate-monitor-with-capacitor/"
        }
      ]
    }
{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "Do I need a physical device to build this heart rate monitor?", "acceptedAnswer": {"@type": "Answer", "text": "Yes. Bluetooth Low Energy talks to real hardware, so you need to run the app on a physical Android or iOS device — the iOS Simulator and Android emulator don't expose Bluetooth. You also need an actual BLE heart rate sensor, such as a chest strap or a compatible smartwatch."}}, {"@type": "Question", "name": "Does the Capacitor Bluetooth Low Energy plugin work on both Android and iOS?", "acceptedAnswer": {"@type": "Answer", "text": "Yes, on both. Each platform requires the appropriate Bluetooth permissions in its native configuration; see the Installation section of the plugin documentation for the exact setup."}}, {"@type": "Question", "name": "My app can't find the heart rate sensor — what's wrong?", "acceptedAnswer": {"@type": "Answer", "text": "The usual causes are missing Bluetooth (and, on Android, location) permissions, a sensor that isn't in pairing mode, or scanning for the wrong service. Double-check the permissions and confirm you're filtering for the Heart Rate service ( 0x180D)."}}, {"@type": "Question", "name": "Can I read sensors that don't use Bluetooth?", "acceptedAnswer": {"@type": "Answer", "text": "Yes. The phone's built-in sensors — compass, gyroscope, proximity, ambient light, barometer, and thermal state — are available directly without pairing. See Reading the Device's Built-In Sensors above."}}], "url": "https://capawesome.io/blog/how-to-build-a-heart-rate-monitor-with-capacitor/"}
```
