Chapters

15 CoAP Observe Freshness Contracts

coap
observe
server-push
reliability

A wall display receives a room temperature and then loses its connection. A green tile without a freshness warning can imply that the room is still being watched. An Observe client needs a freshness decision even when the value itself has not changed.

15.1 Start With the Stale Alarm

Treat Every Update as Fresh Only Until Proven Otherwise

Picture a clinic room sensor that sends a new temperature only when the value changes. A wall screen loses contact for ten minutes, then shows its last update beside a current time. The nurse may act on an old fact unless the client can tell its age and source.

CoAP is a web-style exchange method for small devices. Observe is its way for a client to ask for later updates. Record the client, server, request identity, update identity, start time, allowed age, last accepted order value, and rule for ending or renewing the request.

Delay one update, change their order, drop several, restart each side, let the age limit expire, and wrap the order value. Check that a late item cannot replace a newer one and that silence becomes an explicit unknown state rather than a false healthy state.

A successful message only proves delivery for that exchange. It does not prove sensor accuracy, a current room state, or continued server health. The screen must show age and uncertainty clearly enough for the nurse to choose a safe next step.

Practitioner builds the freshness and renewal policy. Under the Hood explains tokens, age fields, confirmation, order comparison, wrap rules, pacing, and the limits of best-effort updates.

Use this fresh-state review:

  • Record when the request began.
  • Bind each update to that request.
  • Show the age beside the value.
  • Set the oldest useful age.
  • Delay one update past that age.
  • Send two updates out of order.
  • Drop enough updates to create doubt.
  • Restart the client and server.
  • End the request on purpose.
  • Test renewal after a long gap.
  • Display silence as an unknown state.
  • Keep the failed trace for review.

An alarm notification that arrives late can be worse than no notification if the client treats it as current. Observe therefore needs more than “server push”: the client must know which registration a notification belongs to, whether the value is fresh, and what to do when UDP reorders updates.

This page follows the subscription through token binding, Max-Age, liveness checks, sequence comparison, cancellation, and stale-update rejection so the pushed value can be trusted.

15.2 Learning Objectives

After this page, you should be able to:

  • Trace a CoAP Observe registration from GET with Observe: 0 through token-bound notifications and cancellation.
  • Design Max-Age, Confirmable notification, and re-registration policies for best-effort notification streams.
  • Apply the RFC 7641 Observe-value comparison rule to reordered, skipped, and wrapped 24-bit sequence values.
  • Capture the lifecycle, freshness, pacing, and stale-update evidence needed to review an Observe deployment.

15.3 Why This Contract Comes After Observe Server Push

CoAP Observe Server Push teaches the main Observe pattern: replace repeated polling with change-driven notifications. This page narrows in on the deeper operational contract that makes the pattern safe: which token identifies the subscription, how long a value remains fresh, how the server detects unreachable observers, and how the client rejects stale notifications when UDP reorders datagrams.

The CoAP Observe contract therefore keeps the parent idea intact while adding the evidence needed for token binding, freshness, liveness, cancellation, and stale-update rejection.

Use it when an observed resource controls alarms, industrial telemetry, building automation, battery gateways, NAT-crossing clients, or any application where a stale pushed value could be mistaken for current state.

Overview: Register Once, Then Receive Pushes

Observe (RFC 7641) adds a lightweight publish/subscribe relationship on top of plain CoAP request/response, using a single option numbered 6. A client registers by sending an ordinary GET with the Observe option set to 0. The server records the client — keyed by its source endpoint, its Token, and the requested resource — and answers 2.05 Content that itself carries an Observe option holding a sequence number. From that moment the client is an observer.

Whenever the resource's representation changes, the server sends a fresh 2.05 Content notification carrying an incremented Observe value and, crucially, the same Token as the original registration. That Token is how the client knows an unsolicited notification belongs to a subscription it opened. To stop, the client either sends a GET with Observe set to 1 (explicit cancel) or rejects a Confirmable notification with an RST.

A concrete trace shows the contract. If a dashboard registers GET /sensors/temp with Token 0x4a01, the server might answer 2.05 Content, Observe 12, and Max-Age: 60. Fourteen seconds later the pushed update uses a new Message ID but the same Token 0x4a01 and Observe 13. The client must keep that Token reserved while the observation is active; reusing it for another outstanding exchange would make later pushes ambiguous.

ServerClientServerClientResource value changesGET (Observe: 0, Token)2.05 Content (Observe: 12, Token)2.05 Content (Observe: 13, same Token)2.05 Content (Observe: 14, same Token)

Inspect Figure to connect the registration exchange above with the server registry and notification state it creates.

CoAP implementation patterns showing confirmable, non-confirmable, acknowledgement, and reset message types alongside RESTful methods and the Observe pattern for pushed updates.
A CoAP resource keeps observer registry entries keyed by client endpoint, Token, and URI, then fans out 2.05 notifications with increasing Observe values whenever the resource changes.

Read Figure from message types and REST methods into the Observe relationship. The server keys an observer entry by endpoint, Token, and resource URI, then emits `2.05 Content` notifications with advancing Observe values when that resource changes. The Token preserves relationship identity while freshness rules order updates. Those separate responsibilities frame the failure and re-registration contracts developed next.

Register

GET with Observe = 0. Server replies 2.05 Content plus an Observe option (starting sequence number).

Notify

On each change the server sends 2.05 Content with a higher Observe value, reusing the registration Token.

Cancel

GET with Observe = 1, or reject a CON notification with RST, to end the relationship.

Token binding

The Token ties every later notification to the subscription; without it the client cannot match a push.

Practitioner: Notifications Are Best-Effort, So Max-Age and CON Checks Matter

Observe promises eventual consistency, not guaranteed delivery. Notifications are usually Non-confirmable, so any single one may be lost; the model only guarantees that the client eventually converges on the current state through later notifications. That has two practical consequences you must design for: freshness and liveness.

Freshness is governed by Max-Age. Each notification says how long its value can be considered current. A well-behaved server sends the next notification before the previous one's Max-Age expires, so a live resource never looks stale; if the client's Max-Age lapses with no new push, the client should re-GET (re-register) rather than trust an aged value. Liveness is checked with the occasional Confirmable notification: if its retransmissions all go unanswered, the server concludes the observer is gone and removes it, which is how "ghost observers" behind a closed NAT binding get cleaned up.

For example, a battery gateway observing /tank/level might send ordinary NON notifications only when the level changes by at least 2% or every 60 seconds, whichever comes first, with Max-Age: 120. The client treats silence for 120 seconds as stale and re-registers instead of assuming the last level is still safe. The server might make every tenth notification Confirmable, or use a five-minute CON probe, so closed NAT bindings and rebooted clients are detected without turning every update into an ACK exchange. If the sensor chatters around the 2% threshold, the server should coalesce changes and publish the newest value at the pacing limit; Observe reduces polling traffic only when push frequency is also controlled.

Mechanism
Purpose
What the client should do
Evidence to capture
Max-Age on notifications
Bounds how long a value is fresh
Re-register if Max-Age lapses with no push
Trace shows notify interval below Max-Age
Occasional CON notify
Confirms observer is still reachable
ACK it to stay registered
Server log shows CON, then observer kept or dropped
Rate limiting / pacing
Prevents flooding on fast-changing data
Tolerate coalesced updates
Notify rate stays within link and client budget

Under the Hood: The Observe Value Orders Notifications Despite UDP Reordering

Because CoAP runs over UDP, notifications can arrive out of order: a client may receive an older reading after a newer one. If it simply trusted arrival order it would display stale data. The Observe option value — a number up to 24 bits wide that the server increments per notification — exists to solve exactly this, and RFC 7641 defines a precise comparison so wraparound does not fool the client.

Let V1 be the value of the notification the client currently accepts, received at time T1, and V2 the value of a newly arrived notification at time T2. The new notification is treated as fresher only if (V1 < V2 and V2 − V1 < 2^23) or (V1 > V2 and V1 − V2 > 2^23) — the two cases that correctly handle counter wraparound — or if more than 128 seconds have elapsed (T2 > T1 + 128 s), after which the later arrival simply wins regardless of value. Anything that fails all three tests is a reordered straggler and is discarded.

Suppose the client has accepted Observe 120 and then receives 124; because the difference is small and positive, 124 becomes the new displayed state. If 122 arrives two seconds later, it is discarded as a late datagram. Near wraparound, a server can move from 16777214 to 1; the large reverse numeric difference tells the client that 1 is actually newer, not older. After a long quiet period above 128 seconds, the client accepts the later arrival as a new baseline because old ordering evidence has expired.

This is why the Observe value must be read as a reordering sequence number, not as a reliable event counter. Lost Non-confirmable notifications mean the numbers a client sees can skip; the guarantee is ordering and eventual convergence, not that every increment is delivered.

Observe value

Up to 24 bits, incremented per notification, used purely to decide which of two notifications is newer.

Wraparound window

The 2^23 threshold distinguishes a genuine increment from a wrapped-around older value.

128-second rule

After 128 s, the later arrival is accepted regardless of the numeric comparison.

Straggler drop

A notification failing all freshness tests is a reordered duplicate and is silently discarded.

15.4 Let the Temperature Tile Become Unknown

Use an illustrative notification received at elapsed time 100 s with Max-Age of 30 s. Its freshness allowance runs out at 130 s if nothing renews it. At 125 s, 5 s remain. At 131 s, the display should follow its stale-data policy instead of presenting the temperature as current. Freshness measured from receipt does not establish the physical sample time unless the payload also carries it.

Suppose the accepted Observe value is 100, then 102 arrives, followed shortly by delayed value 101. Under the normal ordering comparison for this small interval, 102 is newer and 101 must not replace it. Skipping a sequence value does not by itself prove a lost critical event: notifications may represent changing resource state rather than a complete event history. An Observe application that requires every transition needs a separate durable event-history contract.

The freshness timer and ordering rule answer different questions. Ordering asks which representation is newer within the registration. Max-Age asks how long the accepted representation may be treated as fresh. A higher Observe value does not grant indefinite freshness, and an old packet arriving late must not silently renew confidence in an obsolete state.

Predict the result when the room stays at the same temperature but all later communication stops. The tile still becomes unknown when its freshness allowance expires; unchanged physical conditions cannot be inferred from silence. Next, restart the client and lose its reserved Token. A renewed Observe registration must not accept an arbitrary old notification as its own continuation.

This is why Observe contracts matter to alarm design. A display can keep the last temperature for context while marking its age and loss of freshness clearly. A separate warning can indicate that the monitoring path needs attention. Re-registration, confirmation and cancellation rules then restore a bounded relationship with the server. They do not turn best-effort updates into a guarantee that every physical event was observed.

15.5 Release Checklist

Before shipping a CoAP Observe contract, verify these records:

Read these points as one connected sequence: start with Registration state is keyed by client endpoint, request Token, and resource URI, and the Token stays reserved while the observation is active; then Notification policy names which updates are Non-confirmable, which are occasional Confirmable liveness probes, and when failed probes remove the observer; then Freshness policy sets Max-Age for each observed resource and says what the client does when no notification arrives before that value expires; then Ordering policy implements the RFC 7641 24-bit Observe-value comparison, including the 2^23 wraparound window and the 128-second fallback; then Pacing policy documents change thresholds, coalescing, maximum notification rate, and evidence that Observe reduces traffic instead of creating a push flood; and finish with Recovery behavior covers explicit Observe: 1 cancellation, RST cancellation, client reboot with token loss, NAT binding expiry, resource deletion, and re-registration.

  • Registration state is keyed by client endpoint, request Token, and resource URI, and the Token stays reserved while the observation is active.
  • Notification policy names which updates are Non-confirmable, which are occasional Confirmable liveness probes, and when failed probes remove the observer.
  • Freshness policy sets Max-Age for each observed resource and says what the client does when no notification arrives before that value expires.
  • Ordering policy implements the RFC 7641 24-bit Observe-value comparison, including the 2^23 wraparound window and the 128-second fallback.
  • Pacing policy documents change thresholds, coalescing, maximum notification rate, and evidence that Observe reduces traffic instead of creating a push flood.
  • Recovery behavior covers explicit Observe: 1 cancellation, RST cancellation, client reboot with token loss, NAT binding expiry, resource deletion, and re-registration.

15.6 See Also

Read these points as one connected sequence: start with CoAP Observe Server Push for the parent tutorial and implementation workflow; then CoAP Message Types for CON, NON, ACK, RST, and retransmission mechanics; then CoAP Message Format for Token, option, and Message ID fields; then CoAP Implementation Labs for code patterns that maintain observer registries and notification pacing; and finish with MQTT Broker and Topics for a broker-mediated pub/sub comparison.

15.7 Next

Return to CoAP Observe Server Push, then continue to CoAP Advanced Features for block-wise transfer and large-payload considerations.