---
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
---

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

[ 🎉 Introducing **Capawesome Platform** — one platform for Live Updates, Native Builds, App Store Publishing, and Insider SDKs.](https://capawesome.io) 

* [  Formbricks ](/docs/plugins/formbricks/)
* [  Geocoder ](/docs/plugins/geocoder/)
* [  Google Sign-In ](/docs/plugins/google-sign-in/)
* [  Grafana Faro ](/docs/plugins/grafana-faro/)
* [  libSQL ](/docs/plugins/libsql/)
* [  Live Update ](/docs/plugins/live-update/)
* [  Managed Configurations ](/docs/plugins/managed-configurations/)
* [  Media Session ](/docs/plugins/media-session/)
* [  ML Kit ](/docs/plugins/mlkit/)
* [  Navigation Bar ](/docs/plugins/navigation-bar/)
* [  NFC ](/docs/plugins/nfc/)
* [  OAuth ](/docs/plugins/oauth/)
* [  Pedometer ](/docs/plugins/pedometer/)
* [  Photo Editor ](/docs/plugins/photo-editor/)
* [  PostHog ](/docs/plugins/posthog/)
* [  Printer ](/docs/plugins/printer/)
* [  Purchases ](/docs/plugins/purchases/)
* [  RealtimeKit ](/docs/plugins/realtimekit/)
* [  Screen Orientation ](/docs/plugins/screen-orientation/)
* [  Screenshot ](/docs/plugins/screenshot/)
* [  Secure Preferences ](/docs/plugins/secure-preferences/)
* [  Speech Recognition ](/docs/plugins/speech-recognition/)
* [  Speech Synthesis ](/docs/plugins/speech-synthesis/)
* [  Share Target ](/docs/plugins/share-target/)
* [  Square Mobile Payments ](/docs/plugins/square-mobile-payments/)
* [  SQLite ](/docs/plugins/sqlite/)
* [  Superwall ](/docs/plugins/superwall/)
* [  Torch ](/docs/plugins/torch/)
* [  Wifi ](/docs/plugins/wifi/)
* [  Zip ](/docs/plugins/zip/)
* [  Cloud ](/docs/cloud/)
* [  Live Updates ](/docs/cloud/live-updates/)
* Advanced
* Integrations
* [  Native Builds ](/docs/cloud/native-builds/)
* [  Configuration ](/docs/cloud/native-builds/configuration/)
* [  Environments ](/docs/cloud/native-builds/environments/)
* Guides
* [  Sample Projects ](/docs/cloud/native-builds/sample-projects/)
* [  Troubleshooting ](/docs/cloud/native-builds/troubleshooting/)
* [  Automations ](/docs/cloud/automations/)
* [  Assist ](/docs/cloud/assist/)
* Account
* Organizations
* [  Organization and User Management ](/docs/cloud/organizations/memberships/)
* [  Single Sign-On (SSO) ](/docs/cloud/organizations/sso/)
* [  Teams ](/docs/cloud/organizations/teams/)
* [  Two-Factor Authentication ](/docs/cloud/organizations/two-factor-authentication/)
* [  Integrations ](/docs/cloud/integrations/)
* [  License Keys ](/docs/cloud/license-keys/)
* [  Webhooks ](/docs/cloud/webhooks/)
* [  Pricing ](https://capawesome.io/pricing/)
* [  FAQ ](/docs/cloud/faq/)
* [  Support ](/docs/cloud/support/)
* [  Contributing ](/docs/contributing/)
* [  LLMs ](/docs/llms/)
* [  Insiders ](/docs/insiders/)
* [  License ](https://capawesome.io/legal/eula/)
* [  Support ](/docs/insiders/support/)
* [  FAQ ](/docs/insiders/faq/)
* [  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)
* [  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](/docs/plugins/bluetooth-low-energy/) plugin 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](/docs/plugins/bluetooth-low-energy/) plugin. 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/plugins/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/plugins/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/plugins/bluetooth-low-energy/#startscan). As soon as a device is found, the [deviceScanned](/docs/plugins/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/plugins/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/plugins/bluetooth-low-energy/#discoverservices).
7. **Add the `characteristicChanged` listener**: We need to add a listener for the [characteristicChanged](/docs/plugins/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/plugins/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
`

## 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](/docs/plugins/bluetooth-low-energy/) plugin 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.

March 18, 2026 

 Back to top 