Skip to contentHacker gift guide · Christmas 2026

BLE Beacons for Beginners: Scan and Decode Bluetooth LE

BLE beacons for beginners: how Bluetooth Low Energy advertising works and how to decode iBeacon and Eddystone on your own beacon with nRF Connect and Python.

Published on 7 min read

A BLE beacon is a small Bluetooth Low Energy transmitter that repeats a short message, an "advertising packet", which any phone can pick up without connecting. To decode it, all you need is a phone with the nRF Connect app, then Wireshark or a few lines of Python when you want to go further. This guide explains what's inside a packet and how to read the two most common beacon formats, iBeacon and Eddystone, on your own hardware.

A simple practice target: an off-the-shelf BLE beacon, an ESP32 (a microcontroller board costing a few euros with built-in Bluetooth) programmed as a beacon, or the advertiser feature in some Android apps.

BLE vs classic Bluetooth

Bluetooth Low Energy (BLE) arrived with version 4.0 of the Bluetooth standard. It shares the same 2.4 GHz band as classic Bluetooth, but it's a different protocol built for the opposite use case.

Classic BluetoothBluetooth Low Energy
Typical useHeadphones, speakers, carsWatches, sensors, trackers, beacons
Channels79 channels of 1 MHz40 channels of 2 MHz, 3 of them for advertising
TrafficContinuous, for audioSmall, intermittent packets
PowerRechargeable batteryMonths or years on a coin cell
DiscoveryPairingAnnouncements broadcast to everyone (advertising)

The key idea in BLE is advertising: a device regularly announces itself on three reserved channels, numbered 37, 38 and 39 (2402, 2426 and 2480 MHz). A scanning phone listens on those three channels. A beacon does nothing else: it doesn't wait for connections, it just broadcasts.

Anatomy of an advertising packet

A standard ("legacy") BLE advertising packet looks like this, simplified:

┌────────────┬────────────┬────────┬──────────────┬────────────────────┬─────┐
│ Preamble   │ Access     │ PDU    │ Device       │ Advertising data   │ CRC │
│ 1 byte     │ address    │ header │ address      │ 0 to 31 bytes      │     │
│            │ 8E89BED6   │        │ 6 bytes      │                    │     │
└────────────┴────────────┴────────┴──────────────┴────────────────────┴─────┘

The interesting part is the 31 bytes of advertising data. They're split into "AD structures", each in length, type, value format:

02 01 06                      → length 2, type 0x01 (Flags), value 0x06
1A FF 4C 00 02 15 …           → length 26, type 0xFF (manufacturer data)…

The most common types:

TypeMeaning
0x01Flags: the device's discovery mode
0x09Complete device name
0x03List of services (16-bit UUIDs)
0x16Service data (a 16-bit UUID followed by data)
0xFFManufacturer-specific data (2-byte company ID, then free-form data)

Two useful notes. First, 31 bytes isn't much: every beacon format is an exercise in compression. Second, the device address isn't always fixed: phones and many recent devices use random addresses that change regularly, precisely to make tracking harder. A beacon, by contrast, often keeps the same address, because it's meant to be recognised.

The tools: nRF Connect, Wireshark, bleak

nRF Connect for Mobile

This free app from Nordic Semiconductor, a BLE chipmaker, runs on Android and iOS. The Scanner tab lists nearby devices with their received signal strength (RSSI, in dBm) and, when you tap one, shows the raw and decoded advertising data. It's the ideal place to start.

One limitation: iOS doesn't pass iBeacon frames to general-purpose Bluetooth apps. To study an iBeacon, use Android or a computer.

Wireshark

Wireshark, the standard network traffic analyser, can decode BLE. There are two ways to feed it packets:

  • Capture your own computer's Bluetooth interface on Linux: you see what your adapter receives and sends, which is enough for advertisements.
  • Use a dedicated sniffer, such as Nordic's nRF Sniffer for Bluetooth LE on an nRF52840 dongle, to capture packets straight off the air.

For a beginner, the first option is plenty.

bleak (Python)

bleak is an open-source Python library that runs on Linux, macOS and Windows. It lets you write your own scanner in a few lines, and therefore understand every byte.

python -m pip install bleak

Decoding iBeacon and Eddystone on your own beacon

iBeacon

Apple's iBeacon format lives in the manufacturer data (type 0xFF) under Apple's company ID, 0x004C. The bytes that follow:

BytesFieldPurpose
10x02iBeacon type
10x15Remaining length: 21 bytes
16UUIDIdentifies the organisation or deployment
2MajorA group (for example a building)
2MinorA specific beacon (for example a room)
1Measured powerExpected RSSI at 1 metre, signed dBm

So an iBeacon only broadcasts identifiers. It's the app that knows "UUID X, major 3, minor 12" means the cheese aisle in a shop.

Eddystone

Eddystone, the open format launched by Google, uses service data (type 0x16) with the service UUID 0xFEAA. The first byte gives the frame type. The project was archived at the end of 2022, but its specification is still online and many beacons still speak it.

Type byteFrameContent
0x00UID10-byte namespace and 6-byte instance
0x10URLA compressed URL
0x20TLMTelemetry: battery voltage, temperature, counters
0x30EIDAn encrypted identifier that changes periodically

The URL frame makes a nice decoding exercise: one byte encodes the prefix (0x00 for http://www., 0x01 for https://www., 0x02 for http://, 0x03 for https://) and some bytes stand for common suffixes (0x00 for .com/, 0x07 for .com, and so on).

A Python scanner

This script listens for 10 seconds and decodes iBeacon and Eddystone packets. Run it next to your beacon.

import asyncio
import struct

from bleak import BleakScanner

APPLE_ID = 0x004C
EDDYSTONE_UUID = "0000feaa-0000-1000-8000-00805f9b34fb"


async def main():
    found = await BleakScanner.discover(timeout=10.0, return_adv=True)
    for address, (device, adv) in found.items():
        apple = adv.manufacturer_data.get(APPLE_ID)
        if apple and len(apple) >= 23 and apple[0] == 0x02 and apple[1] == 0x15:
            uuid = apple[2:18].hex()
            major, minor = struct.unpack(">HH", apple[18:22])
            power = struct.unpack("b", apple[22:23])[0]
            print(f"iBeacon {address} uuid={uuid} major={major} "
                  f"minor={minor} power@1m={power} dBm rssi={adv.rssi}")

        eddy = adv.service_data.get(EDDYSTONE_UUID)
        if eddy:
            frame = {0x00: "UID", 0x10: "URL", 0x20: "TLM", 0x30: "EID"}.get(eddy[0], "?")
            print(f"Eddystone-{frame} {address} data={eddy.hex()} rssi={adv.rssi}")


asyncio.run(main())

Ways to build on this script:

  1. Compare the received RSSI with the advertised measured power as you walk away from the beacon: you get a rough distance estimate, and you'll quickly see why it's so unreliable indoors.
  2. Write the function that rebuilds the URL from an Eddystone-URL frame.
  3. Change your beacon's major and minor and check that your decoder keeps up.

On macOS, the system may also hide iBeacon frames: if your beacon doesn't show up, try Linux or Windows.

What about other people's beacons?

Your scanner will also show your neighbours' devices: watches, earbuds, TVs. Listening to these public announcements is passive; your phone does it all the time. But that's where the exercise stops: don't connect to a device that isn't yours, don't change its data, and don't try to track a person through their devices' advertisements. Your own beacon is all you need.

Going further: the BLE Beacon Decode Challenge

Once iBeacon and Eddystone feel familiar, the natural next step is a beacon whose message isn't in plain text. That's the idea behind our BLE Beacon Decode Challenge puzzle: a card-sized beacon powered by a CR2032 coin cell broadcasts a message to decode across three honestly labelled levels. A phone is enough for level one, a computer helps for the next two, there's nothing to solder, and the official solution is published 60 days after delivery.

The puzzle is planned for summer 2027 at €32: join the waitlist from its page or from our CTF puzzles page. Meanwhile, if the challenge format appeals to you, our guide What Is a CTF in Cybersecurity? shows where to practise, and getting started with hardware hacking places BLE among the other disciplines.

Frequently asked questions

What is Bluetooth Low Energy?

A variant of Bluetooth introduced with version 4.0 and designed to use very little power. It's used by watches, sensors, trackers and beacons that run for months on a coin cell. It shares the 2.4 GHz band with classic Bluetooth but isn't compatible with it.

Why doesn't my iPhone show my iBeacon in nRF Connect?

iOS doesn't pass iBeacon frames to general-purpose Bluetooth apps. To look at an iBeacon, use an Android phone or a Linux or Windows computer.

Listening to the public advertisements devices broadcast is passive, and every smartphone does it all the time. Connecting to a device that isn't yours, changing its data or tracking a person through their devices is not acceptable. Run your experiments on your own beacons.

Related articles

What is UART? The serial port hidden on circuit boards. Find TX, RX and GND, work out the baud rate and safely read the boot console of a device you own.
USB logic analyzer tutorial: install PulseView, then decode an Arduino's UART, a sensor's I2C and an SPI flash chip. Plus: cheap clone or Saleae?
RTL-SDR beginner guide: install drivers on Windows (Zadig), Linux and macOS, choose SDR++, SDR# or GQRX, tune your first FM station and fix common errors.