[{"data":1,"prerenderedAt":49},["ShallowReactive",2],{"integration-node-red-contrib-slack\u002F":3},{"_id":4,"categories":5,"author":8,"description":10,"npmOwners":11,"npmScope":14,"name":4,"ffCertified":15,"downloads":16,"version":18,"updatedAt":19,"maintainers":20,"homepage":25,"bugs":26,"repository":28,"time":31,"lastUpdated":19,"created":32,"license":45,"githubOwner":12,"githubRepo":46,"examples":47,"readme":48},"node-red-contrib-slack",[6,7],"catalogue_communication","catalogue",{"name":9},"Adrian Lansdown","A node-red module to interact with the Slack API",[12,13],"yayadrian","travisghansen",null,false,{"week":17},2357,"2.1.0","2025-04-06T18:36:39.992Z",[21,23],{"name":12,"email":22},"npmjs@thejaronline.com",{"name":13,"email":24},"travisghansen@yahoo.com","https:\u002F\u002Fgithub.com\u002Fyayadrian\u002Fnode-red-slack#readme",{"url":27},"https:\u002F\u002Fgithub.com\u002Fyayadrian\u002Fnode-red-slack\u002Fissues",{"type":29,"url":30},"git","git:\u002F\u002Fgithub.com\u002Fyayadrian\u002Fnode-red-slack.git",{"created":32,"modified":19,"0.0.1":32,"0.0.2":33,"0.0.3":34,"0.0.4":35,"0.0.5":36,"0.0.6":37,"0.0.7":38,"0.0.8":39,"0.1.0":40,"0.1.1":41,"0.1.2":42,"2.0.0":43,"2.1.0":44},"2015-01-31T13:15:09.378Z","2015-02-01T22:31:17.557Z","2015-02-01T22:43:00.034Z","2015-02-02T22:17:07.089Z","2015-04-11T20:48:10.738Z","2015-05-30T21:43:53.927Z","2015-06-01T12:34:56.454Z","2015-06-01T18:09:07.673Z","2015-06-14T16:40:36.178Z","2015-11-29T12:02:04.634Z","2017-01-24T12:37:10.051Z","2019-03-18T13:31:03.985Z","2025-04-06T18:36:39.817Z","MIT","node-red-slack",[],"\u003Ch1 id=\"node-red-contrib-slack\">\u003Ca class=\"header-anchor\" href=\"#node-red-contrib-slack\">node-red-contrib-slack\u003C\u002Fa>\u003C\u002Fh1>\n\u003Cp>A \u003Ca href=\"http:\u002F\u002Fnodered.org\" target=\"_new\">Node-RED\u003C\u002Fa> node to interact with\nthe \u003Ca href=\"https:\u002F\u002Fslack.com\u002F\" target=\"_new\">Slack\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002F\" target=\"_new\">API\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch1 id=\"install\">\u003Ca class=\"header-anchor\" href=\"#install\">Install\u003C\u002Fa>\u003C\u002Fh1>\n\u003Cp>Run the following command in the root directory of your Node-RED install:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>npm install --save node-red-contrib-slack\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Version \u003Ccode>2.x\u003C\u002Fcode> of this package is \u003Cstrong>NOT\u003C\u002Fstrong> compatible with older versions. Plese\nrefer to the \u003Ca href=\"#migration-from-012-or-earlier\">migration\u003C\u002Fa> section for help.\u003C\u002Fp>\n\u003Ch1 id=\"usage\">\u003Ca class=\"header-anchor\" href=\"#usage\">Usage\u003C\u002Fa>\u003C\u002Fh1>\n\u003Cp>The nodes included in this package are \u003Cstrong>purposely\u003C\u002Fstrong> generic in nature. The\nusage very closely mimics the\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002F\" target=\"_new\">Slack API\u003C\u002Fa>. Your best source\nof reference for input\u002Foutput specifics will be from:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>https:\u002F\u002Fapi.slack.com\u003C\u002Fli>\n\u003Cli>https:\u002F\u002Fapi.slack.com\u002Frtm\u003C\u002Fli>\n\u003Cli>https:\u002F\u002Fapi.slack.com\u002Fweb\u003C\u002Fli>\n\u003Cli>https:\u002F\u002Fapi.slack.com\u002Fmethods\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>4 nodes are provided:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ca href=\"#slack-rtm-in\">\u003Ccode>slack-rtm-in\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"#slack-rtm-out\">\u003Ccode>slack-rtm-out\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"#slack-web-out\">\u003Ccode>slack-web-out\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"#slack-state\">\u003Ccode>slack-state\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>The \u003Ccode>rtm\u003C\u002Fcode> API\u002Fnode(s) are connected to slack via web sockets and are useful for\nreceiving a real-time stream of events\u002Fdata.\u003C\u002Fp>\n\u003Cp>The \u003Ccode>web\u003C\u002Fcode> API\u002Fnode(s) are useful for making traditional web service calls and\nhave a much broader use-case.\u003C\u002Fp>\n\u003Cp>Combining both \u003Ccode>rtm\u003C\u002Fcode> and \u003Ccode>web\u003C\u002Fcode> APIs provides a full solution to interact with\nthe \u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002F\" target=\"_new\">Slack API\u003C\u002Fa> in it's\nentirety facilitating powerful flows in \u003Ccode>Node-RED\u003C\u002Fcode>. Which nodes are\nappropriate to use for any given use-case can be subjective so familiarizing\nyouself with the documentation links above is \u003Cstrong>extremely\u003C\u002Fstrong> beneficial.\u003C\u002Fp>\n\u003Ch2 id=\"invoking-methods\">\u003Ca class=\"header-anchor\" href=\"#invoking-methods\">invoking methods\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>To invoke methods (\u003Ca href=\"#slack-rtm-out\">\u003Ccode>slack-rtm-out\u003C\u002Fcode>\u003C\u002Fa>,\n\u003Ca href=\"#slack-web-out\">\u003Ccode>slack-web-out\u003C\u002Fcode>\u003C\u002Fa>) set the \u003Ccode>msg.topic\u003C\u002Fcode> to the name of the\nmethod and set the \u003Ccode>msg.payload\u003C\u002Fcode> to the args\u002Fparams.\u003C\u002Fp>\n\u003Cp>The \u003Ccode>token\u003C\u002Fcode> property is \u003Cstrong>NOT\u003C\u002Fstrong> required to be set in any \u003Ccode>msg.payload\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>As an example of invoking the\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fmethods\u002Fchat.meMessage\">\u003Ccode>chat.meMessage\u003C\u002Fcode>\u003C\u002Fa>\nmethod with the \u003Ca href=\"#slack-web-out\">\u003Ccode>slack-web-out\u003C\u002Fcode>\u003C\u002Fa> node you would do the\nfollowing:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>msg.topic = \"chat.meMessage\";\nmsg.payload = {\n    channel: \"...\",\n    text: \"...\"\n}\n\nreturn msg;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"dressed-output\">\u003Ca class=\"header-anchor\" href=\"#dressed-output\">\u003Ccode>dressed\u003C\u002Fcode> output\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>The following nodes each provide\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002F\" target=\"_new\">Slack API\u003C\u002Fa> output:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ca href=\"#slack-rtm-in\">\u003Ccode>slack-rtm-in\u003C\u002Fcode>\u003C\u002Fa> - view details of each event in the\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Frtm\" target=\"_new\">documentation\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"#slack-rtm-out\">\u003Ccode>slack-rtm-out\u003C\u002Fcode>\u003C\u002Fa> - view details of each event in the\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Frtm\" target=\"_new\">documentation\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"#slack-web-out\">\u003Ccode>slack-web-out\u003C\u002Fcode>\u003C\u002Fa> - view \u003Ccode>response\u003C\u002Fcode> section of each method in\nthe \u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fmethods\" target=\"_new\">documentation\u003C\u002Fa>\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>The respective events\u002Fresponses are generally left unaltered and are directly\npassed through as \u003Ccode>msg.payload\u003C\u002Fcode>. However, before outputting the \u003Ccode>msg\u003C\u002Fcode> the data\nis traversed to enrich the \u003Ccode>msg.payload\u003C\u002Fcode> (examples provided below) with\ncomplete object data where otherwise only internal Slack IDs are present.\u003C\u002Fp>\n\u003Cp>All of the lookups are done dynamically\u002Fgenerically so regardless of what API\nresponse you get if the node finds an attribute that appears to be a\nsupported object (\u003Ccode>user\u003C\u002Fcode>\u002F\u003Ccode>channel\u003C\u002Fcode>\u002F\u003Ccode>team\u003C\u002Fcode>\u002F\u003Ccode>bot\u003C\u002Fcode>) in some shape or form, a\ncorresponding \u003Ccode>&lt;attribute&gt;Object\u003C\u002Fcode> attribute with the lookup value will be\nadded.\u003C\u002Fp>\n\u003Cp>For example, if the response contains a \u003Ccode>bot_id\u003C\u002Fcode> attribute you would see\n\u003Ccode>bot_idObject\u003C\u002Fcode> added, or if it found an attribute called \u003Ccode>bot\u003C\u002Fcode> it would add\n\u003Ccode>botObject\u003C\u002Fcode> etc. Ultimately all the lookups come from\n\u003Ca href=\"#slackstate\">\u003Ccode>slackState\u003C\u002Fcode>\u003C\u002Fa> (see below) so it could be done on your own but\nit's added to simplify and for convenience.\u003C\u002Fp>\n\u003Cp>An example\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fevents\u002Fuser_typing\" target=\"_new\">\u003Ccode>user_typing\u003C\u002Fcode>\u003C\u002Fa>\nevent from the \u003Ca href=\"#slack-rtm-in\">\u003Ccode>slack-rtm-in\u003C\u002Fcode>\u003C\u002Fa> node:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>{\n  \"type\": \"user_typing\",\n  \"channel\": \"...\",\n  \"user\": \"...\"\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>is \u003Ccode>dressed\u003C\u002Fcode> to be sent as:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>{\n  \"type\": \"user_typing\",\n  \"channel\": \"...\",\n  \"user\": \"...\",\n  \"channelObject\": {\n    \"id\": \"...\",\n    \"name\": \"...\",\n    \"is_channel\": true,\n    \"is_group\": false,\n    \"is_im\": false,\n    \"created\": 1434735155,\n    ...\n  },\n  \"userObject\": {\n    \"id\": \"...\",\n    \"name\": \"...\",\n    \"real_name\": \"...\",\n    ...\n  }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"helpers\">\u003Ca class=\"header-anchor\" href=\"#helpers\">Helpers\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>As a convenience for both the \u003Ca href=\"#slack-web-out\">\u003Ccode>slack-web-out\u003C\u002Fcode>\u003C\u002Fa> and\n\u003Ca href=\"#slack-rtm-out\">\u003Ccode>slack-rtm-out\u003C\u002Fcode>\u003C\u002Fa> nodes a special interface is supported that\nallows you to send a message with a simplified structure (\u003Ccode>msg.topic\u003C\u002Fcode> starts\nwith \u003Ccode>@\u003C\u002Fcode> or \u003Ccode>#\u003C\u002Fcode>):\u003C\u002Fp>\n\u003Cpre>\u003Ccode>msg.topic = \"@some_user\";\n# or\nmsg.topic = \"#some_channel\";\n\nmsg.payload = \"a special message just for you\"\n\nreturn msg\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>As an additional convenience, if you are invoking the\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fmethods\u002Fchat.meMessage\" target=\"_new\">\u003Ccode>chat.meMessage\u003C\u002Fcode>\u003C\u002Fa>,\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fmethods\u002Fchat.postEphemeral\" target=\"_new\">\u003Ccode>chat.postEphemeral\u003C\u002Fcode>\u003C\u002Fa>,\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fmethods\u002Fchat.postMessage\" target=\"_new\">\u003Ccode>chat.postMessage\u003C\u002Fcode>\u003C\u002Fa>\nmethods (\u003Ca href=\"#slack-web-out\">\u003Ccode>slack-web-out\u003C\u002Fcode>\u003C\u002Fa>), or\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Frtm\">\u003Ccode>message\u003C\u002Fcode>\u003C\u002Fa> method\n(\u003Ca href=\"#slack-rtm-out\">\u003Ccode>slack-rtm-out\u003C\u002Fcode>\u003C\u002Fa>) and the \u003Ccode>channel\u003C\u002Fcode> starts with \u003Ccode>@\u003C\u002Fcode> or \u003Ccode>#\u003C\u002Fcode>\nthe node will automatically lookup the appropriate \u003Ccode>channel.id\u003C\u002Fcode> from\n\u003Ca href=\"#slackstate\">\u003Ccode>slackState\u003C\u002Fcode>\u003C\u002Fa> (see below) and set it for you.\u003C\u002Fp>\n\u003Ch2 id=\"slackstate\">\u003Ca class=\"header-anchor\" href=\"#slackstate\">\u003Ccode>slackState\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>All outputs for all nodes include a \u003Ccode>msg.slackState\u003C\u002Fcode> object which has several\nproperties containing the lists of \u003Ccode>members\u003C\u002Fcode>\u002F\u003Ccode>channels\u003C\u002Fcode>\u002F\u003Ccode>bots\u003C\u002Fcode>\u002F\u003Ccode>team\u003C\u002Fcode>\u002Fetc so\ndownstream nodes can do 'lookups' without re-hitting the API (this data is\ncurrently refreshed in the background every 10 minutes). Additionally the\ninternal state is connected to all relevant slack events and updates are\nreflected real-time in any new messages (ie: a user getting created\nautomatically updates the \u003Ccode>slackState\u003C\u002Fcode> even before the 10 minute refresh).\u003C\u002Fp>\n\u003Ch2 id=\"nodes\">\u003Ca class=\"header-anchor\" href=\"#nodes\">nodes\u003C\u002Fa>\u003C\u002Fh2>\n\u003Ch3 id=\"slack-rtm-in\">\u003Ca class=\"header-anchor\" href=\"#slack-rtm-in\">\u003Ccode>slack-rtm-in\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>The \u003Ca href=\"#slack-rtm-in\">\u003Ccode>slack-rtm-in\u003C\u002Fcode>\u003C\u002Fa> node listens to\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Frtm\" target=\"_new\">Slack RTM\u003C\u002Fa> events and\noutputs the \u003Ca href=\"#dressed-output\">\u003Ccode>dressed\u003C\u002Fcode>\u003C\u002Fa> response as the \u003Ccode>msg.payload\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>By default the node will listen to ALL events. You can however filter\nevent types by setting the node \u003Cem>Slack Events\u003C\u002Fem> property to a value\ntaking the form of \u003Ccode>type[::subtype][,type[::subtype],...]\u003C\u002Fcode>. For example\n\u003Ccode>message\u003C\u002Fcode> to receive only events of type \u003Ccode>message\u003C\u002Fcode> or \u003Ccode>message::bot_message\u003C\u002Fcode> to\nreceive only events of type \u003Ccode>message\u003C\u002Fcode> which additionally have a \u003Ccode>subtype\u003C\u002Fcode> of\n\u003Ccode>bot_message\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Example output:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>{\n  \"payload\" {\n    \"type\": \"user_typing\",\n    \"channel\": \"...\",\n    \"user\": \"...\",\n    \"channelObject\": {\n        \"id\": \"...\",\n        \"name\": \"...\",\n        \"is_channel\": true,\n        \"is_group\": false,\n        \"is_im\": false,\n        \"created\": 1434735155,\n        ...\n    },\n    \"userObject\": {\n        \"id\": \"...\",\n        \"name\": \"...\",\n        \"real_name\": \"...\",\n        ...\n    }\n  },\n  \"slackState\": {\n    ...\n  }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"slack-rtm-out\">\u003Ca class=\"header-anchor\" href=\"#slack-rtm-out\">\u003Ccode>slack-rtm-out\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>Invokes a \u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Frtm\" target=\"_new\">Slack RTM\u003C\u002Fa>\nmethod and outputs the \u003Ca href=\"#dressed-output\">\u003Ccode>dressed\u003C\u002Fcode>\u003C\u002Fa> response as the\n\u003Ccode>msg.payload\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Available methods:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ccode>message\u003C\u002Fcode>: send a message\u003C\u002Fli>\n\u003Cli>\u003Ccode>ping\u003C\u002Fcode>: pong\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fevents\u002Fpresence_sub\" target=\"_new\">\u003Ccode>presence_sub\u003C\u002Fcode>\u003C\u002Fa>:\nto subscribe to\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fevents\u002Fpresence_change\" target=\"_new\">\u003Ccode>presence_change\u003C\u002Fcode>\u003C\u002Fa>\nevents\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fevents\u002Fpresence_query\" target=\"_new\">\u003Ccode>presence_query\u003C\u002Fcode>\u003C\u002Fa>:\nto request a one-time\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fevents\u002Fpresence_change\" target=\"_new\">\u003Ccode>presence_change\u003C\u002Fcode>\u003C\u002Fa>\nstatus\u003C\u002Fli>\n\u003Cli>\u003Ccode>typing\u003C\u002Fcode>: to send typing indicators\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Using \u003Ca href=\"#slack-rtm-out\">\u003Ccode>slack-rtm-out\u003C\u002Fcode>\u003C\u002Fa> for sending messages should only be\nused for very basic messages, preference would be to use the\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fmethods\u002Fchat.postMessage\" target=\"_new\">\u003Ccode>chat.postMessage\u003C\u002Fcode>\u003C\u002Fa>,\nmethod of the \u003Ca href=\"#slack-web-out\">\u003Ccode>slack-web-out\u003C\u002Fcode>\u003C\u002Fa> node for anything beyond the\nsimplest messaging use-case as it supports\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fdocs\u002Fattachments\" target=\"_new\">\u003Ccode>attachments\u003C\u002Fcode>\u003C\u002Fa>\nas well as many other features.\u003C\u002Fp>\n\u003Cp>\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fevents\u002Fpresence_sub\" target=\"_new\">\u003Ccode>presence_sub\u003C\u002Fcode>\u003C\u002Fa>\nis a powerful \u003Ca href=\"#slack-rtm-out\">\u003Ccode>slack-rtm-out\u003C\u002Fcode>\u003C\u002Fa> method that allows you to\nreceive\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fevents\u002Fpresence_change\" target=\"_new\">\u003Ccode>presence_change\u003C\u002Fcode>\u003C\u002Fa>\nevents on the \u003Ca href=\"#slack-rtm-in\">\u003Ccode>slack-rtm-in\u003C\u002Fcode>\u003C\u002Fa> node. See the\n\u003Ca href=\"#presence\">presence\u003C\u002Fa> example below for further details.\u003C\u002Fp>\n\u003Cp>Example input:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>msg.topic = 'presence_query';\nmsg.payload = {\n    ids: [\n        '...'\n    ]\n}\nreturn msg;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Example output:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>{\n  \"topic\": \"presence_query\",\n  \"payload\": {\n    \"ok\":true,\n    \"type\":\"presence_query\"\n  },\n  \"slackState\": {\n    ...\n  }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"slack-web-out\">\u003Ca class=\"header-anchor\" href=\"#slack-web-out\">\u003Ccode>slack-web-out\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>Invokes a \u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fmethods\" target=\"_new\">Slack Web\u003C\u002Fa>\nmethod and outputs the \u003Ca href=\"#dressed-output\">\u003Ccode>dressed\u003C\u002Fcode>\u003C\u002Fa> response as the\n\u003Ccode>msg.payload\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>See the \u003Ca href=\"#sending-a-message\">sending a message\u003C\u002Fa> example for advanced message\nsending.\u003C\u002Fp>\n\u003Cp>Example input:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>msg.topic = \"chat.meMessage\";\nmsg.payload = {\n    channel: \"...\",\n    text: \"...\"\n}\n\nreturn msg;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Example output:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>{\n  \"topic\": \"chat.meMessage\",\n  \"payload\": {\n    \"channel\": \"...\",\n    \"ts\": \"1552705036.049000\",\n    \"ok\": true,\n    \"scopes\": [\n      \"identify\",\n      \"read\",\n      \"post\",\n      \"client\",\n      \"apps\"\n    ],\n    \"acceptedScopes\": [\n      \"chat:write:user\",\n      \"post\"\n    ],\n    \"channelObject\": {\n      \"id\": \"...\",\n      ...\n      \"userObject\": {\n        \"id\": \"...\",\n        ...\n      }\n    }\n  },\n  \"slackState\": {\n    ...\n  }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"slack-state\">\u003Ca class=\"header-anchor\" href=\"#slack-state\">\u003Ccode>slack-state\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>\u003Ca href=\"#slack-state\">\u003Ccode>slack-state\u003C\u002Fcode>\u003C\u002Fa> outputs a message with\n\u003Ca href=\"#slackstate\">\u003Ccode>msg.slackState\u003C\u002Fcode>\u003C\u002Fa> added. If the \u003Ccode>msg.payload\u003C\u002Fcode> sent to\n\u003Ca href=\"#slack-state\">\u003Ccode>slack-state\u003C\u002Fcode>\u003C\u002Fa> is \u003Ccode>true\u003C\u002Fcode> then it will first do a full refresh of\nthe state (should not generally be necessary) and then output the \u003Ccode>msg\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>The \u003Ccode>state events\u003C\u002Fcode> (2nd) output of the node emits a signal when the state has\nbeen fully initialized after (re)connect. This can be useful if you want to\nperform any post initilization tasks (ie:\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fevents\u002Fpresence_sub\" target=\"_new\">\u003Ccode>presence_sub\u003C\u002Fcode>\u003C\u002Fa>\n).\u003C\u002Fp>\n\u003Cp>Example input:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>msg.payload = true; \u002F\u002F force a refresh\nreturn msg;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Example output (state):\u003C\u002Fp>\n\u003Cpre>\u003Ccode>{\n  \"slackState\": {\n    ...\n  }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Example output (state events):\u003C\u002Fp>\n\u003Cpre>\u003Ccode>{\n  \"payload\": {\n    \"type\":\"ready\"\n  },\n  \"slackState\": {\n    ...\n  }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch1 id=\"examples-advanced\">\u003Ca class=\"header-anchor\" href=\"#examples-advanced\">Examples \u002F Advanced\u003C\u002Fa>\u003C\u002Fh1>\n\u003Ch2 id=\"sending-a-message\">\u003Ca class=\"header-anchor\" href=\"#sending-a-message\">sending a message\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>While you can send messages using the simplified syntax (\u003Ccode>msg.topic\u003C\u002Fcode> starts\nwith \u003Ccode>@\u003C\u002Fcode> or \u003Ccode>#\u003C\u002Fcode> and \u003Ccode>msg.payload\u003C\u002Fcode> is the message) using either the\n\u003Ca href=\"#slack-web-out\">\u003Ccode>slack-web-out\u003C\u002Fcode>\u003C\u002Fa> or the \u003Ca href=\"#slack-rtm-out\">\u003Ccode>slack-rtm-out\u003C\u002Fcode>\u003C\u002Fa>\nnodes, your use-case may require more control. The most advanced message\nsending can be accomplished by invoking the\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fmethods\u002Fchat.postMessage\" target=\"_new\">\u003Ccode>chat.postMessage\u003C\u002Fcode>\u003C\u002Fa>\nmethod of the \u003Ca href=\"#slack-web-out\">\u003Ccode>slack-web-out\u003C\u002Fcode>\u003C\u002Fa> node:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>var topic = \"chat.postMessage\";\n\nvar payload = {\n    \u002F\u002F channel: \"@someuser\",\n    \u002F\u002F or\n    \u002F\u002F channel: \"#somechannel\",\n    text: \"hi from bot\",\n    ...\n    \u002F\u002F review linked documentation for all options\n}\n\nmsg = {\n  topic: topic,\n  payload: payload\n}\n\nreturn msg;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"respond-to-keyword\">\u003Ca class=\"header-anchor\" href=\"#respond-to-keyword\">respond to keyword\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>A simple respond to \u003Ccode>keyword\u003C\u002Fcode> example \u003Ccode>function\u003C\u002Fcode> node to place between a\n\u003Ca href=\"#slack-rtm-in\">\u003Ccode>slack-rtm-in\u003C\u002Fcode>\u003C\u002Fa> node and a \u003Ca href=\"#slack-web-out\">\u003Ccode>slack-web-out\u003C\u002Fcode>\u003C\u002Fa>\nnode:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F\u002F ignore anything but messages\nif (msg.payload.type != \"message\") {\n    return null;\n}\n\n\u002F\u002F ignore deleted messages\nif (msg.payload.subtype == \"message_deleted\") {\n    return null;\n}\n\n\u002F\u002F ignore messages from bots\nif (msg.payload.bot_id || (msg.payload.userObject &amp;&amp; msg.payload.userObject.is_bot)) {\n    return null;\n}\n\n\u002F\u002F if you only want to watch a specific channel put name here\nvar channel = \"\";\nif (channel &amp;&amp; !msg.payload.channelObject) {\n    return null;\n}\n\nif (channel &amp;&amp; msg.payload.channelObject.name != channel.replace(\u002F^@\u002F, \"\").replace(\u002F^#\u002F, \"\")) {\n    return null;\n}\n\n\u002F\u002F only specific users\nvar username = \"\";\nif (username &amp;&amp; !msq.payload.userObject) {\n    return null;\n}\n\nif (username &amp;&amp; msq.payload.userObject.name.replace(\u002F^@\u002F, \"\") != username)) {\n    return null;\n}\n\n\u002F\u002F check for keyword\n\u002F\u002F could use regex etc\nif (!msg.payload.text.includes(\"keyword\")) {\n    return null;\n}\n\n\u002F\u002F prepare outbound response\nvar topic = \"chat.postMessage\";\nvar payload = {\n    channel: msg.payload.channel, \u002F\u002F respond to same channel\n    \u002F\u002Ftext: '&lt;@' + msg.payload.userObject.name + '&gt;, thanks for chatting',\n    text: '&lt;@' + msg.payload.user + '&gt;, thanks for chatting',\n    \u002F\u002Fas_user: false,\n    \u002F\u002Fusername: \"\",\n    \u002F\u002Fattachments: [],\n    \u002F\u002Ficon_emoji: \"\",\n}\n\nmsg = {\n    topic: topic,\n    payload: payload\n}\n\nreturn msg;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"presence\">\u003Ca class=\"header-anchor\" href=\"#presence\">presence\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>While \u003Ca href=\"#slackstate\">\u003Ccode>slackState\u003C\u002Fcode>\u003C\u002Fa> does not automatically subscribe to\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fevents\u002Fpresence_change\" target=\"_new\">\u003Ccode>presence_change\u003C\u002Fcode>\u003C\u002Fa>\nevents for you, it will keep track of \u003Ccode>presence\u003C\u002Fcode> details in\n\u003Ca href=\"#slackstate\">\u003Ccode>slackState\u003C\u002Fcode>\u003C\u002Fa> if any\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fevents\u002Fpresence_change\" target=\"_new\">\u003Ccode>presence_change\u003C\u002Fcode>\u003C\u002Fa>\nevents are received (this is all done behind the scenes).\u003C\u002Fp>\n\u003Cp>To subscribe to\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fevents\u002Fpresence_change\" target=\"_new\">\u003Ccode>presence_change\u003C\u002Fcode>\u003C\u002Fa>\nevents for all your users place the following \u003Ccode>function\u003C\u002Fcode> node between the\n\u003Ccode>slack events\u003C\u002Fcode> output of the \u003Ca href=\"#slack-state\">\u003Ccode>slack-state\u003C\u002Fcode>\u003C\u002Fa> node and the\n\u003Ca href=\"#slack-rtm-out\">\u003Ccode>slack-rtm-out\u003C\u002Fcode>\u003C\u002Fa> node:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>msg.topic = 'presence_sub';\nvar ids = [];\n\nfor (var id in msg.slackState.members) {\n  if (msg.slackState.members.hasOwnProperty(id)) {\n    ids.push(id)\n  }\n}\n\nmsg.payload = {\n    ids: ids\n}\nreturn msg;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The theory of operation is:\u003C\u002Fp>\n\u003Col>\n\u003Cli>wait for the \u003Ca href=\"#slackstate\">\u003Ccode>slackState\u003C\u002Fcode>\u003C\u002Fa> to be initialized so you have a\ncomplete list of \u003Ccode>members\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>iterate that list to build up the appropriate request to\n\u003Ca href=\"#slack-rtm-out\">\u003Ccode>slack-rtm-out\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>subscribe to presence events by sending the message to\n\u003Ca href=\"#slack-rtm-out\">\u003Ccode>slack-rtm-out\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>receive presence events on the \u003Ca href=\"#slack-rtm-in\">\u003Ccode>slack-rtm-in\u003C\u002Fcode>\u003C\u002Fa> node\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>Immediately after the request is sent you will see a flood of\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fevents\u002Fpresence_change\" target=\"_new\">\u003Ccode>presence_change\u003C\u002Fcode>\u003C\u002Fa>\nevents emitted on the \u003Ca href=\"#slack-rtm-in\">\u003Ccode>slack-rtm-in\u003C\u002Fcode>\u003C\u002Fa> node. Once the initial\nflood of messages has passed continued updates will come through as\nappropriate. Again, behind the scenes the \u003Ca href=\"#slack-state\">\u003Ccode>slack-state\u003C\u002Fcode>\u003C\u002Fa> nodes\nare listening for these events and updating the\n\u003Ca href=\"#slackstate\">\u003Ccode>slackState.presence\u003C\u002Fcode>\u003C\u002Fa> values appropriately for general\nusage\u002Fconsumption in your flow(s).\u003C\u002Fp>\n\u003Cp>If you are really interested in keeping the data updated you could capture\n\u003Ccode>team_join\u003C\u002Fcode> events from a \u003Ca href=\"#slack-rtm-in\">\u003Ccode>slack-rtm-in\u003C\u002Fcode>\u003C\u002Fa> node and wire those\nto the above \u003Ccode>function\u003C\u002Fcode> node as well triggering the same procedure when new\nusers join the \u003Ccode>team\u003C\u002Fcode>. You may need to put a \u003Ccode>delay\u003C\u002Fcode> node before the\n\u003Ccode>function\u003C\u002Fcode> node just to give \u003Ca href=\"#slackstate\">\u003Ccode>slackState\u003C\u002Fcode>\u003C\u002Fa> enough time to process\nthis same event and update.\u003C\u002Fp>\n\u003Cp>An alternative would be to wire an \u003Ccode>inject\u003C\u002Fcode> node to the \u003Ccode>function\u003C\u002Fcode> node and put\nit on a sane \u003Ccode>interval\u003C\u002Fcode> such as every 10 minutes.\u003C\u002Fp>\n\u003Cp>If you wanted to be \u003Cstrong>really\u003C\u002Fstrong> sure you are receiving all\n\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fevents\u002Fpresence_change\" target=\"_new\">\u003Ccode>presence_change\u003C\u002Fcode>\u003C\u002Fa>\nevents for the whole \u003Ccode>team\u003C\u002Fcode> do all the above.\u003C\u002Fp>\n\u003Ch1 id=\"migration-from-012-or-earlier\">\u003Ca class=\"header-anchor\" href=\"#migration-from-012-or-earlier\">migration from \u003Ccode>0.1.2\u003C\u002Fcode> or earlier\u003C\u002Fa>\u003C\u002Fh1>\n\u003Cp>In order to replicate the previous behavior it is possible to introduce simple\n\u003Ccode>function\u003C\u002Fcode> nodes.\u003C\u002Fp>\n\u003Cp>Roughly speaking the node equivalents are:\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>\u003Ccode>0.1.2\u003C\u002Fcode>\u003C\u002Fth>\n\u003Cth>\u003Ccode>2.x\u003C\u002Fcode>\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ca href=\"#slack\">\u003Ccode>slack\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Ftd>\n\u003Ctd>\u003Ca href=\"#slack-web-out\">\u003Ccode>slack-web-out\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ca href=\"#slack-bot-in\">\u003Ccode>Slack Bot In\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Ftd>\n\u003Ctd>\u003Ca href=\"#slack-rtm-in\">\u003Ccode>slack-rtm-in\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ca href=\"#slack-bot-out\">\u003Ccode>Slack Bot Out\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Ftd>\n\u003Ctd>\u003Ca href=\"#slack-rtm-out\">\u003Ccode>slack-rtm-out\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Ch2 id=\"slack\">\u003Ca class=\"header-anchor\" href=\"#slack\">\u003Ccode>slack\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>To replicate the \u003Ccode>slack\u003C\u002Fcode> node simply place the following \u003Ccode>function\u003C\u002Fcode> node just\nbefore the new \u003Ca href=\"#slack-web-out\">\u003Ccode>slack-web-out\u003C\u002Fcode>\u003C\u002Fa> node:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F\u002F https:\u002F\u002Fapi.slack.com\u002Fmethods\u002Fchat.postMessage\nmsg.topic = \"chat.postMessage\"\nvar payload = {\n    text: msg.payload\n};\n\n\u002F\u002F set default username (replicate the node configuration value)\nvar username = \"\";\nif (username) {\n    payload.username = username;\n    payload.as_user = false;\n} else if (msg.username) {\n    payload.username = msg.username;\n    payload.as_user = false;\n}\n\n\u002F\u002F set default emojiIcon (replicate the node configuration value)\nvar emojiIcon = \"\";\nif (emojiIcon) {\n    payload.icon_emoji = emojiIcon;\n} else if (msg.emojiIcon) {\n    payload.icon_emoji = msg.emojiIcon;\n}\n\n\u002F\u002F set default channel (replicate the node configuration value)\nvar channel = \"\";\nif (channel) {\n    payload.channel = channel;\n} else if (msg.channel) {\n    payload.channel = msg.channel\n}\n\nif (msg.attachments) {\n    payload.attachments = msg.attachments;\n}\n\nmsg.payload = payload;\n\nreturn msg;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"slack-bot-in\">\u003Ca class=\"header-anchor\" href=\"#slack-bot-in\">\u003Ccode>Slack Bot In\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>To replicate the \u003Ccode>Slack Bot In\u003C\u002Fcode> node simply place the following \u003Ccode>function\u003C\u002Fcode> node\ndownstream from the new \u003Ca href=\"#slack-rtm-in\">\u003Ccode>slack-rtm-in\u003C\u002Fcode>\u003C\u002Fa> node:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F\u002F https:\u002F\u002Fapi.slack.com\u002Fevents\u002Fmessage\n\nif (msg.payload.type != \"message\") {\n    return null;\n}\n\n\u002F\u002F if you only want to watch a specific channel put name here\nvar channel = \"\";\nif (channel &amp;&amp; !msg.payload.channelObject) {\n    return null;\n}\n\nif (channel &amp;&amp; msg.payload.channelObject.name != channel.replace(\u002F^@\u002F, \"\").replace(\u002F^#\u002F, \"\")) {\n    return null;\n}\n\nvar payload = \"\";\nif (msg.payload.text) {\n    payload += msg.payload.text;\n}\n\nif (msg.payload.attachments) {\n    if (payload) {\n        payload += \"\\n\";\n    }\n\n    msg.payload.attachments.forEach((attachment, index) =&gt; {\n        if (index &gt; 0) {\n            payload += \"\\n\";\n        }\n        payload += attachment.fallback;\n    })\n}\n\nvar slackObj = {\n    id: msg.payload.client_msg_id,\n    type: msg.payload.type,\n    text: msg.payload.text,\n    channelName: msg.payload.channelObject.name,\n    channel: msg.payload.channelObject,\n    fromUser: (msg.payload.userObject) ? msg.payload.userObject.name : \"\",\n    attachments: msg.payload.attachments\n};\n\nmsg = {\n    payload: payload,\n    slackObj: slackObj\n}\n\nreturn msg;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"slack-bot-out\">\u003Ca class=\"header-anchor\" href=\"#slack-bot-out\">\u003Ccode>Slack Bot Out\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>To replicate the \u003Ccode>Slack Bot Out\u003C\u002Fcode> node simply place the following \u003Ccode>function\u003C\u002Fcode>\nnode just before the new \u003Ca href=\"#slack-rtm-out\">\u003Ccode>slack-rtm-out\u003C\u002Fcode>\u003C\u002Fa> node:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F\u002F set channel\nvar channel = \"\";\nif (channel) {\n    \u002F\u002F do nothing, use the provided channel\n} else if (msg.channel) {\n    channel = msg.channel;\n} else if (msg.slackObj &amp;&amp; msg.slackObj.channel) {\n    channel = msg.slackObj.channel\n} else {\n    node.error(\"'slackChannel' is not defined, check you are specifying a channel in the message (msg.channel) or the node config.\");\n    node.error(\"Message: '\" + JSON.stringify(msg));\n    return null;\n}\n\nmsg = {\n    topic: channel,\n    payload: msg.payload\n}\n\nreturn msg;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch1 id=\"additional-resources\">\u003Ca class=\"header-anchor\" href=\"#additional-resources\">Additional Resources\u003C\u002Fa>\u003C\u002Fh1>\n\u003Cul>\n\u003Cli>\u003Ca href=\"http:\u002F\u002Femoji-cheat-sheet.com\" target=\"_new\">Emoji Cheat Sheet\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fapi.slack.com\u002Fdocs\u002Fattachments\" target=\"_new\">Slack Attachments\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>https:\u002F\u002Fslack.dev\u002Fnode-slack-sdk\u002F\u003C\u002Fli>\n\u003Cli>https:\u002F\u002Fslack.dev\u002Fnode-slack-sdk\u002Frtm_api\u003C\u002Fli>\n\u003Cli>https:\u002F\u002Fslack.dev\u002Fnode-slack-sdk\u002Fweb_api\u003C\u002Fli>\n\u003C\u002Ful>\n",1784738655430]