-
Notifications
You must be signed in to change notification settings - Fork 9
Chat Store
Direct access to the site's Zustand chat store via React fiber tree traversal. Lets you read, modify, or remove chat messages in React state — before they render to the DOM.
This is the recommended way to filter or modify chat messages. For receiving messages with normalised data and TTS/SFX deduplication, use Chat Messages instead.
This module must run in the page's JavaScript realm. It walks React's internal fiber tree, which is only accessible from the same realm React is running in.
| Environment | Works directly? |
|---|---|
| Tampermonkey/Greasemonkey | ✅ Yes |
Page-injected <script> tag |
✅ Yes |
| Browser extension content script | ❌ No — content scripts run in an isolated realm |
For browser extensions, you need to inject a separate page-realm script that imports this module. The extension's content script can communicate with it via window.postMessage. The Fishtank Live Extended extension uses this pattern in chat-filter.js.
import { chat } from 'ftl-ext-sdk';
// Wait for the chat store to become available (it loads after the chat
// component mounts, which is a few seconds after page load)
await chat.store.waitForStore();
// Subscribe to new messages
chat.store.onMessage((msg) => {
console.log(`${msg.user.displayName}: ${msg.message}`);
});
// Read messages directly
const messages = chat.store.getMessages();
// Remove a single message by ID
chat.store.removeMessage('some-message-id');
// Remove messages matching a predicate
const removed = chat.store.removeWhere((msg) => {
return msg.message?.includes('spam');
});
console.log(`Removed ${removed} spam messages`);
// Replace the messages array entirely
chat.store.setMessages(filteredMessages);
// Subscribe to all store changes (not just new messages)
const unsub = chat.store.subscribe((state) => {
console.log('Store changed, current room:', state.chatRoom);
});
// Stop subscribing
unsub();
// Status checks
chat.store.isReady(); // boolean — has the store been located?
chat.store.getStore(); // raw Zustand store reference
chat.store.reset(); // clear cached store referenceThe chat store is a Zustand store with (among other things):
| Key | Type | Description |
|---|---|---|
chatMessages |
Array | All chat messages currently in state |
setChatMessages |
Function | Replace the messages array |
chatRoom |
string | Current room ('Global', 'Season Pass', etc.) |
blockedUsers |
Array | User IDs the local user has blocked |
wordFilters |
Array | The local user's word filters |
The full store has ~28 keys. Use getStore().getState() to inspect.
Messages in the store are the raw socket payload, not the normalised shape from Chat Messages:
{
id: "msg_abc123",
message: "Hello world",
user: {
id: "user-uuid",
displayName: "SomeUser",
photoURL: "https://cdn.fishtank.live/avatars/someuser.png",
customUsernameColor: "#966b9e",
clan: null,
endorsement: null,
},
metadata: {
isAdmin: false,
isMod: false,
isFish: false,
// ...
},
mentions: [{ displayName: "other", userId: "uuid" }],
// ... more fields
}| Capability | chat.store |
chat.messages |
|---|---|---|
| Receive new messages | ✅ | ✅ |
| Modify messages before render | ✅ | ❌ |
| Remove messages from chat | ✅ | ❌ |
| Normalised data | ❌ (raw shape) | ✅ |
| TTS/SFX deduplication | ❌ (mixed in chat) | ✅ |
| Multi-room support | ❌ (current room only) | ✅ (with chat.rooms) |
| Works in content scripts | ❌ (page realm only) | ✅ |
Use chat.store when you need to filter, modify, or remove messages — for example, anti-spam, custom word filters, or hiding message types. Use chat.messages when you just want to log or react to messages, especially across multiple rooms.
The fiber traversal path the SDK uses to find the store may be affected by site refactors. The SDK tries a fast known path first, then falls back to a broader tree search if that fails. If both fail, findStore() returns null and waitForStore() rejects after the timeout.
If the chat component is unmounted and remounted (rare but possible), call chat.store.reset() to clear the cached reference and force a fresh search on the next call.
Core
Archives
Chat
UI
Player
Guides