How It Works
-
Channels and access control are console-only. Create the channel and choose its access control in Console → Cloud Scale → Data Streams; no SDK, REST, or MCP tool creates channels. Ask the user for the channel ID and its access control type, or list channels with
getAllChannels()(control_type0 = User Roles, 1 = Custom Logic). Loadreferences/datastreams-basics.mdfor concepts, the token rules, subscribe types, acknowledgement, and the REST API. -
Pick the token identifier from the access control — it is not interchangeable.
- User Roles →
userId= an app user's ID from Catalyst Authentication. A console admin's user ID is rejected;connectionNamefails with "Mandatory parameter app_user_id is missing." - Custom Logic →
connectionName, and the token must be generated inside the Advanced I/O function selected as the channel's access control. That function is the token endpoint: it runs your check, then callsgetTokenPair. Catalyst never calls it on its own. From any other function or REST: "Invalid access control source!". User-ID tokens on these channels are issued but the WebSocket rejects them (3000).
- User Roles →
-
Server code (publish, token pair, channel reads) — load the runtime reference.
- Node.js / JavaScript →
references/datastreams-javascript-basics.md. Initialize with the app:new DataStreams(await zcAuth.init(req)). Advanced I/O handlers get Node's rawreq/res: noreq.body,res.status(), orres.json(). - Python →
references/datastreams-python-basics.md. Requireszcatalyst-sdk1.5.0+ (Python 3.10+).app = zcatalyst_sdk.initialize(req=request), thenapp.datastreams()(plural). Passget_token_paira string channel ID and a keyworduser_id=/connection_name=; the result's keys are hyphenated (token["wss-id"]). The subscriber does nothing untilconnect(). - Java →
references/datastreams-java-basics.md. Dependency iscom.zoho.catalyst:java-sdk(2.5.0+) fromhttps://maven.zohodl.com; nodatastreamsartifact exists. publishData,getAllChannels,getChannelDetailsandgetLiveCountare admin methods: server only, never in browser or mobile code.getTokenPairalso exists in the browser SDK, but a Custom Logic token must come from the configured function.
- Node.js / JavaScript →
-
Subscriber code — read the token correctly and always acknowledge. The token pair's keys are hyphenated: pass
token['wss-id']aszuid, plustoken.urlandtoken.key. Subscribe only after theopenevent. CallsendAck()after every message, or the next message is never delivered. Messages carrydata(always a string) andstreamingId(plusurl/methodon API-operation messages). To reconnect, release the old session (old token →unsubscribe()), take a fresh token,subscribe('0'), and reload state from your own store; resuming a dropped session with'-2'redelivers missed messages twice and replays the 48-hour retention. Unsubscribe before every deliberate close; theerrorevent with code1000that follows your ownunsubscribe()is expected. In Node,getLiveCount()returns{ status, data: { connections } }. Java:subscribe()throws the checkedZCDataStreamException, and outside a Catalyst function create the client withnew ZCDataStreamsWebSocket(config), notZCDatastream.getInstance(). -
Verify end to end before reporting success. Open a subscriber, check
getLiveCount()shows it, publish a test message, and confirm the subscriber received it. For anything the references do not cover, fetch the page under https://docs.catalyst.zoho.com/en/cloud-scale/help/data-streams/ as Markdown (<page-url>/index.md), and prefer the references where they disagree.
Security Checklist
publishDataand the channel-read methods are admin operations: run them only in a Catalyst function, never in a browser or mobile app.- Protect the token endpoint. Anyone who can call it can subscribe to the channel, so authenticate the caller before issuing a token.
- On Custom Logic channels, the configured function is the only gatekeeper: put the real validation there before calling
getTokenPair. - Do not log or return the token
keyanywhere except to the client that asked for it.
Triggers
Use this skill for: "Data Streams", "Catalyst Data Streams", "datastreams", "real-time channel", "live updates", "push updates to the browser", "pub/sub", "publish data", publishData, getTokenPair, "token pair", "wss-id", DataStreamsWebSocket, ZCDataStreamsWebSocket, ZCDatastream, "WebSocket subscriber", sendAck, "subscribe type", "resume from last message", "live count", getLiveCount, "channel access control", "User Roles channel", "Custom Logic channel", "app_user_id is missing", "Invalid access control source", "Authentication failed 3000", "reconnect", "duplicate messages after reconnect", "DUPLICATE_VALUE", @zcatalyst/datastreams, zcatalyst_sdk, get_token_pair, publish_data, send_ack, or "Data Streams Python".
References
| Reference | Load when the query is about… |
|---|---|
references/datastreams-basics.md | Concepts, channels, access control (User Roles vs Custom Logic), which token identifier to use, token pair shape, subscribe types, acknowledgement, retention, message fields, REST API endpoints and scopes |
references/datastreams-javascript-basics.md | Node.js functions (init, publish, token endpoint, Custom Logic function, channel reads), Node and browser subscribers, package versions |
references/datastreams-python-basics.md | Python functions and subscribers: zcatalyst-sdk 1.5.0+, app.datastreams(), get_token_pair argument rules, DataStreamsWebSocket with connect() and set_on_* callbacks, deploying Python functions |
references/datastreams-java-basics.md | Java functions and subscribers: Maven setup, ZCDatastream, ZCDataStreamsWebSocket, checked exceptions, running outside Catalyst |


