Most wearables spend their lives disconnected and sync in bursts. How fast and how reliably that burst moves data decides how long the radio stays on, how much battery a sync costs, and whether a user ever sees a missing day of data. Teams often assume the answer is a number from the Bluetooth specification. It is not: throughput depends on the negotiated parameters, the phone, the controller, interference and, most of all, how the sync protocol is designed on top.

This note covers both halves: getting bytes across the link efficiently, and designing a protocol that is resumable, loss-free and cheap. It is the engineering counterpart to our note on BLE pairing UX, and it builds on the offline backlog problem described in offline-first companion apps and wearable device firmware design constraints. In our smart ring and sleep coach work, data was batched and synced on a cadence, not streamed, because radio time is among the most power-expensive things such a device does.

Where throughput actually comes from

Data moves in connection events: at each connection interval the two radios meet, and exchange as many packets as the controllers allow before the event ends. Throughput is therefore roughly the payload per packet, times packets per event, divided by the interval. Each term is something you can influence, and each can be capped by the other side.

  • Connection interval. Shorter intervals give more events per second. The specification allows a wide range, but phones apply their own limits and preferences, and a sync that depends on an aggressive interval may not get it.
  • Data length extension. By default, a link-layer packet carries a small payload. The data length extension, available from Bluetooth 4.2, allows much larger packets, which reduces per-packet overhead. Both ends must support it and it has to be negotiated.
  • ATT MTU. The default is small enough that each notification carries very little application data. Negotiating a larger MTU lets a single notification span multiple link-layer packets. The maximum the specification allows is much larger than the default, and the value actually in force is whatever both sides agree.
  • PHY. Bluetooth 5 added a 2 Mbps PHY that moves the same bits in less airtime, which can save energy per byte when the signal is good. A longer-range coded PHY trades speed for robustness. Support varies by phone and chip.
  • Write mode. Notifications and writes without response avoid waiting for a protocol-level acknowledgement of every packet and so can keep the link busy. Indications and writes with response wait for confirmation and are much slower for bulk data.
  • Packets per event. How many packets fit in one event depends on the controller and the host stack on both sides, and is often the least controllable term. Measure it on the phones you care about.

A useful habit: treat the maximum as something to measure, not assume. Log the negotiated interval, MTU, data length and PHY at the start of every sync in your test builds, and you will quickly see why two phones differ.

Optimize for energy per byte, not just speed

For a battery device the goal is to finish the sync quickly and go back to sleep. Faster transfer means less time with the radio on, which usually saves more energy than the higher power of a short interval costs. Practical consequences:

  • Request faster parameters for the duration of a sync and relax them for idle connection, within the limits the phone will accept.
  • Reduce the number of bytes before optimizing how they travel: compact binary records, delta-encoded timestamps and values, and compression where the data is compressible.
  • Disconnect or move to a lazy connection when there is nothing to send. Staying connected costs energy, and advertising aggressively costs more.
  • Batch records so that each wakeup of the radio does as much useful work as possible. See power profiling firmware to verify the effect on real current.

Designing the sync protocol

The link layer delivers packets in order and retransmits losses while the connection is up. It does not give your application a reliable bulk-transfer guarantee, because connections drop, the phone's app can be suspended, buffers can overflow and a transfer can end halfway. The application protocol has to supply what is missing.

device -> phone   HELLO     { proto_ver, device_id, oldest_seq, newest_seq }
phone  -> device   REQUEST   { from_seq, max_records }          // the cursor lives on the phone
device -> phone   CHUNK     { chunk_id, first_seq, n, payload, crc16 }   // repeated
phone  -> device   ACK       { highest_contiguous_seq }          // cumulative, per window
        ... repeat until caught up ...
phone  -> device   COMMIT    { durable_through_seq }             // phone has stored it
device:            erase / reuse flash only up to durable_through_seq

Sequence numbers and a cursor

Every record gets a monotonically increasing sequence number when it is written on the device, and the sync is defined in terms of those numbers: "send me everything after N". A dropped link then costs only the unacknowledged part, and a resumed sync starts from the cursor rather than from the beginning.

Windowed, cumulative acknowledgements

Acknowledging every packet wastes airtime and stalls the link. Send a window of chunks and acknowledge cumulatively, reporting the highest contiguous sequence received, so the device can retransmit only from the first gap. Choose the window size to keep the radio busy without overrunning the phone's buffers.

Two-phase commit before erasing

This is the rule that prevents data loss: the device must not erase a record from flash because the phone received it, but because the phone stored it durably. Hence the separate commit message. If the app crashes or the user force-quits after receiving data but before saving it, the device still has the records and the next sync can send them again.

Idempotence and deduplication

Retries will deliver records more than once. Make processing idempotent by keying records on device identity and sequence number, so that duplicates are harmless on the phone and in the cloud, and the sync can be retried without fear.

Integrity checks

The link has a CRC, but end-to-end integrity is still your concern: bugs in stacks and in your own reassembly code do occur. Add a checksum per chunk and consider a check over the whole transfer, plus a record format that can be validated independently of the transport.

Versioning

Devices in the field run old firmware and phones run new apps, and the reverse. Put a protocol version and schema version in the handshake and make the app tolerate old formats. Fixing a framing bug on a million deployed devices is not a pleasant option.

Flow control

A fast device can overrun a phone that is slow to drain its notification queue. Use the window and acknowledgements as backpressure, and have the device stop sending when acknowledgements stop arriving rather than queueing indefinitely.

Phones are part of your system

Behavior differs across operating systems and versions, and the differences show up exactly in a sync flow.

  • Connection parameters. Both major platforms constrain the values a peripheral can request, and may ignore some requests. Check the platform's current accessory or peripheral guidance for the supported ranges instead of relying on memory.
  • Background behavior. A sync that runs while the app is in the background is subject to operating-system limits on background Bluetooth work and on how and when the app is woken. Design the flow so that it can complete in short windows and resume.
  • MTU and data length. What is negotiated differs by platform and by phone model. Do not hard-code assumptions about it.
  • Vendor variation. Android devices differ widely in their Bluetooth stacks. A device farm covering the models your customers actually use is worth more than any specification.

The firmware side of connection handling is summarized in the pairing note; here, the point is that your protocol must hold up on the worst phone, not the best.

Security on the sync path

Health and activity data is personal. Use LE Secure Connections for pairing where possible and an encrypted link for the sync, and consider whether payloads need application-level protection that survives past the radio, for example if data is relayed through the phone to the cloud. Authenticate who may request a sync so that a nearby device cannot read a backlog. Related background is in firmware security and secure boot and HIPAA-compliant health device data.

Testing the sync, not the happy path

  • Kill the link mid-transfer. At random points, including during the commit. Verify no loss and no duplication.
  • Kill the app. After receiving but before storing. The device must still have the data.
  • Fill the buffer. A very large backlog, after days of absence, should still complete in multiple sessions.
  • Inject packet loss and interference. A busy radio environment shows protocol weaknesses that a quiet lab hides.
  • Use a sniffer. A Bluetooth packet capture shows what really happened on air, including renegotiation you did not know about.
  • Measure energy per sync. Track current and time per megabyte, or per day of data, as a regression metric across firmware versions.
  • Run old against new. Test old firmware with the new app and the reverse, since both exist in the field.

Checklist

  • Do you log the negotiated interval, MTU, data length and PHY on every test sync?
  • Are records sequenced, with the cursor held by the phone?
  • Are acknowledgements windowed and cumulative?
  • Does the device erase only after a durable commit?
  • Is processing idempotent end to end?
  • Is there a protocol version in the handshake?
  • Has the sync been tested with link loss, app kill, large backlogs and several phone models?

Common questions

How do you increase BLE throughput on a wearable?

Negotiate a larger ATT MTU and enable data length extension, use a short connection interval during the sync, use notifications or writes without response for bulk data, consider the 2M PHY where supported, and reduce the data itself with compact encoding. Then measure on the real phones, because the achieved rate depends on the phone and controller.

Why not just stream sensor data over BLE?

Radio time is one of the most power-expensive things a small wearable does. Batching data and syncing in short bursts, or sending only processed events, usually extends battery life considerably compared with continuous streaming.

How do you avoid losing data during a BLE sync?

Give every record a sequence number, acknowledge cumulatively, and delete data on the device only after the phone confirms it has stored it durably, in a separate commit step. Make processing idempotent so retries do not create duplicates.

Why does BLE behave differently on different phones?

Operating systems and Bluetooth chip vendors constrain connection parameters, MTU and background behavior differently, and Android stacks vary widely between manufacturers. The sync protocol has to be tested on a spread of real devices and designed for the worst case.