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.
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 Bluetooth | Bluetooth Low Energy | |
|---|---|---|
| Typical use | Headphones, speakers, cars | Watches, sensors, trackers, beacons |
| Channels | 79 channels of 1 MHz | 40 channels of 2 MHz, 3 of them for advertising |
| Traffic | Continuous, for audio | Small, intermittent packets |
| Power | Rechargeable battery | Months or years on a coin cell |
| Discovery | Pairing | Announcements 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:
| Type | Meaning |
|---|---|
0x01 | Flags: the device's discovery mode |
0x09 | Complete device name |
0x03 | List of services (16-bit UUIDs) |
0x16 | Service data (a 16-bit UUID followed by data) |
0xFF | Manufacturer-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:
| Bytes | Field | Purpose |
|---|---|---|
| 1 | 0x02 | iBeacon type |
| 1 | 0x15 | Remaining length: 21 bytes |
| 16 | UUID | Identifies the organisation or deployment |
| 2 | Major | A group (for example a building) |
| 2 | Minor | A specific beacon (for example a room) |
| 1 | Measured power | Expected 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 byte | Frame | Content |
|---|---|---|
0x00 | UID | 10-byte namespace and 6-byte instance |
0x10 | URL | A compressed URL |
0x20 | TLM | Telemetry: battery voltage, temperature, counters |
0x30 | EID | An 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:
- 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.
- Write the function that rebuilds the URL from an Eddystone-URL frame.
- 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.
Is it legal to scan BLE beacons around me?
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.