Bulk user onboarding for Cliq channels in a jiffy

Bulk user onboarding for Cliq channels in a jiffy

As developers, we frequently switch between coding, debugging, and optimizing tasks. The last thing we want is to be burdened by manual user management. Adding users one by one to a channel is tedious and prone to errors, taking up more time than we could devote to actual development. 



Let's explore how to create a custom workflow using Cliq's platform components to streamline the process of bulk-adding users to a channel via a Zoho Sheet or CSV file. This approach facilitates a smooth onboarding experience without the need for manual effort.

Pre-requisite :

Before beginning to script the code below, we must create a connection with Zoho Cliq. Once a connection is created and connected, you can use it in Deluge integration tasks and invoke URL scripts to access data from the required service.

Create a Zoho Oauth default connection with any unique name and the scopes -  ZohoCliq.Channels.All and ZohoSheet.dataApi.ALL

Refer to the below links to learn more :

Step 1  : Creation of slash command

  • After a successful login in Cliq, hover to the top right corner and click your profile. Post clicking, navigate to Bots & Tools > Commands.
  • At your right, click the button - Create Command.
  • To know more about slash commands and their purposes, refer to Introduction to slash commands.
  • Create a slash command using your preferred name. Specify the following details: the command name, a hint (to give users an idea of what the command is for), and the access level.
  • Finally, click "Save & edit code".

  1. inputs = List();
  2. inputs.add({"name":"channels","label":"Pick a channel","placeholder":"Choose a channel where you need to add members","max_selections":"1","multiple":false,"mandatory":true,"type":"native_select","data_source":"channels"});
  3. inputs.add({"name":"headername","label":"Header name","placeholder":"Email ID","hint":"In which the Email ID is present","min_length":"0","max_length":"25","mandatory":true,"type":"text"});
  4. inputs.add({"type":"radio","label":"Import type","name":"import_Type","hint":"Choose a type that you need to import users","options":[{"label":"CSV","value":"csv"},{"label":"Zoho sheet","value":"zohosheet"}],"trigger_on_change":"true"});
  5. return {"name":"addbulkuser","type":"form","title":"Add bulk users","hint":"To add maximum of upto 1000 users in a channel.","button_label":"Add Users","inputs":inputs,"action":{"type":"invoke.function","name":"addbulkusers"};

Step 2  : Scripting form function

  • We need to create a function for the form that manages submission responses, including the Zoho Sheet link or CSV file, the name of the column containing the email addresses, and the channel details where users should be added in bulk.
  • Hover to the top right corner and click your profile. After clicking, navigate to Bots & Tools > Functions.
  • To your right, click the Create Function button.
  • Name the function "addbulkusers," provide a description as desired, and select "form" as the function type. Then, click "Save and edit code," and paste the following code.
  1. emailIdList = list();
  2. successlist = list();
  3. failedlist = list();
  4. try 
  5. {
  6. info form;
  7. formValues = form.get("values");
  8. columnName = formValues.get("headername");
  9. headerName = formValues.get("headername");
  10. if(formValues.get("import_Type").get("value") == "zohosheet")
  11. {
  12. url = formValues.get("url");
  13. spreadSheetId = url.getPrefix("?").getSuffix("open/");
  14. sheetName = url.getSuffix("?").getPrefix("&").getSuffix("=");
  15. worksheetname = sheetName.replaceAll(" ","%20");
  16. columnName = columnName.replaceAll(" ","%20");
  17. allDatas = list();
  18. params = Map();
  19. params.put("column_names",columnName);
  20. params.put("method","worksheet.records.fetch");
  21. params.put("worksheet_id",sheetName + "#");
  22. sheetDetails = invokeurl
  23. [
  24. url :"https://sheet.zoho"+environment.get("tld")+"/api/v2/" + spreadSheetId
  25. type :GET
  26. parameters:params
  27. connection:"addbulkusers"
  28. ];
  29. info sheetDetails;
  30. if(sheetDetails.get("status") == "success" && sheetDetails.get("records").size() <= 1000)
  31. {
  32. allDatas.addAll(sheetDetails.get("records"));
  33. }
  34. else if(sheetDetails.get("status") == "success" && sheetDetails.get("records").size() > 1000)
  35. {
  36. return {"type":"form_error","text":"I can only able to add 1000 user. Kindly try passing with 1000 records in the sheet!!!"};
  37. }
  38. else
  39. {
  40. return {"type":"form_error","text":"I can't find any email ids. Kindly re-check the column name and header row!!!"};
  41. }
  42. info "allData: " + allDatas.size();
  43. if(allDatas.size() > 1000)
  44. {
  45. return {"type":"form_error","text":"I can only able to add 1000 user. Kindly try passing with 1000 records in the sheet!!!"};
  46. }
  47. for each  data in allDatas
  48. {
  49. if(data.get(formValues.get("headername")) == null)
  50. {
  51. return {"type":"form_error","text":"I can't find any email ids. Kindly re-check the column name and header row!!!"};
  52. }
  53. emailIdList.add(data.get(formValues.get("headername")));
  54. if(emailIdList.size() == 100)
  55. {
  56. channelID = formValues.get("channels").get("id");
  57. params = {"email_ids":emailIdList};
  58. info "Params: " + params;
  59. addUsers = invokeurl
  60. [
  61. url :environment.get("base_url") + "/api/v2/channels/" + channelID + "/members"
  62. type :POST
  63. parameters:params.toString()
  64. detailed:true
  65. connection:"addbulkusers"
  66. ];
  67. info "Adduser: " + addUsers;
  68. if(addUsers.get("responseCode") == "204")
  69. {
  70. successlist.addAll(emailIdList);
  71. }
  72. else
  73. {
  74. failedlist.addAll(emailIdList);
  75. }
  76. info "100: " + emailIdList.size();
  77. emailIdList = list();
  78. }
  79. }
  80. if(emailIdList.size() > 0)
  81. {
  82. channelID = formValues.get("channels").get("id");
  83. params = {"email_ids":emailIdList};
  84. info "Params: " + params;
  85. addUsers = invokeurl
  86. [
  87. url :environment.get("base_url") + "/api/v2/channels/" + channelID + "/members"
  88. type :POST
  89. parameters:params.toString()
  90. detailed:true
  91. connection:"addbulkusers"
  92. ];
  93. info "Adduser: " + addUsers;
  94. if(addUsers.get("responseCode") == "204")
  95. {
  96. successlist.addAll(emailIdList);
  97. }
  98. else
  99. {
  100. failedlist.addAll(emailIdList);
  101. }
  102. info "Email id: " + emailIdList;
  103. }
  104. info "Successlist: " + successlist;
  105. info "Failedlist: " + failedlist;
  106. if(successlist.size() > 0 && failedlist.size() > 0)
  107. {
  108. postMessage = {"text":"Successfully added " + successlist.size() + " member(s) and failed for " + failedlist.size() + " Member(s)"};
  109. }
  110. else if(successlist.size() > 0 && !failedlist.size() > 0)
  111. {
  112. postMessage = {"text":"Successfully added " + successlist.size() + " member(s)"};
  113. }
  114. else if(!successlist.size() > 0 && failedlist.size() > 0)
  115. {
  116. postMessage = {"text":"Adding members in channel failed for " + failedlist.size() + " member(s)"};
  117. }
  118. info zoho.cliq.postToChat(chat.get("id"),postMessage);
  119. }
  120. else
  121. {
  122. csvFile = formValues.get("csvFile");
  123. csvFile = csvFile.getfilecontent();
  124. allDatas = csvFile.toList("\n");
  125. i = 0;
  126. indexValue = 0;
  127. indexBoolean = false;
  128. for each  data in allDatas
  129. {
  130. if(i == 0)
  131. {
  132. headers = data.toList(",");
  133. for each  header in headers
  134. {
  135. info header;
  136. if(headerName == header)
  137. {
  138. indexBoolean = true;
  139. indexValue = headers.indexOf(headerName);
  140. }
  141. }
  142. if(indexBoolean == false)
  143. {
  144. return {"type":"form_error","text":"I can't find any email ids. Kindly re-check the column name and header row!!!"};
  145. }
  146. }
  147. else 
  148.             {
  149. emailIdList.add(data.get(indexValue));
  150.             }
  151. i = i + 1;
  152. if(emailIdList.size() == 100)
  153. {
  154. channelID = formValues.get("channels").get("id");
  155. params = {"email_ids":emailIdList};
  156. info "Params: " + params;
  157. addUsers = invokeurl
  158. [
  159. url :environment.get("base_url") + "/api/v2/channels/" + channelID + "/members"
  160. type :POST
  161. parameters:params.toString()
  162. detailed:true
  163. connection:"addbulkusers"
  164. ];
  165. info "Adduser: " + addUsers;
  166. if(addUsers.get("responseCode") == "204")
  167. {
  168. successlist.addAll(emailIdList);
  169. }
  170. else
  171. {
  172. failedlist.addAll(emailIdList);
  173. }
  174. info "100: " + emailIdList.size();
  175. emailIdList = list();
  176. }
  177. }
  178. if(emailIdList.size() > 0)
  179. {
  180. channelID = formValues.get("channels").get("id");
  181. params = {"email_ids":emailIdList};
  182. info "Params: " + params;
  183. addUsers = invokeurl
  184. [
  185. url :environment.get("base_url") + "/api/v2/channels/" + channelID + "/members"
  186. type :POST
  187. parameters:params.toString()
  188. detailed:true
  189. connection:"addbulkusers"
  190. ];
  191. info "Adduser: " + addUsers;
  192. if(addUsers.get("responseCode") == "204")
  193. {
  194. successlist.addAll(emailIdList);
  195. }
  196. else
  197. {
  198. failedlist.addAll(emailIdList);
  199. }
  200. }
  201. info "Successlist: " + successlist;
  202. info "Failedlist: " + failedlist;
  203. if(successlist.size() > 0 && failedlist.size() > 0)
  204. {
  205. postMessage = {"text":"Successfully added " + successlist.size() + " member(s) and failed for " + failedlist.size() + " Member(s)"};
  206. }
  207. else if(successlist.size() > 0 && !failedlist.size() > 0)
  208. {
  209. postMessage = {"text":"Successfully added " + successlist.size() + " member(s)"};
  210. }
  211. else if(!successlist.size() > 0 && failedlist.size() > 0)
  212. {
  213. postMessage = {"text":"Adding members in channel failed for " + failedlist.size() + " member(s)"};
  214. }
  215. info zoho.cliq.postToChat(chat.get("id"),postMessage);
  216. }
  217. }
  218. catch (e)
  219. {
  220. info e;
  221. return {"type":"form_error","text":"I can't find any email ids. Kindly re-check the column name and header row!!!"};
  222. }
  223. return Map();

Step 3  : Configuring form change handler

  • After copying and pasting the code into the form submission handler, navigate to the form change handler for the created form function.
  • You can find this in the top left corner of the editor, where you will see an arrow next to the form submission handler. Clicking on this arrow will display the form change handler in a dropdown menu.
  • Click it to edit the code in the form change handler, which is necessary for real-time modifications to a form's structure or behaviour based on user input in a specific field. 
  1. targetName = target.get("name");
  2. info targetName;
  3. inputValues = form.get("values");
  4. info inputValues;
  5. actions = list();
  6. if(targetName.containsIgnoreCase("import_Type"))
  7. {
  8. fieldValue = inputValues.get("import_Type").get("value");
  9. info fieldValue;
  10. if(fieldValue == "csv")
  11. {
  12. actions.add({"type":"add_after","name":"import_Type","input":{"label":"CSV File","name":"csvFile","placeholder":"Please upload a zCSV File","mandatory":true,"type":"file"}});
  13. actions.add({"type":"remove","name":"url"});
  14. }
  15. else if(fieldValue == "zohosheet")
  16. {
  17. actions.add({"type":"add_after","name":"import_Type","input":{"name":"url","label":"Enter the sheet url","placeholder":"https://sheet.zoho.com/sheet/open/6xhgb324f142e91d845e5b4b472f7422379c9","min_length":"0","max_length":"400","mandatory":true,"type":"text","format":"url"}});
  18. actions.add({"type":"remove","name":"csvFile"});
  19. }
  20. }
  21. return {"type":"form_modification","actions":actions};

Business use cases:

  • HR onboarding: Seamlessly add new employees to internal communication channels.
  • Event management: Quickly invite attendees to event-specific channels.
  • Education platforms: Enroll students in course groups in one go.
  • Community building: Grow large communities by importing member lists effortlessly.

Bottom line

Bulk user addition in Cliq channels through Zoho Sheet or CSV files allows us to eliminate tedious tasks, reduce errors, and manage large-scale data effortlessly. Is onboarding consuming too much of your valuable development time? If so, it might be time to shake things up with a customized workflow!

We're here to help, so don't hesitate to reach out to support@zohocliq.com with any questions or if you need assistance in crafting even more tailored workflows.


      • Sticky Posts

      • Bulk user onboarding for Cliq Channels in a jiffy

        As developers, we frequently switch between coding, debugging, and optimizing tasks. The last thing we want is to be burdened by manual user management. Adding users one by one to a channel is tedious and prone to errors, taking up more time than we could
      • Convert a message on Cliq into a task on Zoho Connect

        Message actions in Cliq are a great way to transform messages in a conversation into actionable work items. In this post, we'll see how to build a custom message action that'll let you add a message as a task to board on Zoho Connect. If you haven't created
      • Unfurling Unlimited Possibilities in Zoho Cliq 🔗

        Are you tired of your app links looking plain? Imagine if the shared links came to life with custom previews, organized data, and one-click actions, making chats more interactive. With the Cliq platform's unfurl handlers, let's see how developers can
      • Let's build a dashboard with Cliq Widgets!

        While juggling multiple tasks and tracking real-time data, you face a strict deadline for delivering a quarterly analysis report on a blank canvas while switching between different apps. Sounds exhausting, right? What if you could streamline everything
      • Cliq Bots - Post message to a bot using the command line!

        If you had read our post on how to post a message to a channel in a simple one-line command, then this sure is a piece of cake for you guys! For those of you, who are reading this for the first time, don't worry! Just read on. This post is all about how

        • Recent Topics

        • Zoho Sign API lacking clarity

          I'm trying to use Zoho Sign to embed a document for signing into a web application, and the documentation is proving to to be lacking something. Some issues... 1) No clarity if the API only works with a document uploaded through the API -- it would be
        • 【Zoho CRM】キャンバス機能のアップデート

          ユーザーの皆さま、こんにちは。コミュニティチームの藤澤です。 今回は「Zoho CRM アップデート情報」の中からキャンバス機能のアップデートをご紹介します。 新たに追加された「可変式ボックス」では、データの表示方法を柔軟にカスタマイズ可能です。画面サイズやデバイスに応じてレイアウトが自動調整されるため、より快適なユーザー体験が実現します。 【目次】 可変式ボックスとは 主要機能の詳細 より高度な可変式ツール 1.可変式ボックスとは 可変式ボックスをレイアウトに組み込むことで、高いカスタマイズ性と柔軟なデザインが可能になり、データの視覚化やユーザーインタラクションがより効果的に行うことができます。以下が可変式ボックスが備える主要な機能の概要です。
        • Unable to delete Attachment on Modules/Record

          Hi Team, Could you please check the backend. Looks like today, CRM decided not to allow deletion of Attachment on Modules or Records. No error message but when you click Delete > Move to recycle bin, nothing happens. Please fix ASAP.
        • Simple Text Search Function

          Would it be too much to ask for a simple text search function? My slide decks are often simply collections of slides of a random over, and I often have to find the slide I need at a moment's notice. A text search function, no matter how rudimentary, would
        • Removed email address - can't access account

          Hi Zoho Support Team, I recently removed my email address from my Zoho Desk account (which is part of our organization's Desk setup) and then signed out. Now, I’m unable to log back in because there is no email address associated with the account, even
        • Customers not receiving emails

          So, a little backstory, we have been using Zoho Forms for the past eight years. And when we initially started, we would have email notifications be sent from inside Zoho Forms after a submission. We recently started using Zoho CRM as we wanted a better
        • Clone a Module??

          I am giong to repurpose the Vendors module but would like to have a separate but very similar module for another group of contacts called Buyers. I have already repurposed Contacts to Sellers. Is it possible to clone (make a duplicate) module of Vendors
        • Share passwords/secrets and folders/chambers with external users

          Currently you allow sharing passwords with internal users, internal user groups, and third parties. The third party feature gives temporary access of 30 minutes and it does not have any sign up. What we really need is to properly share secrets/passwords (and ideally folders/chambers) with Zoho Vault users that are not part of our organisation - even if they are on the free plan. If they accept the share, the password would be stored in their Zoho Vault as long as I maintain the share. If I revoke
        • Does Zoho US Payroll now support employees in multiple states?

          Does Zoho US now support having employees in multiple US states? I looked at the site and can't find and of the restrictions on multiple states anywhere.
        • Zoho Payroll: Product Updates | April 2025

          At Zoho Payroll, we’re always working to make every payday feel effortless. And sometimes, that means listening closely to your unique needs. This month, we’ve focused on adding features that give you the flexibility to pay your employees based on your
        • Notebook for watch no longer in Play store.

          I had to reinstall Notebook on my Galaxy Watch 7. Alas: the app is no longer available in the Play store. What now?
        • move notebooks to another notebook?

          Do I have the ability to add one or more existing notebooks to another notebook? For example, I have an existing notebook named Dog, with several articles in it, and I would like to move it to another notebook called animals?
        • Import from OneNote

          Is there a way to import notes from OneNote? 
        • Add export option that only export one or selected notebooks

          Currently the export function will export ALL data every time, this not only wastes user bandwidth, disk I/O and local storage space, but also consumes more resources on the server. Partial export should be a very basic and easy-to-implement feature.
        • Make other sub fields mandatory, if first subfield is not empty

          I am not finding an option in the rules to make other sub fields mandatory if the first sub field is not empty. I am using the name field to collect parts info, with sub fields of Part Name, Part Number, and Quantity. But I don't want these mandatory
        • Is Zoho Marketing Plus part of Zoho One?

          Hi, Is the new fancy Zoho Marketing Plus part of the Zoho One package? Is there any benefit in using this rather than the standalone products? Many thanks Jon
        • Ability to Initiate WhatsApp Template Messages in Zoho SalesIQ Without Preexisting Chat

          Hi Zoho SalesIQ Team, I hope you're doing well. I understand that with the WhatsApp integration in SalesIQ, clients can contact us via WhatsApp, and we can use WhatsApp templates to send messages outside of the 24-hour window by reopening an existing
        • Duplicating Forms doesn't duplicate Forms attachment path to workdrive

          Hi, I have this user, who uses one forms and duplicates it when needed and update the content. For him, it's important to have the submission forms saved in a specific folder inside Workdrive (as this PDF is transmitted later to another team). However,
        • Zoho Creator Mobile app no Default Workspace

          When I use the Zoho Creator mobile app I do not get a default workspace. This is occurring for me and another new user. I believe this is an issue with Zoho One / Zoho Creator. I have tried working with support and it's been over a week of no solution
        • Kaizen #189: Manipulating Multi-Module Lookup (MML) Field using Zoho CRM APIs

          Hello everyone! Welcome back to another week of Kaizen. In this post, we explore the Multi-Module Lookup (MML) field in the Appointments module of Zoho CRM. You learn what an MML field is, how it works, and how to use it with Zoho CRM APIs. Table of Contents:
        • Xcode 16.2

          I am facing multiple bitcode enable issue with Zoho. Which version is compatible with xcode 16.2 or version with out bitcode Flutter 3.27.4 pod 'ZohoDeskPortalCore' pod 'ZohoDeskPortalServices'
        • Unable to invite contacts

          Hi! I'm unable to invite contacts as end-users from my trial account. The green pop-up displays "Invited succesfully" but the email never arrives, nor the re-invitation - even though it's "sucessfully" as well. Tried with several e-mail accounts, even
        • Set expiration date on document and send reminder

          We have many company documents( for example business registration), work VISA documents. It will be nice if we can set a expiry date and set reminders ( for example 90 days, 60 days, 30 days etc.,) Does Zoho workdrive provide that option?
        • Refresh Page Or View After Workflow-Triggered Rule

          Good Morning, Is this feature that's discussed on this CRM thread available on Recruit? https://help.zoho.com/portal/en/community/topic/refresh-page-or-view-after-workflow-triggered-rule
        • Forward, attach, or flag email to an open ticket.

          Hi, when resolving customer requests through tickets in Zoho Desk, it is very common to receive emails from suppliers or third parties in Zoho Mail accounts or email groups that are not registered in the system. Is there any way to forward these emails
        • Need help adding Zoho Vault License

          "Proceed" is grayed our when i try to add 5 more license on our Zoho Vault account. Thanks
        • Notifications no longer being sent to my email address for any scheduled events

          The last few weeks, I stopped receiving email notifications to my email for events I have scheduled and have a selected reminder option checked.
        • 'call for best price' option

          Hi guys, Pricing of items that we sell to end-customers changes often, so I don't want to put up a 'static' price, but would like to have the option to 'call for best price', or what-ever the best wording is.. Has anybody got a suggestion on how to do
        • Modifying product search in invoice field

          Hello, I imported my product list in Books. Since I have many products with the same name, but with different order units, and that Books doesn't permit same names in items, I used ID's number has product name, and put the product name in the description.
        • How do I embed the webinar into a webpage?

          All I can seem to do is embed the signup form. This is cheesy. Surely they must have fixed this by now, right? How do I do it?
        • Bulk upload image option in Zoho Commerce

          I dont know if I am not looking into it properly but is there no option to bulk upload images along with the products? Like after you upload the products, I will have to upload images one by one again? Can someone help me out here? And what should I enter
        • 404 Error When Using record_cursor in ZOHO.CREATOR.DATA.getRecords (js api)

          Iam working on fetching all records from a Zoho Creator report using the Get Records API (V2.1) with the following recursive function: js CopyEdit // Recursive function to fetch records using record_cursor from the response function fetchAllRecords(recordCursor
        • Add haptic feedback when QR / barcode is scanned

          Hi, One of my user has a Creator App and scan QR codes. He suggests a haptic feedback is a great addition to validate that the QR code is effectively scanned and inserted in to the field. He is using an iPad for scanning. Thank you !
        • Input list of records in Lookup

          Salut, I have 2 scripts that input list of records in a lookup. The first on works fine, the second one doesn't and I do not know why. The only differences, is that the first one input in a lookup a list of records from an actual lookup field, and with
        • Are downloadable product available in Zoho Commerce

          Hi all. We're considering switching to Zoho Commerce for our shop, but we sell software and remote services. Is there a features for downloadable products? I can't find any information about this. Thank you very much Alice
        • Parent-Child Tickets using API or Deluge

          Hi Everyone, We are looking at the parent-child ticketing features in Zoho Desk. We want to be able to create a parent ticket at customer level and nest child tickets underneath. The issue we are facing is to be able to automate this. I'm checking the
        • In line code commenting in Deluge

          A request to enhance readability: currently you can add 'in line' comments for Deluge code, but after you save and reopen, the comments are moved down to the new line. i.e. info "test response"; //this is a info statement for a test response gets changed
        • Delete purchase order

          Buenos días, quisiera su ayuda para retirar los documentos adjuntos, ya que necesito iniciar sesión nuevamente para la venta de unos vehículos.
        • Zoho One Groups and Departments - how are they used ?

          I've seen that Zoho One has the ability to create Groups and Departments, however they don't seem to do anything ? There is no ability to pick up these same groups in ; Zoho Analytics, Zoho Forms, Zoho Vault for just starters . Why aren't the Zoho One
        • Insert Dates Into Subform

          Hi Everyone, Good evening. I've been looking for this all day, but can't find it. Is it possible to insert the entire date inputted from start date and end date into the subform? I also attached the image, to make it clearer. Jadwal Pertemuan = Start
        • Next Page