For Zoho services only


I'm currently part of a wider delivery team at Ascent Business Solutions, recognised as a leading Zoho Premium Solutions Partner in the United Kingdom.

Ascent Business Solutions support organisations with everything from targeted technical fixes through to full Zoho CRM implementations and long-term platform adoption. Working as a team rather than a one-person consultancy allows projects to move forward consistently, with access to the right skills at each stage.

The team I manage specialises in API integrations between Zoho and third-party finance and commerce platforms such as Xero, Shopify, WooCommerce, and eBay. Much of our work involves solving integration challenges that fall outside standard documentation, supporting new ideas, new sectors, and evolving business models.

Success is measured through practical outcomes and return on investment, ranging from scaling small operations into high-turnover businesses to delivering rapid gains through online payments, automation, and streamlined digital workflows.

If you are looking for structured Zoho expertise backed by an established consultancy, you can contact Ascent Business Solutions on 0121 392 8140 (UK), email info@ascentbusiness.co.uk, or visit https://www.ascentbusiness.co.uk.
Zoho CRM: JS Widget: Generic Script to pass the Record ID to a CRM function

Zoho CRM: JS Widget: Generic Script to pass the Record ID to a CRM function

What?
There's documentation out there but as this took me a couple of days to simply install a JS widget hosted by Zoho and pass the record ID via a button to it, I'm adding it here in case I need to refer to it in future.

Why?
We have an Accounts module which holds all the companies we deal with in our Zoho CRM. I want our sales team to be able to click on a button off the CRM account record which will call an API returning all the credit information about a company. Unfortunately, if you do this simply using Zoho Deluge in a button, there are no new lines/carriage returns or styling that you can apply, which pops up as a message box to the sales person; but all on one line and not that readable. Using a JS Widget, we can popup a window over the Zoho CRM which displays a more clear HTML & CSS styled message box.

How?
There are links to how to create a widget in detail which I'll link to at the bottom of this page. What follows are the quick steps to create a widget.html file and how to get whatever the Zoho Deluge CRM function returns.

Create a JS Widget on your device (MacOS)
These steps are the minimal amount of information I need to quickly set up a JS widget:
  1. Open a MacOS Terminal
    1. sudo npm install -g zoho-extension-toolkit (this also updates existing install)
    2. sudo zet init
    3. select Zoho CRM
    4. enter a unique Project Name
    5. cd to the new project name
    6. To give permissions to write sudo chmod -R 777 .
    7. open the newly created widget.html file in your code editor
    8. add the code as per the below generic script
    9. when done, save 'widget.html'
    10. then return to terminal and type zet validate
    11. and then type zet pack
    12. this will create a zip file in a dist folder
  2. Login to ZohoCRM as a system administrator
    1. go to Setup > Customization > Modules and Fields > Accounts [or whichever module the button needs to be on] > Buttons > Create New Button
    2. Give it a name, Define the action as Open a Widget, Select Page as In Record, select position as Details then click on Configured Widget - Choose
      1. Click on New Widget, give it a name and set hosting to Zoho
      2. Click on File Upload and upload the zip file that was just created
      3. the Index Page is /widget.html
      4. Hit Save
    3. then find the one you just created in the list and click on Install
    4. Select the profile(s) that will have access to this button and click on Save
  3. Go to a CRM account record and test the button works.
  4. Go back to your Zoho CRM function and simply include HTML and CSS in the output of the function... done.

What we're here for
The following script is what I use to pass the record ID to a CRM function called fn_Accounts_CreditSafe. It was partly written by referring to documentation and using CoPilot or OpenAI ChatGPT for parsing the return value of the function (note that I have SCRIPT within the BODY tags and not in the HEAD):
copyraw
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
  </head>
  <body>
    <script src="https://live.zwidgets.com/js-sdk/1.1/ZohoEmbededAppSDK.min.js"></script>
    <pre>  Loading... Please Wait... </pre>
    <script>
      console.clear();

      ZOHO.embeddedApp.on("PageLoad", function(r_Data) {

        // for debugging
        console.log(r_Data);

        // get id and module on page (if this is a button off a record details view)
        var v_EntityID = r_Data.EntityId, v_EntityModule = r_Data.Entity;

        // get id and module on page (depending on trigger)
        // var v_EntityID = r_Data.EntityId[0], v_EntityModule = r_Data.Entity;

        // Define the function name to be called (don't include the namespace)
        var v_FuncName = "fn_Accounts_GetCreditSafe";

        // Prepare the parameters for the function call
        var m_Params = {
          "arguments": JSON.stringify({
            "p_AccountID": v_EntityID
          })
        };

        ZOHO.CRM.FUNCTIONS.execute( v_FuncName, m_Params )
        .then( function( r_SubData ){

          console.log("Raw response:", r_SubData);

          // Check if the response contains the expected structure
          let output = r_SubData?.details?.output;

          // If the output is JSON text, parse it into a real object
          let parsedOutput;

          try {

            // Attempt to parse the output as JSON
            parsedOutput = JSON.parse(output);

          } catch (e) {

            // If parse fails, just fall back to plain text
            parsedOutput = output;

          }

          // Log the parsed output for debugging
          console.log("Parsed output:", parsedOutput);

          // If parsedOutput is undefined or null, set a default message
          if(parsedOutput === undefined || parsedOutput === null) {

             let errorOutput = r_SubData?.message || "Response from function was unparseable";
            parsedOutput = "<pre style='padding:30px;'>Error: " + errorOutput + "</pre>";
            document.writeln(parsedOutput);

          } else {

            // If parsedOutput is an object, you can now use normal dot notation:
            if (parsedOutput && typeof parsedOutput === "object") {

              // If the output is an object, you can access its properties
              document.writeln(parsedOutput.details.output || "<pre style='padding:30px;'>Error: No parsed output found</pre>");

            } else {

              // If the output is not an object, just write it directly
              document.writeln(parsedOutput);

            }
          }

        })
        .catch( function( r_Error ){
          document.write(JSON.stringify(r_Error));
        });

      });

      ZOHO.embeddedApp.init();

    </script>

  </body>
</html>
  1.  <!DOCTYPE html> 
  2.  <html> 
  3.    <head> 
  4.      <meta charset="UTF-8"> 
  5.    </head> 
  6.    <body> 
  7.      <script src="https://live.zwidgets.com/js-sdk/1.1/ZohoEmbededAppSDK.min.js"></script> 
  8.      <pre>  Loading... Please Wait... </pre> 
  9.      <script> 
  10.        console.clear()
  11.   
  12.        ZOHO.embeddedApp.on("PageLoad", function(r_Data) { 
  13.   
  14.          // for debugging 
  15.          console.log(r_Data)
  16.   
  17.          // get id and module on page (if this is a button off a record details view) 
  18.          var v_EntityID = r_Data.EntityId, v_EntityModule = r_Data.Entity; 
  19.   
  20.          // get id and module on page (depending on trigger) 
  21.          // var v_EntityID = r_Data.EntityId[0], v_EntityModule = r_Data.Entity; 
  22.   
  23.          // Define the function name to be called (don't include the namespace) 
  24.          var v_FuncName = "fn_Accounts_GetCreditSafe"
  25.   
  26.          // Prepare the parameters for the function call 
  27.          var m_Params = { 
  28.            "arguments": JSON.stringify({ 
  29.              "p_AccountID": v_EntityID 
  30.            }) 
  31.          }
  32.   
  33.          ZOHO.CRM.FUNCTIONS.execute( v_FuncName, m_Params ) 
  34.          .then( function( r_SubData ){ 
  35.   
  36.            console.log("Raw response:", r_SubData)
  37.   
  38.            // Check if the response contains the expected structure 
  39.            let output = r_SubData?.details?.output; 
  40.   
  41.            // If the output is JSON text, parse it into a real object 
  42.            let parsedOutput; 
  43.   
  44.            try { 
  45.   
  46.              // Attempt to parse the output as JSON 
  47.              parsedOutput = JSON.parse(output)
  48.   
  49.            } catch (e) { 
  50.   
  51.              // If parse fails, just fall back to plain text 
  52.              parsedOutput = output; 
  53.   
  54.            } 
  55.   
  56.            // Log the parsed output for debugging 
  57.            console.log("Parsed output:", parsedOutput)
  58.   
  59.            // If parsedOutput is undefined or null, set a default message 
  60.            if(parsedOutput === undefined || parsedOutput === null) { 
  61.   
  62.               let errorOutput = r_SubData?.message || "Response from function was unparseable"
  63.              parsedOutput = "<pre style='padding:30px;'>Error: " + errorOutput + "</pre>"
  64.              document.writeln(parsedOutput)
  65.   
  66.            } else { 
  67.   
  68.              // If parsedOutput is an object, you can now use normal dot notation: 
  69.              if (parsedOutput && typeof parsedOutput === "object") { 
  70.   
  71.                // If the output is an object, you can access its properties 
  72.                document.writeln(parsedOutput.details.output || "<pre style='padding:30px;'>Error: No parsed output found</pre>")
  73.   
  74.              } else { 
  75.   
  76.                // If the output is not an object, just write it directly 
  77.                document.writeln(parsedOutput)
  78.   
  79.              } 
  80.            } 
  81.   
  82.          }) 
  83.          .catch( function( r_Error ){ 
  84.            document.write(JSON.stringify(r_Error))
  85.          })
  86.   
  87.        })
  88.   
  89.        ZOHO.embeddedApp.init()
  90.   
  91.      </script> 
  92.   
  93.    </body> 
  94.  </html> 


[Note to self]
Retrieving the record itself (not needed for this task):
copyraw
ZOHO.embeddedApp.on("PageLoad", function(r_Data) {
        // get id and module on page
        var v_EntityID = r_Data.EntityId, v_EntityModule = r_Data.Entity;

        // get the record details
        ZOHO.CRM.API.getRecord({ Entity: v_EntityModule, RecordID: v_EntityID })
        .then(function(response) {
            console.log("Record data:");
            console.log(response);
        }).catch(function(error) {
            console.log("Error:");
            console.log(error);
        });
});
ZOHO.embeddedApp.init();
  1.  ZOHO.embeddedApp.on("PageLoad", function(r_Data) { 
  2.          // get id and module on page 
  3.          var v_EntityID = r_Data.EntityId, v_EntityModule = r_Data.Entity; 
  4.   
  5.          // get the record details 
  6.          ZOHO.CRM.API.getRecord({ Entity: v_EntityModule, RecordID: v_EntityID }) 
  7.          .then(function(response) { 
  8.              console.log("Record data:")
  9.              console.log(response)
  10.          }).catch(function(error) { 
  11.              console.log("Error:")
  12.              console.log(error)
  13.          })
  14.  })
  15.  ZOHO.embeddedApp.init()

[Optional]
What follows is the code for the function fn_Accounts_CreditSafe... obviously I can't give you the real Zoho Deluge function here as it would use my credentials but what you need to know is that it is passed the crmAPIRequest (string) variable and that the function itself had to have API Key and OAuth enabled (hover over function in CRM setup and select REST API, then tick both to the "on" position). The returned output from this function should be the HTML that will be displayed in your JS Widget:
copyraw
string standalone.fn_Accounts_GetCreditSafe(string crmAPIRequest)
{
/* *******************************************************************************
	Function:       string standalone.fn_Accounts_GetCreditSafe(string crmAPIRequest)
	Label:          Fn - Accounts - Get Credit Safe Details
	Trigger:        On-Demand / Widget
	Purpose:		Given an account ID returns the credit safe details from CreditSafe Connect API. This function is used by a JS Widget.
	Inputs:         string crmAPIRequest (webhook request from Zoho CRM)
	Outputs:        -

	Date Created:   2025-08-15 (Ascent Business - Joel Lipman)
					- Initial release
					- Testing auth and connection
	Date Modified:	2025-08-15 (Ascent Business - Joel Lipman)
					- Separated function from button so that is can be used by Widget
	******************************************************************************* */
	//
	// initialize
	v_AccountID = "";
	v_Output = "Error: Could not retrieve given CRM Account ID";
	//
	// ****************************** GENERIC CODE BELOW ******************************
	//
	// retrieving the parameters of the request
	m_RequestParams = crmAPIRequest.toMap().get("params");
	//
	// retrieving the set of values from 'arguments' passed in the javascript code
	m_Arguments = ifnull(m_RequestParams.get("arguments"), Map());
	//
	if(!isNull(m_Arguments.get("p_AccountID")))
	{
		v_AccountID = m_Arguments.get("p_AccountID").toString();
		v_Output = "Info: Recognized CRM Account ID: " + v_AccountID;
		//
		r_Account = zoho.crm.getRecordById("Accounts",v_AccountID.toLong());
		if(!isNull(r_Account.get("id")))
		{
			v_Output = "Info: Retrieved Record of CRM Account ID: " + v_AccountID;
		}
	}
	//
	// format output
	v_OutputHtml = "<h1 style='color:green'>Hullo World!</h1><p>"+v_Output+"</p>";
	return v_OutputHtml;
}
  1.  string standalone.fn_Accounts_GetCreditSafe(string crmAPIRequest) 
  2.  { 
  3.  /* ******************************************************************************* 
  4.      Function:       string standalone.fn_Accounts_GetCreditSafe(string crmAPIRequest) 
  5.      Label:          Fn - Accounts - Get Credit Safe Details 
  6.      Trigger:        On-Demand / Widget 
  7.      Purpose:        Given an account ID returns the credit safe details from CreditSafe Connect API. This function is used by a JS Widget. 
  8.      Inputs:         string crmAPIRequest (webhook request from Zoho CRM) 
  9.      Outputs:        - 
  10.   
  11.      Date Created:   2025-08-15 (Ascent Business - Joel Lipman) 
  12.                      - Initial release 
  13.                      - Testing auth and connection 
  14.      Date Modified:    2025-08-15 (Ascent Business - Joel Lipman) 
  15.                      - Separated function from button so that is can be used by Widget 
  16.      ******************************************************************************* */ 
  17.      // 
  18.      // initialize 
  19.      v_AccountID = ""
  20.      v_Output = "Error: Could not retrieve given CRM Account ID"
  21.      // 
  22.      // ****************************** GENERIC CODE BELOW ****************************** 
  23.      // 
  24.      // retrieving the parameters of the request 
  25.      m_RequestParams = crmAPIRequest.toMap().get("params")
  26.      // 
  27.      // retrieving the set of values from 'arguments' passed in the javascript code 
  28.      m_Arguments = ifnull(m_RequestParams.get("arguments"), Map())
  29.      // 
  30.      if(!isNull(m_Arguments.get("p_AccountID"))) 
  31.      { 
  32.          v_AccountID = m_Arguments.get("p_AccountID").toString()
  33.          v_Output = "Info: Recognized CRM Account ID: " + v_AccountID; 
  34.          // 
  35.          r_Account = zoho.crm.getRecordById("Accounts",v_AccountID.toLong())
  36.          if(!isNull(r_Account.get("id"))) 
  37.          { 
  38.              v_Output = "Info: Retrieved Record of CRM Account ID: " + v_AccountID; 
  39.          } 
  40.      } 
  41.      // 
  42.      // format output 
  43.      v_OutputHtml = "<h1 style='color:green'>Hullo World!</h1><p>"+v_Output+"</p>"
  44.      return v_OutputHtml; 
  45.  } 


Source(s)

Category: Zoho CRM :: Article: 432

Joes Word Cloud

have   output   need   embeddedapp   function   accounts   using   your   record   there   which   give   create   will   that   deluge   zoho   here   widget   file   select   install   click   parsedoutput   html   simply   message   name   page   button   JoelLipman.Com

Accreditation

Badge - Zoho Creator Certified Developer Associate
Badge - Zoho Deluge Certified Developer
Badge - Certified Zoho CRM Developer

Donate & Support

If you like my content, and would like to support this sharing site, feel free to donate using a method below:

Paypal:
Donate to Joel Lipman via PayPal

Bitcoin:
Donate to Joel Lipman with Bitcoin bc1qf6elrdxc968h0k673l2djc9wrpazhqtxw8qqp4

Ethereum:
Donate to Joel Lipman with Ethereum 0xb038962F3809b425D661EF5D22294Cf45E02FebF

Credit where Credit is Due:


Feel free to copy, redistribute and share this information. All that we ask is that you attribute credit and possibly even a link back to this website as it really helps in our search engine rankings.

Disclaimer: Please note that the information provided on this website is intended for informational purposes only and does not represent a warranty. The opinions expressed are those of the author only. We recommend testing any solutions in a development environment before implementing them in production. The articles are based on our good faith efforts and were current at the time of writing, reflecting our practical experience in a commercial setting.

Thank you for visiting and, as always, we hope this website was of some use to you!

Kind Regards,

Joel Lipman
www.joellipman.com