BLE Advertising Payloads: Fit Device Identity into Legacy Advertising and Scan Responses
A device can advertise successfully yet never appear in the product app. The cause may be a payload contract: the app filters for a service UUID that firmware moved into the scan response, or it requires a complete name that no longer fits. Fix discovery by allocating bytes deliberately and specifying which information must be available in the first advertisement.
For qualification, consult the SIG’s Core 6.0 page and its mandatory updates. This engineering guide is not a compliance checklist.
Scope: this guide uses legacy, undirected, scannable BLE advertising with a 31-byte advertising-data budget and a separate 31-byte scan-response-data budget. The design baseline is Bluetooth Core 6.0, Supplement v15 data-type definitions (5 May 2026) and Zephyr 3.7.0 where SDK behavior is discussed. These are deliberate reference versions, not a claim that they are the latest. Sources were checked on 11 October 2026.
Choose the compatibility boundary before packing bytes
The Bluetooth SIG’s LE primer distinguishes legacy and extended advertising capacities. Extra extended-advertising capacity does not make an existing legacy scanner compatible. Record the controller, host stack and receiving application capabilities before changing advertising mode simply to accommodate a longer name.
Also separate advertisement contents from GATT contents. Nordic’s services and characteristics lesson describes the GATT database structure. Declaring a service there does not automatically document how your advertising builder exposes it. Keep the service implementation and the pre-connection discovery contract as two reviewable artifacts.
Count complete AD structures
Each AD structure contains a one-byte Length, a one-byte Type and its data. Length counts Type plus data, excluding the Length byte itself. Therefore a data value of N bytes occupies N + 2 bytes in the packet. This follows Core 6.0 GAP section 11. Counting only the visible name or UUID bytes underestimates the budget.
The following layout is an original allocation example. Its manufacturer field is a size model, not an assigned company identifier or a ready-to-transmit product identity.
| Advertising field | Data bytes | Length + Type | Total |
|---|---|---|---|
| Flags | 1 | 2 | 3 |
| One 128-bit service UUID | 16 | 2 | 18 |
| Manufacturer field: company ID plus six product bytes | 8 | 2 | 10 |
| Advertising total | 25 | 6 | 31 |
The manufacturer payload can allocate its six product bytes to a format version, product class, setup flags and a three-byte display tag. This is a proposed schema, with collision and privacy properties to assess separately. The scan response can contain the 12-byte ASCII name “EnvSensor-7A”; its AD structure uses 14 bytes and leaves 17 bytes unused. Unused scan-response capacity cannot rescue an oversized advertising structure.

Give each field an honest meaning
Supplement v15 Part A distinguishes complete and shortened names, complete and incomplete service lists, and manufacturer data beginning with a two-byte company identifier. A shortened name must be a prefix of the full name. Do not truncate a name while continuing to label it complete, or advertise a partial service list as complete.
Budget names in UTF-8 bytes rather than characters. A user-assigned multilingual name may fit a character limit while exceeding the serialized byte limit. If shortening is allowed, stop on a valid character boundary and use the shortened-name type. Do not borrow a standard 16-bit service UUID solely to save fourteen bytes; use identifiers appropriate to the actual service.
Treat scan response as optional enrichment
Passive scanning does not request additional information. Active scanning can request a scan response from a scannable advertiser, as specified in Core 6.0 Link Layer section 4.4.3. This is a separate exchange, so design first-stage eligibility around fields in the advertisement itself.
For the example, the app can recognize the service UUID before receiving a name. It can display a product-class label and later replace it with a valid advertised name. A missing scan response should not silently discard an otherwise eligible device. Neither a name nor a short display tag proves authenticity; establish trust through the product’s connection and application-security design.
Inspect the bytes the SDK actually builds
In Zephyr 3.7.0 GAP, bt_le_adv_start accepts separate advertising and scan-response arrays. Its array-length arguments count elements, not serialized octets. The deprecated automatic-name option can place the name in scan-response data and shorten it when necessary. Explicit field construction makes the intended allocation easier to inspect.
Keep a build-time byte-budget assertion for each array, then inspect the serialized output and advertising-start return value. A successful build does not establish that the controller accepted the configuration. Check runtime name changes too: a new string can invalidate a previously valid allocation. Record actual field placement instead of relying on a scanner application’s combined display.
Validate boundaries and receiver assumptions
- Construct exact-fit 31-byte advertising data, then add one product byte. The builder should reject the 32-byte result before starting legacy advertising.
- Validate every structure length against remaining bytes. Reject a structure that runs beyond the received buffer; handle fixed-field zero padding separately from meaningful structures.
- Test empty, short, exact-fit and multilingual names. Confirm the declared name type and UTF-8 boundaries match the emitted bytes.
- Capture advertising and scan response separately on authorized test hardware. Compare passive and active scans rather than assuming both deliver the same fields.
- Run the production app filter against saved byte fixtures with the name absent, delayed or shortened. The discovery decision should still match the agreed contract.
- Publish an internal protocol table containing AD type, location, byte order, maximum length, version and behavior when absent or unknown.
The arithmetic in this example can be checked offline; reception and phone compatibility require hardware tests. Release when firmware and app agree on essential first-packet fields and reject malformed or oversized structures predictably. That contract prevents a cosmetic name change from becoming a discovery outage.