diff --git a/src-docs/shared_state/conflicts.md b/src-docs/shared_state/conflicts.md
index 0486f5f..c4ab7d6 100644
--- a/src-docs/shared_state/conflicts.md
+++ b/src-docs/shared_state/conflicts.md
@@ -29,6 +29,13 @@ both a Total Order of messages and a "single source of truth" can not be assumed
Many webxdc applications are incapable of producing conflicts,
either because they do not use the network communication APIs,
or because any given data structure can only have one writer.
+Alternatively, an application can designate a "central" authority
+by checking [`webxdc.appSenderAddr`](../spec/selfAddr_and_selfName.html#appsenderaddr)
+to identify the user who shared the app.
+This peer could then authoritatively resolve conflicts or coordinate state updates.
+However, developers should be aware that if the app depends entirely on the sender being online,
+the app's availability will be limited when the sender is offline.
+
For example, many of the available [webxdc games](https://webxdc.org/apps/) offer a high-score table
and how users scored will typically be reported back to the chat.
Such a gaming app will simply post their user's highscore
diff --git a/src-docs/shared_state/crdts.md b/src-docs/shared_state/crdts.md
index cb60f8f..1ab41b7 100644
--- a/src-docs/shared_state/crdts.md
+++ b/src-docs/shared_state/crdts.md
@@ -146,11 +146,13 @@ This enables peers to queue updates while entirely offline,
and to merge their local state with others' when they are once again able to communicate.
While this behaviour can be very helpful for application developers,
it may not free you entirely from having to think about network conditions.
-_Eventually-consistent_ application state should generally be treated as
subjective, which can be a significant shift if you are used to having a server acting as an authority.
+While you can use [`webxdc.appSenderAddr`](../spec/selfAddr_and_selfName.html#appsenderaddr) to nominate a peer
+(the app sender) to act as a kind of server, this introduces a dependency on that peer being online.
That means that conditional behaviour that you'd usually treat as _yes_ and _no_,
may instead behave more like _currently_ and _not yet_.
+
This section has discussed attributes of CRDTs that are mostly theoretical.
The next section will give more concrete examples using **Yjs**,
with a particular focus on how it can be used to accomplish common
diff --git a/src-docs/shared_state/practical.md b/src-docs/shared_state/practical.md
index d0c87c5..0425a25 100644
--- a/src-docs/shared_state/practical.md
+++ b/src-docs/shared_state/practical.md
@@ -473,6 +473,26 @@ As for the matter of duplicate ids in the `order` array,
the rendering code which constructs the app's UI from this data
could ignore repeated elements when iterating over them.
+## Centralized coordination
+
+While CRDTs are designed for peer-to-peer operation,
+you may sometimes want to designate one client as a "coordinator".
+By comparing [`webxdc.appSenderAddr`](../spec/selfAddr_and_selfName.html#appsenderaddr)
+with `webxdc.selfAddr`,
+an app can identify whether it is running for the peer
+that initially shared the app.
+This "sender" instance can then take on special roles,
+such as authoritatively resolving state conflicts,
+for example by letting the app sender's updates always win.
+
+However, use this model with care:
+if your app logic requires the sender to be online to function,
+it will be unusable whenever the sender is offline or has left the chat.
+One further complication occurs if the app sender
+has multiple devices running the app simultaneously,
+with each device possibly regarding itself as the central coordinator
+and producing conflicting application states.
+
## Learning more
Many more examples can be found throughout
diff --git a/src-docs/spec/CHANGELOG.md b/src-docs/spec/CHANGELOG.md
index d5310c9..d409869 100644
--- a/src-docs/spec/CHANGELOG.md
+++ b/src-docs/spec/CHANGELOG.md
@@ -1,5 +1,11 @@
# Changelog
+## [1.4] - 2026-04-16
+
+### New APIs
+
+- add `webxdc.appSenderAddr` and `webxdc.canOnlySendUpdatesToAppSender`
+ to allow apps to determine their role and their ability to send updates.
## [1.3] - 2026-02-11
### Other changes
diff --git a/src-docs/spec/messenger.md b/src-docs/spec/messenger.md
index 0f2ca90..c3bd9a5 100644
--- a/src-docs/spec/messenger.md
+++ b/src-docs/spec/messenger.md
@@ -54,6 +54,9 @@ When starting a web view for a webxdc app to run, messenger implementors
- MUST support `` is useful especially as webviews from different platforms have different defaults
+- MUST support `window.webxdc.appSenderAddr` and `window.webxdc.canOnlySendUpdatesToAppSender`
+ to allow apps to determine their role and their ability to send updates.
+
- MUST support `` to allow importing of files;
see [`sendToChat()`](../spec/sendToChat.md) for a way to export files.
diff --git a/src-docs/spec/selfAddr_and_selfName.md b/src-docs/spec/selfAddr_and_selfName.md
index 6bbfffa..a29ccd1 100644
--- a/src-docs/spec/selfAddr_and_selfName.md
+++ b/src-docs/spec/selfAddr_and_selfName.md
@@ -32,6 +32,33 @@ Note that `selfAddr`
- should not be shown in the user interface of the webxdc application
(use `selfName` instead).
+## appSenderAddr
+
+```js
+window.webxdc.appSenderAddr
+```
+
+`appSenderAddr` is the address of the peer who initially shared the webxdc application in the chat.
+It can be compared to `webxdc.selfAddr` to determine whether the app is running
+for the sender or a receiver.
+This supports a common development model where a "central" app instance
+(the sender's) processes all updates and distributes the resulting state
+back to all peers.
+
+## canOnlySendUpdatesToAppSender
+
+```js
+window.webxdc.canOnlySendUpdatesToAppSender
+```
+
+`canOnlySendUpdatesToAppSender` is a boolean that is `true` if updates sent
+by the local user will only be seen by the app sender.
+If it is `false` or `undefined`, the local user can send [updates](./sendUpdate.md) to everyone in the chat.
+
+On some platforms, such as "broadcast channels," it is technically impossible
+for subscribers to discover or send updates to each other directly.
+In those cases, only the app sender can distribute updates globally.
+
## Example using selfAddr and selfName
diff --git a/src-docs/spec/sendUpdate.md b/src-docs/spec/sendUpdate.md
index d7fedeb..f95edb2 100644
--- a/src-docs/spec/sendUpdate.md
+++ b/src-docs/spec/sendUpdate.md
@@ -4,9 +4,13 @@
window.webxdc.sendUpdate(update, descr);
```
-Send an update to all peers.
+Send an update to peers.
+If `webxdc.canOnlySendUpdatesToAppSender` is false, the update is sent to all peers.
+If `webxdc.canOnlySendUpdatesToAppSender` is true, the update is only sent to the app sender
+(the peer with the address `webxdc.appSenderAddr`).
-All peers, including the sending one,
+
+All receiving peers, including the sending one,
will receive the update by the callback given to [`setUpdateListener()`](./setUpdateListener.html).
There are situations where the user cannot send messages to a chat,
diff --git a/src-docs/webxdc.d.ts b/src-docs/webxdc.d.ts
index 7338a49..afc14af 100644
--- a/src-docs/webxdc.d.ts
+++ b/src-docs/webxdc.d.ts
@@ -72,6 +72,11 @@ interface Webxdc {
selfAddr: string;
/** Returns the peer's own name. This is name chosen by the user in their settings, if there is nothing set, that defaults to the peer's address. */
selfName: string;
+ /** The address of the peer who initially shared this webxdc app. */
+ appSenderAddr: string;
+ /** True if updates sent by this peer will only be received by the app sender.
+ * If false, the current user can send updates to all peers. */
+ canOnlySendUpdatesToAppSender: boolean;
/**
* set a listener for new status updates.
* The "serial" specifies the last serial that you know about (defaults to 0).