Bangle.js is an open, hackable smartwatch

Bangle.js 1 is no longer for sale, however you can now purchase the much improved Bangle.js 2!

You can easily install new apps from the web or develop your own using JavaScript or a graphical programming language (Blockly). All you need is a Web Browser (Chrome, Edge or Opera) and you can upload apps or write code to run on your watch wirelessly! Bangle.js is waterproof and AI enabled and comes with Bluetooth Low Energy, GPS, a heart rate monitor, accelerometer and more.

Just got your Bangle.js? Check out The Bangle.js 'Getting Started' page



  • IP68 Waterproof: up to 10m underwater
  • Nordic 64MHz nRF52832 ARM Cortex-M4 processor with Bluetooth LE
  • 64kB RAM 512kB on-chip flash, 4MB external flash
  • 1.3 inch 240x240 16 bit LCD display with 2 zone touch
  • GPS/Glonass receiver (UBlox)
  • Heart rate monitor
  • 3 Axis Accelerometer (with Pedometer and Tap detect)
  • 3 Axis Magnetometer
  • Vibration motor
  • 350mAh battery, 1 week standby time
  • 5 x 5 x 1.7 cm case, plastic with stainless steel ring
  • Can be disassembled with just 4 screws

Power Consumption

  • Idle, accelerometer on 12.5Hz - 0.35mA
  • Idle, accelerometer on 1.25Hz - 0.15mA (default if not moved)
  • BLE Connected in high bandwidth mode - 0.5mA
  • Compass on - 2mA
  • Heart rate monitor on - 2.5mA
  • 100% CPU usage running JavaScript - 7mA
  • GPS on - 30mA
  • LCD on - 40mA
  • Turned off - 0.08mA (0.6mA if turned off via Bootloader)

This means that when idle (in the normal power-on state) you can expect around 30-90 days of battery life depending on whether Bangle.js is moved or not.

Note: These figures are based on the latest Bangle.js firmware. Earlier firmwares have slightly higher power consumption figures.


The supplied charge cable connects to a USB port to charge Bangle.js (there is no data connection, it is power only).

You must connect the cable the right way around or it won't work: With Bangle.js facing away from you (so you're looking at the shiny back) and the CE Rohs text the right way up, the USB cable should exit from the left side of the watch.

The cable is magnetic and the wires are connected directly to USB power. Do not leave your cable plugged in or it might attract itself to the nearest magnetic (probably conductive) object and short out.

Powering off

  • Press the middle button BTN2 when at the watch face
  • Scroll down with BTN3 until you get to Settings
  • Press BTN2 to select
  • Scroll down with BTN3 to Turn Off
  • Press BTN2 to select it

Powering off if firmware is broken

This method uses Bangle.js's bootloader to turn off as a last resort. However, the bootloader is not as good at entering a low power state as the Espruino firmware, and so the battery may drain faster than if you could use the main Bangle.js 'off' functionality.

  • Long-press BTN1 + BTN2 for about 6 seconds until the screen goes blank
  • Keep pressing them while ==== goes across the screen
  • Watch will start vibrating
  • Release both buttons
  • Your watch may restart if it hasn’t been turned off since the last firmware update. If so, repeat the process again.


  • Long-press BTN1 + BTN2 for about 6 seconds until the screen goes blank
  • Release both buttons
  • Bangle.js will boot as if it just turned on normally (although the current time will be lost)

If you release the buttons too late you'll enter bootloader mode, in which case you need to press BTN1 to exit.

Resetting without loading any code

If you uploaded some code that runs at startup and breaks Bangle.js you may need to do this.

It won’t delete anything, so unless you fix/remove the broken code (see "Deleting all Code") Bangle.js will remain broken next time it restarts.

  • Long-press BTN1 + BTN2 for about 6 seconds until the screen goes blank
  • Release BTN2 but keep pressing BTN1 while ==== goes across the screen
  • Keep holding BTN1 while Bangle.js boots
  • Release it - you should have the Bangle.js logo, version, and MAC address

Note: In the 2v05 version shipped with Bangle.js KickStarter devices, Bangle.js would still load some parts of the bootloader. If you had turned off Bluetooth in Settings and then broke your Bangle's firmware you would be unable to connect in order to correct the problem. If this happens, install the latest firmware and follow these steps again, and you will then be able to connect.

Deleting all code

You can do this either while your watch is connectable, or if you have reset it without loading any code (above).


This will erase everything and install just the default apps.


Deleting apps

  • If you can access the menus on your device and the App Manager app is installed, you can delete apps using the App Manager
  • You can go to and click Connect. Under My Apps your installed apps are listed, and you can click the 'Bin' icon next to them to remove them
  • If you hit any issues with installed apps and can't access the menus on your device, then follow the instructions above for "Resetting without loading any code" above.


Tutorials using Bangle.js:

Tutorials using Bluetooth LE:

Tutorials using Bluetooth LE and functionality that may not be part of Bangle.js:

There are many more tutorials that may not be specifically for you device but will probably work with some tweaking. Try searching to find what you want.


LCD Screen

Bangle.js displays the REPL (JavaScript console) if Debug Info: show has been set in settings. If enabled, any calls like print("Hello") or console.log("World") will output to the LCD when there is no computer connected via Bluetooth. Any errors generated when there is no connection will also be displayed on the LCD.


You can output graphics on Bangle.js's display via the global variable g that is an instance of the Graphics class. By default the display is unbuffered, so any changes will take effect immediately.

// Draw a pattern with lines
for (i=0;i<64;i+=7.9) g.drawLine(0,i,i,63);
g.drawString("Hello World",30,30);

Screen buffering

Bangle'js's screen is 240 x 240 x 16 bits - which uses substantially more memory than the microcontroller has RAM. As such, draw commands go straight to the screen (and g.getPixel will not work).

Drawing straight to the screen can cause flicker, so for applications that need to update the screen constantly we'd suggest using Bangle.setLCDMode(...) to set the screen to a buffered mode. In a buffered mode, draw commands will not be visible until you call g.flip().

Available options for Bangle.setLCDMode are:

  • Bangle.setLCDMode("doublebuffered") - The drawable area is 240x160 16 bit, terminal and vertical scrolling will not work.
  • Bangle.setLCDMode("120x120") - The drawable area is 120x120 8 bit, g.getPixel and full scrolling work.
  • Bangle.setLCDMode("80x80") - The drawable area is 80x80 8 bit, g.getPixel and full scrolling work.

You can also call Bangle.setLCDMode() to return to normal, unbuffered mode.

Bangle.js comes with a built-in menu library that can be accessed with the E.showMenu() command.

E.showPrompt() and E.showMessage() can also be used for simple prompts and full-screen messages.

// Two variables to update
var boolean = false;
var number = 50;
// First menu
var mainmenu = {
  "" : {
    "title" : "-- Main Menu --"
  "Beep" : function() { Bangle.beep(); },
  "Buzz" : function() {; },
  "Submenu" : function() { E.showMenu(submenu); },
  "A Boolean" : {
    value : boolean,
    format : v => v?"On":"Off",
    onchange : v => { boolean=v; }
  "A Number" : {
    value : number,
    onchange : v => { number=v; }
  "Exit" : function() { E.showMenu(); },
// Submenu
var submenu = {
  "" : {
    "title" : "-- SubMenu --"
  "One" : undefined, // do nothing
  "Two" : undefined, // do nothing
  "< Back" : function() { E.showMenu(mainmenu); },
// Actually display the menu

See for more detailed information.


Bangle.js's LCD acts as a VT100 Terminal. To write text to the LCD regardless of connection state you can use Terminal.println("your text"). Scrolling and simple VT100 control characters will be honoured.

You can even move the JavaScript console (REPL) to the LCD while connected via Bluetooth, and use your bluetooth connection as a simple keyboard using the following commands:


On-device Peripherals

Most peripherals on the device are accessible via fields and events on the Bangle object.


There are no LEDs on Bangle.js. There are two 'fake' LED variables called LED1 and LED2 that create red and green fake LEDs at the top of the watch screen - these serve no purpose other than to allow tutorials for existing Espruino boards to be used.

Vibrate will make Bangle.js's vibration motor turn on. It takes optional time and strength arguments, and returns a promise. See the reference.

For example:>{
  return new Promise(resolve=>setTimeout(resolve,500)); // wait 500ms

Will do a short buzz followed by a long buzz and will print Done when finished.


You can use Bangle.beep() in much the same way as .buzz above to make sounds. See the reference.

To output an entire scale of notes, you could do:


Note: The majority of Bangle.js devices do not contain a piezo speaker, but instead use the vibration motor for sound. If you received your device and it doesn't make a noise when using Bangle.beep();, please update the Bootloader app via the App Loader.


There are 5 buttons on Bangle.js. The 3 physical buttons on the right are (top to bottom) BTN1, BTN2 and BTN3, and the screen has two touch areas, on the left (BTN4) and right (BTN5).

  • BTN1 - ‘Up/Previous’ in menus
  • BTN2 - ‘Select’ in menus, or bring up menu when in Clock
  • BTN3 - Down/Next in menus
  • BTN4 - Left-hand side of touchscreen. Used for some games, but not in menus
  • BTN5 - Right-hand side of touchscreen. Used for some games, but not in menus
  • You can access a button's state with digitalRead(BTN1) or (the two commands are identical). BTN is also defined, and is the same as BTN1.
  • Polling to get the button state wastes power, so it's better to use setWatch to call a function whenever the button changes state:
setWatch(function() {
}, BTN, {edge:"rising", debounce:50, repeat:true});


The accelerometer runs all the time and produces accel events on the Bangle object.

Bangle.on('accel', function(acc) {
  // acc = {x,y,z,diff,mag}

See the reference for more information.


When a sudden movement is detected, the accelerations in it are recorded and a gesture event is created.

If .tfmodel and .tfnames files are created in storage, Tensorflow AI will be run on the model with the gesture information and an aiGesture event will be created with the name of the detected gesture.


The compass can be turned on with Bangle.setCompassPower(1) and when enabled, mag events are created 12.5 times a second:

Bangle.on('mag', function(mag) {
  // mag = {x,y,z,dx,dy,dz,heading}

See the reference for more information.


The GPS can be turned on with Bangle.setGPSPower(1) and when enabled, GPS events are created once a second:

Bangle.on('GPS', function(gps) {
  // gps = {lat,lon,alt,speed,etc}

GPS-raw events are also created containing a String for each NMEA line that comes from the GPS receiver. These contain far more detailed information from the GPS.

See the reference for more information.

It's also possible to write data to the GPS to configure it. Check out the Bangle.js technical specs page for more info.

Heart rate

You can turn on the heart rate monitor with Bangle.setHRMPower(1), which will cause HRM events to be generated roughly every second:

Bangle.on('HRM',function(hrm) {
  /*hrm is an object containing:
    { "bpm": number,             // Beats per minute
      "confidence": number,      // 0-100 percentage confidence in the heart rate
      "raw": Uint8Array,         // raw samples from heart rate monitor

Beats per minute is calculated using autocorrelation.

See the reference for more information.

You can also access the heart rate detection hardware manually with:

Bangle.ioWr(0x80,0); // turn HRM on

var a = analogRead(D29); // read the raw PPG value

Firmware Updates

Please see the Firmware Update page for detailed instructions.


Check out:

Other Official Espruino Boards

This page is auto-generated from GitHub. If you see any mistakes or have suggestions, please let us know.