PageSourceSearch

https://socket.io/assets/js/2a858073.710a8375.js

js socket.io collected 2026-10-01 07:33:08 UTC 12,179 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunksample_website=self.webpackChunksample_website||[]).push([[752],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>d});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function s(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},r=Object.keys(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),c=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},p=function(e){var t=c(e.components);return o.createElement(l.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},k=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,l=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),m=c(n),k=a,d=m["".concat(l,".").concat(k)]||m[k]||u[k]||r;return n?o.createElement(d,s(s({ref:t},p),{},{components:n})):o.createElement(d,s({ref:t},p))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,s=new Array(r);s[0]=k;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[m]="string"==typeof e?e:a,s[1]=i;for(var c=2;c<r;c++)s[c]=n[c];return o.createElement.apply(null,s)}return o.createElement.apply(null,n)}k.displayName="MDXCreateElement"},6632:(e,t,n)=>{n.r(t),n.d(t,{contentTitle:()=>s,default:()=>m,frontMatter:()=>r,metadata:()=>i,toc:()=>l});var o=n(3117),a=(n(7294),n(3905));const r={title:"How to emit to a list of sockets"},s="How to emit to a list of sockets",i={type:"mdx",permalink:"/how-to/emit-to-a-list-of-sockets",source:"@site/src/pages/how-to/emit-to-a-list-of-sockets.md",title:"How to emit to a list of sockets",description:"In Socket.IO, there are several ways to emit an event to a specific subset of connected sockets:",frontMatter:{title:"How to emit to a list of sockets"}},l=[{value:"Room",id:"room",level:2},{value:"Pros",id:"pros",level:3},{value:"Cons",id:"cons",level:3},{value:"Namespace",id:"namespace",level:2},{value:"Pros",id:"pros-1",level:3},{value:"Cons",id:"cons-1",level:3},{value:"Dynamic subset of sockets",id:"dynamic-subset-of-sockets",level:2},{value:"Standalone version",id:"standalone-version",level:3},{value:"Cluster version",id:"cluster-version",level:3},{value:"Pros",id:"pros-2",level:3},{value:"Cons",id:"cons-2",level:3}],c={toc:l},p="wrapper";
1function m(e){let{components:t,...n}=e;return(0,a.kt)(p,(0,o.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"how-to-emit-to-a-list-of-sockets"},"How to emit to a list of sockets"),(0,a.kt)("p",null,"In Socket.IO, there are several ways to emit an event to a specific subset of connected sockets:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#room"},"with a room")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#namespace"},"with a namespace")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#dynamic-subset-of-sockets"},"with a dynamic subset of sockets"))),(0,a.kt)("h2",{id:"room"},"Room"),(0,a.kt)("p",null,"In most applications, the recommended approach is to use ",(0,a.kt)("strong",{parentName:"p"},"rooms"),": create rooms based on your domain model, such as user IDs, organizations, projects, conversations, or subscriptions, then emit to those rooms."),(0,a.kt)("p",null,"Reference: ",(0,a.kt)("a",{parentName:"p",href:"/docs/v4/rooms/"},"Rooms")),(0,a.kt)("p",null,"Example targeting a specific user:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'function computeUserId(handshake) {\n  // compute the user ID based on the headers/cookies/etc.\n}\n\nio.use(async (socket, next) => {\n  const userId = await computeUserId(socket.handshake);\n\n  socket.join(`user:${userId}`);\n\n  next();\n});\n\n// then later\nio.to("user:123").emit("event", "to this specific user");\n')),(0,a.kt)("p",null,"Similarly, to target a specific project:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'function computeUserId(handshake) {\n  // compute the user ID based on the headers/cookies/etc.\n}\n\nio.use(async (socket, next) => {\n  const userId = await computeUserId(socket.handshake);\n  const projects = await getProjectsForUser(userId);\n\n  for (const project of projects) {\n    socket.join(`project:${project.id}`);\n  }\n\n  next();\n});\n\n// then later\nio.to("project:123").emit("event", "to all users working on this project");\n')),(0,a.kt)("h3",{id:"pros"},"Pros"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"easy to implement"),(0,a.kt)("li",{parentName:"ul"},"performant")),(0,a.kt)("h3",{id:"cons"},"Cons"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"you need to keep the rooms up-to-date:"),(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"call ",(0,a.kt)("a",{parentName:"li",href:"/docs/v4/server-api/#socketjoinroom"},(0,a.kt)("inlineCode",{parentName:"a"},"socket.join()"))," or ",(0,a.kt)("a",{parentName:"li",href:"/docs/v4/server-api/#serversocketsjoinrooms"},(0,a.kt)("inlineCode",{parentName:"a"},"io.socketsJoin()"))," (in the example above, when the user is assigned to a project)"),(0,a.kt)("li",{parentName:"ul"},"call ",(0,a.kt)("a",{parentName:"li",href:"/docs/v4/server-api/#socketleaveroom"},(0,a.kt)("inlineCode",{parentName:"a"},"socket.leave()"))," or ",(0,a.kt)("a",{parentName:"li",href:"/docs/v4/server-api/#serversocketsleaverooms"},(0,a.kt)("inlineCode",{parentName:"a"},"io.socketsLeave()"))," (when the user is unassigned)"))),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"there is no way to do an intersection between rooms (for example, all sockets with a specific role in the organization ",(0,a.kt)("em",{parentName:"p"},"and")," assigned to a particular project)"))),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},(0,a.kt)("inlineCode",{parentName:"p"},'io.to("org:123:manager").to("project:456").emit("event")')," will do a union of the rooms and emit to all sockets which are in ",(0,a.kt)("em",{parentName:"p"},"either")," the ",(0,a.kt)("inlineCode",{parentName:"p"},"org:123:manager")," or ",(0,a.kt)("inlineCode",{parentName:"p"},"project:456")," rooms (or both).")),(0,a.kt)("h2",{id:"namespace"},"Namespace"),(0,a.kt)("p",null,"Namespaces are another way to organize your Socket.IO server into logical groups."),(0,a.kt)("p",null,"Reference: ",(0,a.kt)("a",{parentName:"p",href:"/docs/v4/namespaces/"},"Namespaces")),(0,a.kt)("p",null,"Example with a namespace for admin users:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'const adminNamespace = io.of("/admin");\n\nasync function isAdmin(handshake) {\n  // ...\n}\n\nadminNamespace.use(async (socket, next) => {\n  if (await isAdmin(socket.handshake)) {\n    next();\n  } else {\n    next(new Error("not authorized"));\n  }\n});\n\n// then later\nadminNamespace.emit("event", "to all admin users");\n')),(0,a.kt)("p",null,"Or with one namespace per organization:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'const namespaces = io.of(/^\\/org:\\d+$/);\n\nasync function isMemberOfOrganization(handshake, orgId) {\n  // ...\n}\n\nnamespaces.use(async (socket, next) => {\n  const orgId = socket.nsp.name.slice("/org:".length);\n  \n  if (await isMemberOfOrganization(socket.handshake, orgId)) {\n    next();\n  } else {\n    next(new Error("not authorized"));\n  }\n});\n\nnamespaces.on("connection", (socket) => {\n  const namespace = socket.nsp;\n\n  namespace.emit("event", "to all users in this organization");\n});\n')),(0,a.kt)("h3",{id:"pros-1"},"Pros"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"easy to implement"),(0,a.kt)("li",{parentName:"ul"},"performant")),(0,a.kt)("h3",{id:"cons-1"},"Cons"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"you need to keep the namespaces up-to-date:",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"call ",(0,a.kt)("a",{parentName:"li",href:"/docs/v4/server-api/#socketdisconnectclose"},(0,a.kt)("inlineCode",{parentName:"a"},"socket.disconnect()"))," or ",(0,a.kt)("a",{parentName:"li",href:"/docs/v4/server-api/#serverdisconnectsocketsclose"},(0,a.kt)("inlineCode",{parentName:"a"},"io.disconnectSockets()"))," (in the example above, when the user is removed from an organization)"),(0,a.kt)("li",{parentName:"ul"},"connect to the namespace from the client side when the user is added to an organization")))),(0,a.kt)("h2",{id:"dynamic-subset-of-sockets"},"Dynamic subset of sockets"),(0,a.kt)("p",null,"If the solutions above don't suit your needs, you can always loop through all connected sockets and filter the sockets you want to emit to:"),(0,a.kt)("h3",{id:"standalone-version"},"Standalone version"),(0,a.kt)("p",null,"Example if you have a single Socket.IO server:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'function emitToMatchingSockets(filter, event, arg) {\n  for (const socket of io.of("/").sockets.values()) {\n    if (filter(socket)) {\n      socket.emit(event, arg);\n    }\n  }\n}\n\nemitToMatchingSockets(\n  (socket) => {\n    return (\n      socket.data.orgId === 123 &&\n      socket.data.role === "manager" &&\n      socket.data.projectIds.includes(456)\n    );\n  },\n  "event",\n  "to this specific subset of users",\n);\n')),(0,a.kt)("h3",{id:"cluster-version"},"Cluster version"),(0,a.kt)("p",null,"Example if you have multiple Socket.IO servers:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'function localEmit({ orgId, role, projectId }, event, arg) {\n  function filter(socket) {\n    return (\n      socket.data.orgId === orgId &&\n      socket.data.role === role &&\n      socket.data.projectIds.includes(projectId)\n    );\n  }\n\n  for (const socket of io.of("/").sockets.values()) {\n    if (filter(socket)) {\n      socket.emit(event, arg);\n    }\n  }\n}\n\nio.on("emitToMatchingSockets", (filters, event, arg) => {\n  localEmit(filters, event, arg);\n});\n\nfunction emitToMatchingSockets(filters, event, arg) {\n  // emit to sockets connected on this server\n  localEmit(filters, event, arg);\n\n  // notify the other servers\n  io.serverSideEmit("emitToMatchingSockets", filters, event, arg);\n}\n\nemitToMatchingSockets(\n  {\n    orgId: 123,\n    role: "manager",\n    projectId: 456,\n  },\n  "event",\n  "to this specific subset of users",\n);\n')),(0,a.kt)("p",null,"References:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"/docs/v4/server-api/#serverserversideemiteventname-args"},"io.serverSideEmit()")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"/docs/v4/using-multiple-nodes/"},"Using multiple nodes"))),(0,a.kt)("h3",{id:"pros-2"},"Pros"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"you can apply any filter")),(0,a.kt)("h3",{id:"cons-2"},"Cons"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"a bit less performant, since the payload will be encoded for each socket")),(0,a.kt)("p",null,"That's all folks, thanks for reading!"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"/get-started/"},"Back to the list of examples")))}m.isMDXComponent=!0}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.