Summary
When modifying a SharedState by its shared token (rather than a private client token), the update is not propagated to any of the clients linked to that shared state. This makes it impossible to push shared state updates from external contexts like API route webhooks where no private client token is available — only the shared state token is known.
Current Behavior
The shared state system works correctly when events flow through a private client token:
app.modify_state(private_token) is called
modify_state_with_links patches in the linked shared state
- After the event handler modifies the shared state,
_modify_linked_states collects dirty vars and calls _do_update_other_tokens() to propagate to all other linked clients
- All linked clients receive the delta
However, when code calls app.modify_state(shared_token) directly with a shared state token:
- The state is loaded under the shared token's
ident
modify_state_with_links checks for _reflex_internal_links — this attribute represents outgoing links, which the shared state itself doesn't have
_modify_linked_states is never called, so no propagation happens
- The delta is emitted only to
token.ident (the shared token), but no browser clients are listening on that token — they listen on their private tokens
- No clients receive the update
Expected Behavior
When app.modify_state(shared_token) is called with a shared state token:
- The shared state should be loaded and modifiable as it is today
- After modification, the system should look up all client tokens in
_linked_from on the shared state
- Each linked client should receive the delta, the same way
_do_update_other_tokens works today
Use Case
A common pattern is modifying shared state from an API route / webhook handler, where only the shared state token is known (e.g., a record_id or room_id):
@rx.api(path="/webhook/{record_id}")
async def handle_webhook(record_id: str, payload: dict):
token = _substate_key(record_id, SessionState)
async with app.modify_state(token) as state:
session = await state.get_state(SessionState)
session.update_from_webhook(payload)
# All clients linked to this shared state should see the update
Today, users attempting this pattern resort to manually calling internal APIs like _do_update_other_tokens, which partially works but breaks subsequent event handler deltas in the original tab (reported on Discord).
Relevant Code
Possible Approach
In app.modify_state (or modify_state_with_links), detect when the token refers to a shared state (e.g., check if the loaded state has _linked_from with entries). If so, after modification:
- Collect dirty vars from the modified state
- Use
_linked_from to get all affected client tokens
- Call
_do_update_other_tokens (or equivalent) to propagate the delta to each linked client
- Skip emitting the delta to the shared token itself (no browser is listening on it)
Summary
When modifying a
SharedStateby its shared token (rather than a private client token), the update is not propagated to any of the clients linked to that shared state. This makes it impossible to push shared state updates from external contexts like API route webhooks where no private client token is available — only the shared state token is known.Current Behavior
The shared state system works correctly when events flow through a private client token:
app.modify_state(private_token)is calledmodify_state_with_linkspatches in the linked shared state_modify_linked_statescollects dirty vars and calls_do_update_other_tokens()to propagate to all other linked clientsHowever, when code calls
app.modify_state(shared_token)directly with a shared state token:identmodify_state_with_linkschecks for_reflex_internal_links— this attribute represents outgoing links, which the shared state itself doesn't have_modify_linked_statesis never called, so no propagation happenstoken.ident(the shared token), but no browser clients are listening on that token — they listen on their private tokensExpected Behavior
When
app.modify_state(shared_token)is called with a shared state token:_linked_fromon the shared state_do_update_other_tokensworks todayUse Case
A common pattern is modifying shared state from an API route / webhook handler, where only the shared state token is known (e.g., a
record_idorroom_id):Today, users attempting this pattern resort to manually calling internal APIs like
_do_update_other_tokens, which partially works but breaks subsequent event handler deltas in the original tab (reported on Discord).Relevant Code
_do_update_other_tokens:reflex/istate/shared.py:35-73— creates update tasks for linked clients_modify_linked_states:reflex/istate/shared.py:323-399— orchestrates linked state patching and propagationmodify_state_with_links:reflex/istate/manager/__init__.py:210-242— entry point that decides whether to handle linked statesapp.modify_state:reflex/app.py:1576-1616— high-level API, emits delta only to the passed token_linked_fromfield:reflex/istate/shared.py:404— set of client tokens linked to a shared statePossible Approach
In
app.modify_state(ormodify_state_with_links), detect when the token refers to a shared state (e.g., check if the loaded state has_linked_fromwith entries). If so, after modification:_linked_fromto get all affected client tokens_do_update_other_tokens(or equivalent) to propagate the delta to each linked client