loading
Note:
Try it with two tabs Open this page in a second tab, press Subscribe in both, then post a message from either one - it appears in the other tab's console. Per the spec, a sender never receives its own message, so posting in a single tab logs nothing locally.

Check support

IsSupported

Returns true when the runtime exposes BroadcastChannel. The API is available in every modern browser and requires no permissions.

C#
var supported = await broadcastChannel.IsSupported();
Live sample
support output
Results will appear here when you interact with the samples.

Subscribe to a channel

Subscribe

Subscribes to a named channel. Every message arrives as a JsonElement so you can deserialize into whatever shape you expect; the optional onError callback fires on a messageerror event (a payload that could not be deserialized). One BroadcastChannel instance can host any number of named channels - the JS-side channel is created on first subscribe per name and torn down when its last subscription is disposed.

C#
var subscription = await broadcastChannel.Subscribe("butil-demo",
    onMessage: data =>
    {
        // data is a JsonElement - e.g. data.GetString() for plain text
    },
    onError: () =>
    {
        // a message on the channel failed to deserialize
    });

// later, to detach:
await subscription.DisposeAsync();
Live sample
subscription output
Results will appear here when you interact with the samples.

Post a message

Post

Sends a message to every other listener on the channel within the same origin. Any JSON-serializable value works - strings, numbers or whole objects. Remember: the sender itself does not receive the message, so watch the console of the other tab.

C#
await broadcastChannel.Post("butil-demo", "Hello, other tabs!");

// objects work too:
await broadcastChannel.Post("butil-demo", new { user = "alice", action = "signed-in" });
Live sample
post output
Results will appear here when you interact with the samples.
Warning:
Same origin only Broadcast channels are partitioned by origin (scheme, host and port). Tabs from other origins - even subdomains - never see the messages, which also makes the API unsuitable for cross-site communication by design.

API reference

Member
Signature
Description
IsSupported
ValueTask<bool> IsSupported()
True when the runtime exposes BroadcastChannel.
Post
ValueTask Post<T>(string channelName, T message)
Sends the message to every other listener on the channel in the same origin (the sender does not receive its own message).
Subscribe
Task<ButilSubscription> Subscribe(string channelName, Action<JsonElement>? onMessage, Action? onError = null)
Subscribes to the channel; each message arrives as a JsonElement. Dispose the returned subscription to detach.
DisposeAsync
ValueTask DisposeAsync()
Detaches every subscription created by this instance and releases the interop reference.
InvokeBroadcastChannelMessage
void InvokeBroadcastChannelMessage(Guid id, JsonElement data)
Interop plumbing invoked from JavaScript ([JSInvokable]); not intended for direct use.
InvokeBroadcastChannelError
void InvokeBroadcastChannelError(Guid id)
Interop plumbing invoked from JavaScript ([JSInvokable]); not intended for direct use.
An unhandled error has occurred. Reload 🗙