# Node.js -------------------------------------------------------------------------------- title: "Introduction" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.682Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/express/introduction/" service: "All Services" related: - Project Directory Structure (/en/cli/v1/project-directory-structure/introduction/) - Catalyst SDK for AppSail (/en/serverless/help/appsail/key-concepts/catalyst-configurations/#implementing-catalyst-sdk-in-appsail/) -------------------------------------------------------------------------------- # Lead Manager App Using AppSail ### Introduction This tutorial will help you build a **Node.js Express** application web application called **Lead Manager**. This web app will allow you to connect with your {{%link href="https://www.zoho.com/in/crm/" %}}Zoho CRM account{{%/link%}} and enable you to manage leads in your organization. You will be able to access, add, edit, or delete leads in the {{%link href="https://help.zoho.com/portal/en/kb/crm/sales-force-automation/leads"%}}Leads module{{%/link%}} in your CRM account directly from this application. The connection to Zoho CRM is established using {{%link href="/en/api/oauth2/overview-and-terminology/#OverviewandTerminology" %}}OAuth 2.0 authentication protocol{{%/link%}}. We will generate an {{%badge%}}OAuth Access Token{{%/badge%}} for the *Lead Manager* application and use it to authorize the connection to access CRM data. The authentication requirement in this tutorial is handled using {{%link href="/en/cloud-scale/help/authentication/native-catalyst-authentication/embedded-authentication/introduction/" %}}Embedded Authentication{{%/link%}}. We will also implement a {{%link href="/en/sdk/nodejs/v2/connectors/connectors/" %}}Catalyst Connector{{%/link%}} to manage this access to the CRM account. The connector will refresh the {{%badge%}}Access Token{{%/badge%}} automatically each time it expires using a {{%badge%}}Refresh Token{{%/badge%}}, and will maintain a constant connection between the client and the CRM account. These tokens can be generated after registering the client application in the {{%link href="https://api-console.zoho.com/" %}}Zoho API console{{%/link%}} and obtaining the required credentials. The client application will look like this: <br /> The Lead Manager application employs components from the following Catalyst services: - {{%link href="/en/serverless/" %}}**Catalyst Serverless**{{%/link%}}: - {{%link href="/en/serverless/help/appsail/introduction/" %}}AppSail{{%/link%}}: To host the independent *Node.js Express* application. We will be building the front-end of the app as well as the back-end logic, and bundling them together to deploy them on AppSail. - {{%link href="/en/cloud-scale/" %}}**Catalyst CloudScale**{{%/link%}}: - {{%link href="/en/cloud-scale/help/data-store/introduction/" %}}Data Store{{%/link%}}: To store the {{%badge%}}Refresh Token{{%/badge%}} and {{%link href="/en/cloud-scale/help/authentication/user-management/users/introduction/" %}}UserID of the Catalyst user{{%/link%}} fetched by the function resource. The {{%badge%}}Refresh Token{{%/badge%}} is fetched from this table by the function, whenever a new {{%badge%}}Access Token{{%/badge%}} needs to be generated. - {{%link href="/en/cloud-scale/help/zcql/introduction/" %}}ZCQL{{%/link%}}: To fetch data from the *Data Store* through querying. - {{%link href="/en/cloud-scale/help/authentication/introduction/" %}}Catalyst Authentication{{%/link%}}: To implement a {{%link href="/en/cloud-scale/help/authentication/social-logins/configuring-social-logins/#enable-zoho-social-login" %}}Zoho social login{{%/link%}} in the client application’s login page, in addition to the standard login option, we will be implementing the {{%link href="/en/cloud-scale/help/authentication/native-catalyst-authentication/embedded-authentication/introduction/" %}}Embedded Authentication type{{%/link%}} in this tutorial. We will use the {{%link href="https://console.catalyst.zoho.com" %}}Catalyst web console{{%/link%}} and the {{%link href="/en/cli/v1/cli-command-reference/" %}}Catalyst Command Line Interface{{%/link%}} (CLI) to build this application. {{%info%}}{{%bold%}}Info:{{%/bold%}} You will be given the code for the files to be included in the function and client components in this tutorial. You will just need to copy the provided code and paste it into the appropriate files as directed.{{%/info%}} ### Application Architecture The Lead Manager application’s architecture is depicted below: <br /> The entire workflow of the application will be explained in more detail when you {{%link href="/en/tutorials/leadmanager-appsail/express/frontend-code" %}}code your front end logic{{%/link%}}, which we recommend you check out as you follow along the steps. -------------------------------------------------------------------------------- title: "Prerequisites" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.683Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/express/prerequisites/" service: "All Services" related: - Catalyst Tools VS Code Plugin (/en/catalyst-extensions/vs-code-extension/introduction/) -------------------------------------------------------------------------------- # Prerequisites Before you begin building the application, you must have the following prerequisites installed on your system: 1. **Catalyst CLI**: Catalyst CLI contains a host of tools that enable you to initialize, develop, test, and deploy the components of your application from your local machine. We will be working with Catalyst CLI in this tutorial. You must perform these actions: - {{%bold%}}Install Catalyst CLI{{%/bold%}}: Catalyst CLI is installed through NPM. You must therefore have NPM and Node.js installed on your system before you install the CLI. Refer to the {{%link href="/en/getting-started/installing-catalyst-cli/" %}}{{%bold%}}Install Catalyst CLI help page{{%/bold%}}{{%/link%}} for details on the pre-requisites and the steps to install it. - {{%bold%}}Login Catalyst CLI{{%/bold%}}: After you install Catalyst CLI, you must authenticate the CLI with your Catalyst account before using it. Refer to the {{%link href="/en/cli/v1/login/login-from-cli/" %}}{{%bold%}}CLI Login help page{{%/bold%}}{{%/link%}} for the steps to login from Catalyst CLI and the various options available for it. 2. **Zoho CRM Account**: Because the Leads module is available in all editions of Zoho CRM, you can have a configured Zoho CRM account of any edition to establish a connection with the Lead Manager application. If you don’t have a Zoho CRM account, you can sign up for it {{%link href="https://www.zoho.com/in/crm/" %}}here{{%/link%}}. 3. **Any IDE tool for Node.js and client code development**: You can use any IDE to work with the function and the client code. Some popular choices include Visual Studio Code, IntelliJ IDEA, Eclipse, and Sublime Text. Download and install an IDE of your choice in your system. {{%info image="/images/tutorials/todo-list/vscode.png"%}}If you are a Visual Studio Code IDE user, you can install the {{%bold%}}Catalyst Tools{{%/bold%}} extension, and use your IDE itself in place of the CLI. You can find more details about the Catalyst VS Code extension from this {{%link href="/en/catalyst-extensions/vs-code-extension/introduction/" %}}help section{{%/link%}}.{{%/info%}} -------------------------------------------------------------------------------- title: "Create a Project" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.683Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/express/create-project/" service: "All Services" related: - Project Directory Structure (/en/cli/v1/project-directory-structure/introduction/) - Catalyst SDK for AppSail (/en/serverless/help/appsail/key-concepts/catalyst-configurations/#implementing-catalyst-sdk-in-appsail/) -------------------------------------------------------------------------------- # Create a Project Let’s {{%link href="/en/getting-started/catalyst-projects/#creating-a-catalyst-project" %}}create a Catalyst project{{%/link%}} from the Catalyst console. 1. Log in to the {{%link href="https://console.catalyst.zoho.com/baas/index" %}}Catalyst console{{%/link%}} and click **Create New Project**. <br /> 2. Enter the project’s name as "**LeadManager**" in the pop-up window. <br /> Your project will be created. You can open the project by clicking **Access Project**. <br /> -------------------------------------------------------------------------------- title: "Create a Table" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.683Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/express/create-table/" service: "All Services" related: - Data Store (/en/cloud-scale/help/data-store/introduction/) - ZCQL (/en/cloud-scale/help/zcql/introduction) -------------------------------------------------------------------------------- # Create a Table Next, let’s create a table in the **Data Store**. This table is used to store the *Refresh Token* and {{%badge%}}userID{{%/badge%}} values, which are retrieved whenever an *Access Token* needs to be generated. To create a table: 1. Navigate to the {{%link href="/en/cloud-scale/" %}}Catalyst Cloud Scale{{%/link%}} service section in the console and click **Start Exploring**. <br /> 2. Click **Create a new Table**. <br /> 3. Enter the table’s name as "{{%badge%}}Token{{%/badge%}}" and click **Create**. <br /> {{%note%}}{{%bold%}}Note:{{%/bold%}} Ensure that you enter the name exactly as instructed because the application's code contains the same name.{{%/note%}} The table will be created. <br /> Now, let’s create two columns in the table to store the {{%badge%}}userID{{%/badge%}} and the {{%badge%}}refresh token{{%/badge%}} respectively. {{%info%}}{{%bold%}}Info:{{%/bold%}} You can learn about the various data types supported by Catalyst and the other properties of a column from the {{%link href="/en/cloud-scale/help/data-store/introduction/" %}}Data Store help documentation{{%/link%}}.{{%/info%}} 4. Click **New Column** in the *Schema View* section. <br /> 5. Enter the column’s name as "refresh_token". Select the data type as Encrypted Text. <br /> 6. Click **Create**. <br /> 7. Now click the **New Column** button again to create the second column. Name it "{{%badge%}}userId{{%/badge%}}", and select **BigInt** as its data type. <br /> 8. Click **Create**. <br /> The required columns have been created. ### Configure Scopes and Permissions To allow any user of the Lead Manager application to view or manage leads from the client application, you must enable an additional {{%link href="/en/cloud-scale/help/data-store/scopes-and-permissions" %}}table permission{{%/link%}} that will allow the user to fetch and store new *Refresh Tokens*, if needed. To enable the required permissions: 1. Click the **Scopes and Permissions** tab. <br /> 2. Enable the **Insert** permission for the **App User** role under the *Table Permissions* section. Ensure you do not change any other permission setting. <br /> The Data Store component is now configured for the application. -------------------------------------------------------------------------------- title: "Enable Zoho Social Login" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.683Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/express/enable-auth/" service: "All Services" related: - Authentication (/en/cloud-scale/help/authentication/introduction/) - Embedded Authentication (/en/cloud-scale/help/authentication/native-catalyst-authentication/embedded-authentication/introduction/) - Enable Social Login (/en/cloud-scale/help/authentication/social-logins/configuring-social-logins/) - Public Sign Up (/en/cloud-scale/help/authentication/public-signup/) -------------------------------------------------------------------------------- # Enable Zoho Social Login Using Embedded Authentication The Lead Manager application contains a login page where you must provide valid credentials to access your Zoho CRM account. You need to implement a signup functionality for this application. The functionality should also provide the option to login to the account using {{%link href="/en/cloud-scale/help/authentication/social-logins/configuring-social-logins/#enable-zoho-social-login" %}}Zoho Social Logins{{%/link%}}. We will be implementing the {{%link href="/en/cloud-scale/help/authentication/native-catalyst-authentication/embedded-authentication/introduction/" %}}Embedded Authentication type{{%/link%}} to complete this requirement. To configure the Zoho social login for the Lead Manager application from the console: 1. Navigate to the **Authentication** component under the *Security & Identity* section, and click **Setup** in the **Native Catalyst Authentication** tab. <br /> 2. Select **Embedded Authentication**, and click **Next**. <br /> 3. You can copy and use the scripts provided in the **Configuration** step to setup your login functionality. However, since we are only going to be using *Zoho social login*, you need to enable the **Public Signup toggle** first. <br /> 4. Click **Yes, Proceed** in the dialog box after going through it. <br /> 5. Click the **Zoho** button to enable the social login. <br /> 6. Provide "{{%badge%}}LeadManagerApp{{%/badge%}}" as the *Client Name* and click **Enable**. <br /> 7. Click **Next**. <br /> 8. We will not be configuring any additional authentication settings for our application. Click **Finish**. <br /> **Embedded Authentication** has been enabled for the application, and users can now login to the app using the **Zoho social login**. <br /> -------------------------------------------------------------------------------- title: "Initialize the Project" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.684Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/express/init-project/" service: "All Services" related: - Catalyst CLI (/en/cli/v1/cli-command-reference/) - Initialize Resources (/en/cli/v1/initialize-resources/introduction/) - Catalyst AppSail Help (/en/serverless/help/appsail/introduction/) - Project Directory (/en/cli/v1/project-directory-structure/introduction/) -------------------------------------------------------------------------------- # Initialize the Project You can now begin working on your Catalyst project from the CLI. The first step is to initialize the project in an empty directory. This will be the home directory of your project, and all of the project files will be saved in it. You can learn more about this from the {{%link href="/en/cli/v1/project-directory-structure/introduction/" %}}Project Directory Structure help page{{%/link%}}. You can learn about initializing a project in detail from the {{%link href="/en/cli/v1/initialize-resources/introduction/" %}}CLI help documentation{{%/link%}}. For this application, you will be initializing the {{%link href="/en/serverless/help/appsail/introduction/" %}}AppSail{{%/link%}} component alone. The *AppSail* component will be initialized in the **Node.js** programming stack. 1. Create a folder for the project on your local machine and navigate to it from the terminal. 2. Initialize a project by executing the following command from that directory: {{%cli%}}catalyst init{{%/cli%}} 3. Navigate using the **arrow keys** and select your preferred portal and click **Enter**. If you have no other organizations associated with the account, then the default will be selected automatically. <br /> {{%info%}}{{%bold%}}Info:{{%/bold%}} You can find out more about Catalyst’s multi-org portal feature in this {{%link href="/en/getting-started/catalyst-organizations/#access-the-multi-org-portal" %}}help document{{%/link%}}.{{%/info%}} 4. The CLI will now ask you to associate a Catalyst project with the directory. Associate it with the project that we created earlier from the console. Select **LeadManager** from the list and click **Enter**. <br /> 5. Select **AppSail** using the space bar, then click **Enter** to initialize. <br /> 6. The CLI will prompt you to choose between {{%link href="/en/serverless/help/appsail/catalyst-managed-runtimes/key-concepts/" %}}Catalyst-Managed Runtime{{%/link%}} and {{%link href="/en/serverless/help/appsail/custom-runtimes/container-registry-services/" %}}Docker Image{{%/link%}}. Because you are creating this project from one of the Catalyst-Managed Runtime, select **Catalyst-Managed Runtime** and click **Enter**. <br/> 7. The CLI will initiate the *AppSail* service. - As you are creating your own project, enter "{{%badge%}}n{{%/badge%}}" and click **Enter** for the prompt asking if you wish to get started with a list of recommended projects. <br /> - Enter "{{%badge%}}Y{{%/badge%}}" in the prompt to initialize the *AppSail* service in your current directory. <br /> 8. Enter "{{%badge%}}LeadManagerApp{{%/badge%}}" as the name of your AppSail service, and enter your project directory path as the build path of your AppSail service. <br /> 9. Choose the latest runtime of **Node.js** as the programming stack, and click **Enter**. <br /> The AppSail service has been initialized for your Lead Manager application <br /> The directory will be created in the standard structure, and it will contain the {{%link href="/en/serverless/help/appsail/key-concepts/catalyst-configurations/#the-app-configjson-file" %}}{{%badge%}}app-config.json{{%/badge%}}{{%/link%}} file which includes the configuration of your AppSail service , along with the standard project configuration files such as the {{%link href="/en/cli/v1/project-directory-structure/catalyst-json/" %}}{{%badge%}}catalyst.json file{{%/badge%}}{{%/link%}} and a hidden {{%badge%}}.catalystrc{{%/badge%}} file. This is the structure of the **LeadManager** project’s directory initialized with the AppSail service. <br /> ### Deploy the Application You need to deploy the application to the console to fetch the required **application URL**. We need this URL when we register the client in the {{%link href="https://api-console.zoho.com/" %}}Zoho API console{{%/link%}} to get the required {{%badge%}}Client ID{{%/badge%}} and {{%badge%}}Client Secret{{%/badge%}} values. {{%info%}}{{%bold%}}Info:{{%/bold%}} We will be re-deploying the application service once we have completed coding and adding the {{%badge%}}Client ID{{%/badge%}} and {{%badge%}}Client Secret{{%/badge%}} values to the application.{{%/info%}} <br> Enter the following CLI command to deploy the application: {{%cli%}}catalyst deploy{{%/cli%}} Now, to acquire the application URL: 1. Navigate to the {{%link href="/en/serverless/help/appsail/introduction/" %}}AppSail{{%/link%}} component present under the *COMPUTE* section of the **Catalyst Serverless** section of the console. <br /> You will be able to view that your application has been deployed as an AppSail service. 2. Now click your AppSail service, and you will be able to view the application URL. <br /> {{%info%}}{{%bold%}}Info:{{%/bold%}} We will discuss more about the {{%badge%}}catalyst deploy{{%/badge%}} CLI command and the AppSail service, after we re-deploy the application, towards the end of the tutorial.{{%/info%}} -------------------------------------------------------------------------------- title: "Register the Client" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.685Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/express/register-client/" service: "All Services" related: - Catalyst Authentication (/en/cloud-scale/help/authentication/introduction/) - Social Logins (/en/cloud-scale/help/authentication/social-logins/introduction/) -------------------------------------------------------------------------------- # Register the Client We must now register the client application in the {{%link href="https://api-console.zoho.com/" %}}Zoho API console{{%/link%}} to generate the following credentials: - {{%badge%}}**Client ID**{{%/badge%}}: The unique key generated for a registered client - {{%badge%}}**Client Secret**{{%/badge%}}: The secret value generated for a registered client’s {{%badge%}}Client ID{{%/badge%}} The {{%badge%}}Client ID{{%/badge%}} and {{%badge%}}Client Secret{{%/badge%}} are added to the backend and frontend code in several places. These values are necessary to generate the {{%badge%}}{{%bold%}}Access Token{{%/bold%}}{{%/badge%}} and {{%badge%}}{{%bold%}}Refresh Token{{%/bold%}}{{%/badge%}} initially, and later to refresh the {{%badge%}}{{%bold%}}Access Token{{%/bold%}}{{%/badge%}} using the {{%badge%}}{{%bold%}}Refresh Token{{%/bold%}}{{%/badge%}}. To register the client application in the Zoho API console: 1. Visit the {{%link href="https://api-console.zoho.com/" %}}Zoho API Console{{%/link%}} and click **Get Started**. <br /> 2. Select **Server-based Applications** as the client type. <br /> 3. Enter "{{%badge%}}LeadManagerApp"{{%/badge%}} as the **Client Name**. <br /> 4. Provide the other details in the following format: - Homepage URL: **AppSail application URL** - Authorized Redirect URIs: **AppSail applicationURL/generateToken** <br /> Replace {**AppSail applicationURL**} with the application URL you acquired when you deployed your project earlier in this {{%link href="/en/tutorials/leadmanager-appsail/express/init-project/#deploy-the-application" %}}step{{%/link%}}. 5. You will need to add another **Authorized Redirect URI** for the client. We will serve the app through a **localhost** to test it after configuring the code. Because this will be redirected to a local domain, we must add that as another authorized redirect URI. <br /> {{%info%}}{{%bold%}}Info:{{%/bold%}} When you serve an application locally from the CLI, it is hosted from {{%badge%}}port 3000{{%/badge%}} by default, unless the port is otherwise occupied. So ensure you are adding the domain accordingly.{{%/info%}} 6. Click **Create**. <br /> The API console will generate and display the {{%badge%}}Client ID{{%/badge%}} and {{%badge%}}Client Secret{{%/badge%}} values for the registered client. You will need to copy these values and paste them into the frontend and backend code of your application. We will discuss this in the following sections. -------------------------------------------------------------------------------- title: "Install the Dependencies" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.685Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/express/init-dependencies/" service: "All Services" related: - Node SDK (/en/sdk/nodejs/v2/overview/) -------------------------------------------------------------------------------- # Initialize and Install the Required Dependencies To run the application on a Node.js Express framework, let’s initialize the {{%badge%}}Catalyst Node.js SDK{{%/badge%}}, Node modules, {{%badge%}}Axios{{%/badge%}} and {{%badge%}}Express{{%/badge%}} package for your application. Enter the following command in your CLI in your project directory {{%badge%}}/LeadManager{{%/badge%}} to initialize the Node modules: {{%cli%}}npm init{{%/badge%}} * Enter "{{%badge%}}leadmanagerapp{{%/badge%}}" as the package name, and "{{%badge%}}index.js{{%/badge%}}" as the entry point. You can also just click **Enter** to use the default names generated by NPM, or enter any name of your preference. <br /> * Click **Enter** for the rest of the prompts, and complete the initialization. Your preferences will be stored in a {{%link href="" %}}{{%badge%}}package.json file{{%/badge%}}{{%/link%}}. You can review your options in the terminal and confirm your preferences by entering "**yes**". <br /> * Create a new file in your project directory and name it "{{%badge%}}index.js{{%/badge%}}" If you have provided a different name for your entry point, ensure you provide the same name here. ### Install Express Now, let's install the {{%badge%}}**Express**{{%/badge%}} package in your project’s root folder using the following command: {{%cli%}}npm install express{{%/cli%}} <br /> ### Install Axios Now, let's install the {{%badge%}}**Axios**{{%/badge%}} package in your project’s root folder using the following command: {{%cli%}}npm install axios{{%/cli%}} <br /> ### Install Catalyst Node.js SDK We will utilize Catalyst components in this app. To use them, you will also need to install the {{%link href="/en/sdk/nodejs/v2/overview/" %}}Catalyst Node.js SDK{{%/link%}} package in your project’s root folder using the following CLI command: {{%cli%}}npm install zcatalyst-sdk-node{{%/cli%}} <br /> Now your directory will contain the {{%badge%}}node_modules{{%/badge%}} folder, the {{%badge%}}package.json{{%/badge%}}, {{%badge%}}package-lock.json{{%/badge%}}, and the {{%badge%}}index.js{{%/badge%}} file, in addition to the existing files. <br /> -------------------------------------------------------------------------------- title: "Code Your Backend Logic" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.685Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/express/backend-code/" service: "All Services" related: - Node SDK (/en/sdk/nodejs/v2/overview/) -------------------------------------------------------------------------------- # Code Your Backend Logic You have created the "{{%badge%}}index.js{{%/badge%}}" file in your project’s root directory, and this will contain the backend logic of your application. {{%note%}}{{%bold%}}Note:{{%/bold%}} Please go through the code in this section to make sure you fully understand it.{{%/note%}} Copy the code below and paste it into the respective files of your project using an IDE and save the files. {{%panel_with_adjustment class="language-javascript line-numbers" header="index.js" footer="button" scroll="set-scroll" %}}const catalyst = require('zcatalyst-sdk-node'); const express = require('express'); const axios = require('axios'); const http = require('https') const app = express() app.use(express.static('public')); app.use(express.json()); const HOST = "www.zohoapis.com"; const AUTH_HOST = "https://accounts.zoho.com/oauth/v2/token"; const PORT = 443; const CLIENTID = ''; //Add your client ID const CLIENT_SECRET = ''; //Add your client secret app.get("/generateToken", async (req, res) => { try { console.log("Entered generated token") const catalystApp = catalyst.initialize(req); const code = req.query.code; const domain = &#96;${process.env.X_ZOHO_CATALYST_IS_LOCAL === 'true' ? "http" : "https"}://${process.env.X_ZOHO_CATALYST_IS_LOCAL === 'true' ? req.headers.host : req.headers.host.split(':')[0]}&#96; let userManagement = catalystApp.userManagement(); const refresh_token = await getRefreshToken(code, res, domain); let userDetails = await userManagement.getCurrentUser(); const catalystTable = catalystApp.datastore().table("Token"); const userId = userDetails.user_id; await catalystTable.insertRow({ refresh_token, userId, }); res.status(200).redirect(&#96;${domain}/index.html&#96;); } catch (err) { console.error(err); res .status(500) .send({ message: "Internal Server Error. Please try again after sometime.", error: err, }); } }); app.get("/getUserDetails", async (req, res) => { try{ const catalystApp = catalyst.initialize(req); const userDetails = await getUserDetails(catalystApp); if (userDetails.length !== 0) { console.log("user present") res.status(200).send({ userId: userDetails[0].Token.userId }); } else { console.log("User not present") console res.status(200).send({ userId: null }); } } catch (err) { console.error(err); res .status(500) .send({ message: "Internal Server Error in Getting User Details. Please try again after sometime.", error: err }); } }); app.get("/crmData", async (req, res) => { try { const catalystApp = catalyst.initialize(req); const userDetails = await getUserDetails(catalystApp); const accessToken = await getAccessToken(catalystApp, userDetails); const options = { hostname: HOST, port: PORT, method: "GET", path: &#96;/crm/v2/Leads&#96;, headers: { Authorization: &#96;Zoho-oauthtoken ${accessToken}&#96;, }, }; var data = ""; const request = http.request(options, function (response) { response.on("data", function (chunk) { data += chunk; }); response.on("end", function () { res.setHeader("content-type", "application/json"); res.status(200).send(data); }); }); request.end(); } catch (err) { console.error(err); res .status(500) .send({ message: "Internal Server Error. Please try again after sometime.", }); } }); app.get("/crmData/:id", async (req, res) => { try { const catalystApp = catalyst.initialize(req); const userDetails = await getUserDetails(catalystApp); const accessToken = await getAccessToken(catalystApp, userDetails); const options = { hostname: HOST, port: PORT, method: "GET", path: &#96;/crm/v2/Leads/${req.params.id}&#96;, headers: { Authorization: &#96;Zoho-oauthtoken ${accessToken}&#96;, }, }; var data = ""; const request = http.request(options, function (response) { response.on("data", function (chunk) { data += chunk; }); response.on("end", function () { res.setHeader("content-type", "application/json"); res.status(200).send(data); }); }); request.end(); } catch (err) { console.error(err); res.status(500).send({ message: "Internal Server Error. Please try again after sometime.", }); } }); app.post("/crmData", async (req, res) => { try { const catalystApp = catalyst.initialize(req); const createData = req.body; const reqData = []; reqData.push(createData); const data = { data: reqData, }; if (!createData) { res.status(400).send({ message: "Data Not Found" }); } const userDetails = await getUserDetails(catalystApp); const accessToken = await getAccessToken(catalystApp, userDetails); const options = { hostname: HOST, port: PORT, method: "POST", path: &#96;/crm/v2/Leads&#96;, headers: { Authorization: &#96;Zoho-oauthtoken ${accessToken}&#96;, "Content-Type": "application/json", }, }; const request = http.request(options, function (response) { res.setHeader("content-type", "application/json"); let responseData = ''; response.on('data', (chunk) => { responseData += chunk; }); response.on('end', () => { console.log('Response from the external request:', responseData); }); response.pipe(res); }); request.write(JSON.stringify(data)); request.end(); } catch (err) { console.error(err); res.status(500).send({ message: "Internal Server Error. Please try again after sometime.", }); } }); app.put("/crmData/:id", async (req, res) => { try { const catalystApp = catalyst.initialize(req); const updateData = req.body; const reqData = []; reqData.push(updateData); const data = { data: reqData, }; if (!updateData) { res.status(400).send({ message: "Update Data Not Found" }); } const userDetails = await getUserDetails(catalystApp); const accessToken = await getAccessToken(catalystApp, userDetails); const options = { hostname: HOST, port: PORT, method: "PUT", path: &#96;/crm/v2/Leads/${req.params.id}&#96;, headers: { Authorization: &#96;Zoho-oauthtoken ${accessToken}&#96;, "Content-Type": "application/json", }, }; const request = http.request(options, function (response) { res.setHeader("content-type", "application/json"); response.pipe(res); }); request.write(JSON.stringify(data)); request.end(); } catch (err) { console.error(err); res.status(500).send({ message: "Internal Server Error. Please try again after sometime.", }); } }); app.delete("/crmData/:id", async (req, res) => { try { const catalystApp = catalyst.initialize(req); const userDetails = await getUserDetails(catalystApp); const accessToken = await getAccessToken(catalystApp, userDetails); const options = { hostname: HOST, port: PORT, method: "DELETE", path: &#96;/crm/v2/Leads/${req.params.id}&#96;, headers: { Authorization: &#96;Zoho-oauthtoken ${accessToken}&#96;, "Content-Type": "application/json", }, }; const request = http.request(options, function (response) { res.setHeader("content-type", "application/json"); response.pipe(res); }); request.end(); } catch (err) { console.error(err); res.status(500).send({ message: "Internal Server Error. Please try again after sometime.", }); } }); app.get("/getAccessToken",async (req, res)=>{ try{ const catalystApp = catalyst.initialize(req); const userDetails = await getUserDetails(catalystApp); const access_token = await getAccessToken(catalystApp, userDetails) res.send(access_token) } catch(err){ console.error(err); } }) async function getAccessToken(catalystApp, userDetails) { const refresh_token = userDetails[0].Token.refresh_token; const userId = userDetails[0].Token.userId; const credentials = { [userId]: { client_id: CLIENTID, client_secret: CLIENT_SECRET, auth_url: AUTH_HOST, refresh_url: AUTH_HOST, refresh_token, }, }; const accessToken = await catalystApp.connection(credentials).getConnector(userId).getAccessToken(); return accessToken; } async function getRefreshToken(code, res, domain) { try { const url = &#96;${AUTH_HOST}?code=${code}&client_id=${CLIENTID}&client_secret=${CLIENT_SECRET}&grant_type=authorization_code&redirect_uri=${domain}/generateToken&#96;; const response = await axios({ method: "POST", url }); console.log(response.data.refresh_token) return response.data.refresh_token; } catch (err) { console.log(err); res.status(500).send({ message: "Internal Server Error. Please try again after sometime.", error: err, }); } } async function getUserDetails(catalystApp) { let userDetails = await catalystApp.userManagement().getCurrentUser(); let userDetail = await catalystApp.zcql().executeZCQLQuery(&#96;SELECT * FROM Token where UserId=${userDetails.user_id}&#96;); return userDetail; } app.listen(process.env.X_ZOHO_CATALYST_LISTEN_PORT || 9000,()=>{ console.log(&#96;Listening from port ${process.env.X_ZOHO_CATALYST_LISTEN_PORT}!!!&#96;) }) module.exports = app; {{%/panel_with_adjustment%}} {{%note%}}{{%bold%}}Note:{{%/bold%}} Add the {{%badge%}}Client ID{{%/badge%}} and {{%badge%}}Client Secret{{%/badge%}} values obtained after you registered the client in the Zoho API console to the {{%bold%}}11th{{%/bold%}} and {{%bold%}}12th{{%/bold%}} line of code in the {{%badge%}}index.js{{%/badge%}} file.{{%/note%}} -------------------------------------------------------------------------------- title: "Code Your Frontend Logic" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.686Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/express/frontend-code/" service: "All Services" related: - Web SDK for Authentication (/en/sdk/web/v4/cloud-scale/authentication/get-auth-instance/) -------------------------------------------------------------------------------- # Code Your Frontend Logic Create a folder in your project’s root directory and name it "{{%badge%}}**public**{{%/badge%}}." This folder will contain the files for your front-end logic. Create the following files inside your {{%badge%}}public{{%/badge%}} folder ({{%badge%}}LeadManager/public/{{%/badge%}}): - {{%badge%}}**index.html**{{%/badge%}}: Will contain the HTML code for the front-end of the application. - {{%badge%}}**login.html**{{%/badge%}}: Will contain the HTML code for the {{%link href="/en/cloud-scale/help/authentication/native-catalyst-authentication/embedded-authentication/introduction/" %}}Embedded Authentication{{%/link%}} logic. - {{%badge%}}**main.js**{{%/badge%}}: Will contain the JavaScript code that connects the front-end and backend. - {{%badge%}}**main.css**{{%/badge%}}: Will contain the styling of the application This is the final folder structure of the LeadManager project. <br /> You will be coding the {{%badge%}}index.html{{%/badge%}}, {{%badge%}}login.html{{%/badge%}}, and {{%badge%}}main.js{{%/badge%}} files. You will also be updating the {{%badge%}}app-config.json{{%/badge%}} file. {{%note%}}{{%bold%}}Note:{{%/bold%}} Please go through the code in this section to make sure you fully understand it.{{%/note%}} Copy the code below and paste it into the respective files of your project using an IDE and save the files. {{%panel_with_adjustment class="language-xml line-numbers" header="index.html" footer="button" scroll="set-scroll" %}}&lt;!DOCTYPE html&gt; &lt;html&gt; &lt;head&gt; &lt;meta charset="utf-8" /&gt; &lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&gt; &lt;title&gt;CRM Lead Manager&lt;/title&gt; &lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt; &lt;link rel="stylesheet" type="text/css" media="screen" href="main.css" /&gt; &lt;link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"&gt; &lt;link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet"&gt; &lt;link href="https://cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.19.1/css/mdb.min.css" rel="stylesheet"&gt; &lt;script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"&gt; &lt;/script&gt; &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"&gt; &lt;/script&gt; &lt;script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"&gt; &lt;/script&gt; &lt;script src="main.js"&gt; &lt;/script&gt; &lt;script src="https://static.zohocdn.com/catalyst/sdk/js/4.4.0/catalystWebSDK.js"&gt; &lt;/script&gt; &lt;script src="/__catalyst/sdk/init.js"&gt; &lt;/script&gt; &lt;link href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"&gt; &lt;style&gt; #connect { height: 260px; width: 500px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; margin: auto; } &lt;/style&gt; &lt;/head&gt; &lt;body onload="getUserDetails()"&gt; &lt;br&gt; &lt;center&gt; &lt;h1&gt;CRM Lead Manager&lt;/h1&gt; &lt;br&gt; &lt;/center&gt; &lt;div id="connect"&gt; &lt;center&gt; &lt;p&gt;Click here to connect to Zoho CRM&lt;/p&gt; &lt;button onclick='navigate()'&gt; &lt;img src="https://www.zohowebstatic.com/sites/default/files/styles/product-home-page/public/icon-crm_blue.png" style="width: 180px;height: 130px;"&gt; &lt;/button&gt; &lt;/center&gt; &lt;/div&gt; &lt;div style="width: 200px;float: right; margin-right: 30px;"&gt; &lt;label for="logoutbtn" class="btn btn-success btn-block btn-outlined"&gt;Logout&lt;/label&gt; &lt;button id="logoutbtn" onclick="logout()" style="display: none;"&gt; &lt;/button&gt; &lt;/div&gt; &lt;div id="main"&gt; &lt;div class="container"&gt; &lt;ul class="nav nav-tabs nav-justified mb-3" id="myTab" role="tablist"&gt; &lt;li class="nav-item"&gt; &lt;a class="nav-link active" id="check-tab" data-toggle="tab" href="#check" role="tab" aria-controls="check" aria-selected="true"&gt;Add a Lead&lt;/a&gt; &lt;/li&gt; &lt;li class="nav-item"&gt; &lt;a class="nav-link" id="report-tab" data-toggle="tab" href="#report" onclick="getLeads()" role="tab" aria-controls="report" aria-selected="false"&gt;Manage Leads&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt; &lt;br&gt; &lt;div class="tab-content" id="myTabContent"&gt; &lt;div class="tab-pane fade show active" id="check" role="tabpanel" aria-labelledby="check-tab"&gt; &lt;div class="tab-pane fade show active" id="ex3-tabs-1" role="tabpanel" aria-labelledby="ex3-tab-1"&gt; &lt;div style="margin-left: 100px; margin-right:100px;"&gt; &lt;form id="leads"&gt; &lt;!-- 2 column grid layout with text inputs for the first and last names --&gt; &lt;div class="row mb-4"&gt; &lt;div class="col"&gt; &lt;div class="form-outline"&gt; &lt;label class="form-label" for="form6Example1"&gt;First name&lt;/label&gt; &lt;input type="text" id="firstName" class="form-control" /&gt; &lt;/div&gt; &lt;/div&gt; &lt;div class="col"&gt; &lt;div class="form-outline"&gt; &lt;label class="form-label" for="form6Example2"&gt;Last name&lt;/label&gt; &lt;input type="text" id="lastName" class="form-control" required /&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;!-- Text input --&gt; &lt;div class="form-outline mb-4"&gt; &lt;label class="form-label" for="form6Example3"&gt;Company name&lt;/label&gt; &lt;input type="text" id="companyName" class="form-control" /&gt; &lt;/div&gt; &lt;!-- Email input --&gt; &lt;div class="form-outline mb-4"&gt; &lt;label class="form-label" for="form6Example5"&gt;Email&lt;/label&gt; &lt;input type="email" id="email" class="form-control" /&gt; &lt;/div&gt; &lt;!-- Text input --&gt; &lt;div class="form-outline mb-4"&gt; &lt;label class="form-label" for="form6Example4"&gt;State&lt;/label&gt; &lt;input type="text" id="state" class="form-control" /&gt; &lt;/div&gt; &lt;!-- Number input --&gt; &lt;div class="form-outline mb-4"&gt; &lt;label class="form-label" for="form6Example6"&gt;Phone&lt;/label&gt; &lt;input type="number" id="phone" class="form-control" /&gt; &lt;/div&gt; &lt;!-- Number input --&gt; &lt;div class="form-outline mb-4"&gt; &lt;label class="form-label" for="form6Example6"&gt;Lead Source&lt;/label&gt; &lt;input type="text" id="leadSource" class="form-control" /&gt; &lt;/div&gt; &lt;!-- Submit button --&gt; &lt;center&gt; &lt;button type="submit" onclick="createLead();return false;" class="btn btn-primary btn-block mb-4" style="width: 100px;"&gt;Add Lead&lt;/button&gt; &lt;div id="loader" style="display: none;"&gt; &lt;div class="spinner-border" role="status"&gt; &lt;span class="sr-only"&gt;Loading...&lt;/span&gt; &lt;/div&gt; &lt;/div&gt; &lt;/center&gt; &lt;/form&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;div class="tab-pane fade" id="report" role="tabpanel" aria-labelledby="report-tab"&gt; &lt;center&gt; &lt;div id="loaders" style="display: none; padding-top: 200px;"&gt; &lt;div class="spinner-border" role="status"&gt; &lt;span class="sr-only"&gt;Loading...&lt;/span&gt; &lt;/div&gt; &lt;/div&gt; &lt;/center&gt; &lt;p id="showData"&gt; &lt;/p&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;!-- Modal --&gt; &lt;div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"&gt; &lt;div class="vertical-alignment-helper"&gt; &lt;div class="modal-dialog vertical-align-center"&gt; &lt;div class="modal-content"&gt; &lt;center&gt; &lt;h4 class="modal-title" id="myModalLabel"&gt; &lt;/h4&gt; &lt;div class="modal-body" id="message"&gt; &lt;/div&gt; &lt;div class="modal-footer"&gt; &lt;button type="button" style="background-color: #007bff;color: white;" class="btn btn-default" data-dismiss="modal"&gt;Close&lt;/button&gt; &lt;/div&gt; &lt;/center&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;div class="modal fade" id="editForm" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"&gt; &lt;div class="vertical-alignment-helper"&gt; &lt;div class="modal-dialog vertical-align-center"&gt; &lt;div class="modal-content"&gt; &lt;div style="margin-left: 80px; margin-right:80px;"&gt; &lt;br&gt; &lt;center&gt; &lt;h2&gt;Edit Lead&lt;/h2&gt; &lt;/center&gt; &lt;br&gt; &lt;form id="editLeads"&gt; &lt;!-- 2 column grid layout with text inputs for the first and last names --&gt; &lt;div class="row mb-4"&gt; &lt;div class="col"&gt; &lt;div class="form-outline"&gt; &lt;label class="form-label" for="form6Example1"&gt;First name&lt;/label&gt; &lt;input type="text" id="editfirstName" class="form-control" /&gt; &lt;/div&gt; &lt;/div&gt; &lt;div class="col"&gt; &lt;div class="form-outline"&gt; &lt;label class="form-label" for="form6Example2"&gt;Last name&lt;/label&gt; &lt;input type="text" id="editlastName" class="form-control" required /&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;!-- Text input --&gt; &lt;div class="form-outline mb-4"&gt; &lt;label class="form-label" for="form6Example3"&gt;Company name&lt;/label&gt; &lt;input type="text" id="editcompanyName" class="form-control" /&gt; &lt;/div&gt; &lt;!-- Email input --&gt; &lt;div class="form-outline mb-4"&gt; &lt;label class="form-label" for="form6Example5"&gt;Email&lt;/label&gt; &lt;input type="email" id="editemail" class="form-control" /&gt; &lt;/div&gt; &lt;!-- Text input --&gt; &lt;div class="form-outline mb-4"&gt; &lt;label class="form-label" for="form6Example4"&gt;State&lt;/label&gt; &lt;input type="text" id="editstate" class="form-control" /&gt; &lt;/div&gt; &lt;!-- Number input --&gt; &lt;div class="form-outline mb-4"&gt; &lt;label class="form-label" for="form6Example6"&gt;Phone&lt;/label&gt; &lt;input type="number" id="editphone" class="form-control" /&gt; &lt;/div&gt; &lt;!-- Submit button --&gt; &lt;center&gt; &lt;button type="submit" id="editBtn" onclick="editLead();return false;" class="btn btn-primary btn-block mb-4" style="width: 100px;"&gt;Edit&lt;/button&gt; &lt;div id="loader" style="display: none;"&gt; &lt;div class="spinner-border" role="status"&gt; &lt;span class="sr-only"&gt;Loading...&lt;/span&gt; &lt;/div&gt; &lt;/div&gt; &lt;/center&gt; &lt;/form&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;div class="modal fade right" id="ModalDanger" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"&gt; &lt;div class="modal-dialog modal-notify modal-danger modal-side modal-top-right" role="document"&gt; &lt;!--Content--&gt; &lt;div class="modal-content"&gt; &lt;!--Header--&gt; &lt;div class="modal-header"&gt; &lt;p class="heading"&gt;Lead Deletion&lt;/p&gt; &lt;button type="button" class="close" data-dismiss="modal" aria-label="Close"&gt; &lt;span aria-hidden="true" class="white-text"&gt;×&lt;/span&gt; &lt;/button&gt; &lt;/div&gt; &lt;!--Body--&gt; &lt;div class="modal-body"&gt; &lt;div class="row"&gt; &lt;div class="col-9"&gt; &lt;p&gt;Are you sure you want to delete the Lead?&lt;/p&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;!--Footer--&gt; &lt;div class="modal-footer justify-content-center"&gt; &lt;a type="button" class="btn btn-danger" id="delete-btn" onclick="deleteLead()"&gt;Delete&lt;/a&gt; &lt;a type="button" class="btn btn-outline-danger waves-effect" data-dismiss="modal"&gt;Cancel&lt;/a&gt; &lt;/div&gt; &lt;/div&gt; &lt;!--/.Content--&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/body&gt; &lt;script&gt; //Add Your Client ID and Redirect URL here function navigate() { window.location.href = "https://accounts.zoho.com/oauth/v2/auth?scope=ZohoCRM.modules.ALL&client_id=&lt;&lt;client_id&gt;&gt;&response_type=code&access_type=offline&redirect_uri=" + location.protocol + '//' + location.host + "/generateToken"; } &lt;/script&gt; &lt;/html&gt; {{%/panel_with_adjustment%}} {{%note%}}{{%bold%}}Note:{{%/bold%}} Ensure you add the {{%badge%}}Client ID{{%/badge%}} you configured in line {{%bold%}}252{{%/bold%}}.{{%/note%}} {{%panel_with_adjustment class="language-xml line-numbers" header="login.html" footer="button" scroll="set-scroll" %}}&lt;html&gt; &lt;/html&gt; &lt;meta charset="utf-8" /&gt; &lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&gt; &lt;title&gt;CRM Lead Manager&lt;/title&gt; &lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt; &lt;link rel="stylesheet" type="text/css" media="screen" href="main.css" /&gt; &lt;script src="main.js"&gt; &lt;/script&gt; &lt;link rel="stylesheet" type="text/css" media="screen" href="main.css" /&gt; &lt;link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"&gt; &lt;script src="https://js.zohostatic.com/catalystclient/1.0.0/catalystWebSDK.js"&gt; &lt;/script&gt; &lt;script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"&gt; &lt;/script&gt; &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"&gt; &lt;/script&gt; &lt;script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"&gt; &lt;/script&gt; &lt;script src="https://static.zohocdn.com/catalyst/sdk/js/4.4.0/catalystWebSDK.js"&gt; &lt;/script&gt; &lt;script src="/__catalyst/sdk/init.js"&gt; &lt;/script&gt; &lt;script&gt; catalyst.auth.signIn("login"); &lt;/script&gt; &lt;link href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"&gt; &lt;style&gt; #login { height: 260px; width: 500px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; margin: auto; } &lt;/style&gt; &lt;body&gt; &lt;br&gt; &lt;center&gt; &lt;h1&gt;CRM Lead Manager&lt;/h1&gt; &lt;/center&gt; &lt;div id="login"&gt; &lt;/div&gt; &lt;/body&gt; &lt;/html&gt; {{%/panel_with_adjustment%}} {{%panel_with_adjustment class="language-javascript line-numbers" header="main.js" footer="button" scroll="set-scroll" %}}function createLead() { debugger; $("#loader").show(); var firstName = $("#firstName").val(); var lastName = $("#lastName").val(); if (lastName == "") { alert("Kindly Enter the Last Name"); $("#loader").hide(); return; } var companyName = $("#companyName").val(); var email = $("#email").val(); var state = $("#state").val(); var phone = $("#phone").val(); var leadSource = $("#leadSource").val(); $.ajax({ url: "/crmData", type: "post", contentType: "application/json", data: JSON.stringify({ "First_Name": firstName, "Last_Name": lastName, "Company": companyName, "Email": email, "State": state, "Phone": phone, "Lead_Source": leadSource, }), success: function(data) { debugger; $('#leads').trigger("reset"); $("#myModalLabel").html("Success"); $("#message").html("Lead Created Successfully"); $("#loader").hide(); $('#myModal').modal('show'); }, error: function(error) { $('#leads').trigger("reset"); $("#myModalLabel").html("Failure"); $("#message").html("Please try again after Sometime"); $("#loader").hide(); $('#myModal').modal('show'); } }); } function logout() { var redirectURL = "/login.html"; //Add your app domain var auth = catalyst.auth; auth.signOut(redirectURL); } function getUserDetails() { $("#main").hide(); $("#connect").hide(); catalyst.auth.isUserAuthenticated().then(result => { console.log(result) $("#loader").show(); $.ajax({ url: "/getUserDetails", type: "get", success: function(data) { $("#loader").hide(); if (data.userId) { $("#main").show(); $("#connect").hide(); } else { $("#connect").show(); $("#main").hide(); } }, error: function(error) { $("#myModalLabel").html("Failure"); $("#message").html("Please try again after Sometime"); $("#loader").hide(); $('#myModal').modal('show'); } }); }).catch(err => { document.body.innerHTML = 'You are not logged in. Please log in to continue. Redirecting you to the login page..'; setTimeout(function() { window.location.href = "login.html"; }, 3000); }); } function getLeads() { debugger; var tableContainer = document.getElementById("showData"); tableContainer.innerHTML = ""; $("#loaders").show(); $.ajax({ url: "/crmData", type: "get", success: function(data) { debugger; var reqData = getRequiredData(data.data); $("#loaders").hide(); renderTable(reqData); }, error: function(error) { $("#myModalLabel").html("Failure"); $("#message").html("Please try again after Sometime"); $("#loader").hide(); $('#myModal').modal('show'); } }); } function showDeletePopup(leadID) { $('#ModalDanger').modal('show'); var deleteBtn = document.getElementById("delete-btn"); deleteBtn.value = leadID; } function deleteLead() { var leadID = document.getElementById('delete-btn').value; $.ajax({ url: "/crmData/" + leadID, type: "delete", success: function(data) { debugger; $('#ModalDanger').modal('toggle'); $("#myModalLabel").html("Success"); $("#message").html("Lead Deleted Successfully"); $('#myModal').modal('show'); setTimeout(function() { location.reload(); }, 3000); }, error: function(error) { $("#myModalLabel").html("Failure"); $("#message").html("Please try again after Sometime"); $("#loader").hide(); $('#myModal').modal('show'); } }); } function showEditPopup(leadID) { $.ajax({ url: "/crmData/" + leadID, type: "get", success: function(data) { debugger; var respData = data.data; $('#editfirstName').val(respData[0].First_Name); $('#editlastName').val(respData[0].Last_Name); $('#editcompanyName').val(respData[0].Company); $('#editemail').val(respData[0].Email); $('#editstate').val(respData[0].State); $('#editphone').val(respData[0].Phone); $('#editleadSource').val(respData[0].Lead_Source); $('#editBtn').val(respData[0].id); $('#editfirstName').html(respData[0].First_Name); $('#editlastName').html(respData[0].Last_Name); $('#editcompanyName').html(respData[0].Company); $('#editemail').html(respData[0].Email); $('#editstate').html(respData[0].State); $('#editphone').html(respData[0].Phone); $('#editleadSource').html(respData[0].Lead_Source); $('#editForm').modal('show'); }, error: function(error) { $("#myModalLabel").html("Failure"); $("#message").html("Please try again after Sometime"); $("#loader").hide(); $('#myModal').modal('show'); } }); } function editLead() { var firstName = $("#editfirstName").val(); var lastName = $("#editlastName").val(); if (lastName == "") { alert("Kindly Enter the Last Name"); return; } var companyName = $("#editcompanyName").val(); var email = $("#editemail").val(); var state = $("#editstate").val(); var phone = $("#editphone").val(); var leadSource = $("#editleadSource").val(); var leadID = $("#editBtn").val(); $.ajax({ url: "/crmData/" + leadID, type: "put", contentType: "application/json", data: JSON.stringify({ "First_Name": firstName, "Last_Name": lastName, "Company": companyName, "Email": email, "State": state, "Phone": phone, "Lead_Source": leadSource }), success: function(data) { debugger; $('#editForm').modal('toggle'); $("#myModalLabel").html("Success"); $("#message").html("Lead Edited Successfully"); $('#myModal').modal('show'); setTimeout(function() { location.reload(); }, 3000); }, error: function(error) { $('#leads').trigger("reset"); $("#myModalLabel").html("Failure"); $("#message").html("Please try again after Sometime"); $("#loader").hide(); $('#myModal').modal('show'); } }); } function getRequiredData(data) { var i; var resp = []; for (i = 0; i < data.length; i++) { var gulp = { "First Name": data[i].First_Name, "Last Name": data[i].Last_Name, "Phone": data[i].Phone, "Email": data[i].Email, "Company": data[i].Company, "Edit": '&lt;center&gt;&lt;a href=&quot;javascript:showEditPopup(\'' + data[i].id + '\')&quot;&gt;&#9998;︎&lt;/a&gt;&lt;/center&gt;', "Delete": '&lt;center&gt;&lt;a href=&quot;javascript:showDeletePopup(\'' + data[i].id + '\')&quot;&gt;&#128465;︎&lt;/a&gt;&lt;/center&gt;' } resp.push(gulp); } console.log(resp); return resp; } function renderTable(respData) { var col = []; for (var i = 0; i < respData.length; i++) { for (var key in respData[i]) { if (col.indexOf(key) === -1) { col.push(key); } } } var table = document.createElement("table"); table.id = "dataTable"; var tr = table.insertRow(-1); for (var i = 0; i < col.length; i++) { var th = document.createElement("th"); th.innerHTML = col[i]; tr.appendChild(th); } for (var i = 0; i < respData.length; i++) { tr = table.insertRow(-1); for (var j = 0; j < col.length; j++) { var tabCell = tr.insertCell(-1); tabCell.innerHTML = respData[i][col[j]]; } } var divContainer = document.getElementById("showData"); divContainer.innerHTML = ""; divContainer.appendChild(table); } {{%/panel_with_adjustment%}} {{%panel_with_adjustment class="language-css line-numbers" header="main.css" footer="button" scroll="set-scroll" %}}#dataTable { font-family: Arial, Helvetica, sans-serif; border-collapse: collapse; width: 100%; } #dataTable td, #dataTable th { border: 1px solid #ddd; padding: 8px; } #dataTable tr:nth-child(even) { background-color: #f2f2f2; } #dataTable tr:hover { background-color: #ddd; } #dataTable th { padding-top: 12px; padding-bottom: 12px; text-align: left; background-color: #007bff; color: white; } .vertical-alignment-helper { display: table; height: 100%; width: 100%; pointer-events: none; } .vertical-align-center { display: table-cell; vertical-align: middle; pointer-events: none; } .modal-content { width: inherit; max-width: inherit; height: inherit; margin: 0 auto; pointer-events: all; } {{%/panel_with_adjustment%}} Update the value of the key command as "{{%badge%}}**node index.js**{{%/badge%}}" in the {{%badge%}}app-config.json{{%/badge%}} file. This is the {{%link href="/en/serverless/help/appsail/key-concepts/appsail-execution/#startup-commands" %}}startup command{{%/link%}} that is specific for this programming stack and framework. {{%panel_with_adjustment class="language-json line-numbers" header="app-config.json" footer="button" scroll="set-scroll" %}}{ "command": "node index.js", "build_path": "/", "stack": "node20", "env_variables": {}, "memory": 256, "scripts": {}, "raw": {}, "catalyst_auth": true, "login_redirect": "/index.html" } {{%/panel_with_adjustment%}} {{%note%}}{{%bold%}}Note:{{%/bold%}} Ensure you add your build path in line {{%bold%}}3{{%/bold%}}.{{%/note%}} Now let's go over the logic and functionality of the application code. * The {{%badge%}}login.html{{%/badge%}} file in the client component enables Catalyst Embedded Authentication login, allowing you to log in using the Zoho social login. * The {{%badge%}}index.html{{%/badge%}} file contains the code for the front-end of the client. It defines a function {{%badge%}}navigate(){{%/badge%}} that enables the connection to the CRM account by passing the required authorization information such as the {{%badge%}}Client ID{{%/badge%}} and the scope. * The backend logic of the application defines the following APIs that perform various actions: - {{%badge%}}**/generateToken**{{%/badge%}}: Obtains the *Refresh Token* by calling the {{%badge%}}getRefreshToken(){{%/badge%}} function, and inserts it along with the {{%badge%}}userID{{%/badge%}} of the current user in the {{%badge%}}Token{{%/badge%}} table in the *Data Store*. It then redirects to the index page of the client. - {{%badge%}}**/getUserDetails**{{%/badge%}}: Fetches the user details by calling the {{%badge%}}getUserDetails(){{%/badge%}} function. If there is no record in the table, a JSON response with the {{%badge%}}userID{{%/badge%}} alone is sent. If the record exists in the table, it is sent along with the {{%badge%}}userID{{%/badge%}}. - {{%badge%}}**/crmData**{{%/badge%}}: This route defines the path of all leads in the Leads module. The Node function executes the HTTP {{%badge%}}GET{{%/badge%}} and {{%badge%}}POST{{%/badge%}} operations to fetch all leads or create a new lead using this route, respectively. - {{%badge%}}**/crmData/:id**{{%/badge%}}: This route defines the path of a particular lead in the Leads module. The {{%badge%}}id{{%/badge%}} represents the unique ID of the lead in CRM. The function executes the HTTP {{%badge%}}PUT{{%/badge%}} and {{%badge%}}DELETE{{%/badge%}} operations to edit or delete a lead, respectively, using this route. * The backend logic is implemented using the following functions that are called by the APIs: - {{%badge%}}**getRefreshToken()**{{%/badge%}}: Fetches the *Refresh Token* by passing the {{%badge%}}Client ID{{%/badge%}}, {{%badge%}}Client Secret{{%/badge%}}, *Redirect URI* and other required values as query string parameters. - {{%badge%}}**getAccessToken()**{{%/badge%}}: Fetches the *Access Token* by passing the *Refresh Token* queried from the Token table using {{%link href="/en/cloud-scale/help/zcql/introduction/" %}}ZCQL{{%/link%}}, and other required parameters. The Access Token is fetched each time an operation needs to be performed on the CRM module, such as adding a lead or editing a lead. - {{%badge%}}**getResponse()**{{%/badge%}}: Passes the *Access Token* fetched to obtain the authorization needed to perform each action on the CRM module. This function is called with each {{%badge%}}/crmData{{%/badge%}} and {{%badge%}}/crmData/:id{{%/badge%}} API to authorize the request. - {{%badge%}}**getUserDetails()**{{%/badge%}}: Fetches the record from the *Token* table that contains the *Refresh Token*, by passing the {{%badge%}}userID{{%/badge%}}. * {{%badge%}}**main.js**{{%/badge%}}: It is the JavaScript function in the client component that parses the JSON responses obtained from the function and renders them in the {{%badge%}}index.html{{%/badge%}} page. This function defines the actions for all the UI elements in the client application. For example, {{%badge%}}getLeads(){{%/badge%}} obtains all leads from the function response and renders them in the client, and {{%badge%}}showEditPopup(){{%/badge%}} defines the actions for editing a lead. -------------------------------------------------------------------------------- title: "Test the Application" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.687Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/express/test-app/" service: "All Services" related: - CLI Help Documentation (/en/cli/v1/cli-command-reference/) - Serve Resources (/en/cli/v1/serve-resources/introduction/) -------------------------------------------------------------------------------- # Test the Application Before you deploy the application to the remote console, you can {{%link href="/en/cli/v1/serve-resources/introduction" %}}test the application on a local server{{%/link%}} and check if everything works fine using the Catalyst CLI. To serve the Catalyst project locally, execute the following command from your project directory: {{%cli%}}catalyst serve{{%/cli%}} The Lead Manager application will now be served at default {{%badge%}}port 3000{{%/badge%}}. The local endpoint URLs of the components are displayed. {{%info%}}{{%bold%}}Info:{{%/bold%}} Every time you access the home page or any of the sub-pages of your client or the function, the CLI will display a live log of the URL accessed, along with the HTTP request method.{{%/info%}} {{%note%}}{{%bold%}}Note:{{%/bold%}} Ensure you have provided the required {{%bold%}}Authorized Redirect URIs{{%/bold%}} when you {{%link href="/en/tutorials/leadmanager-appsail/express/register-client/" %}}registered the client in Step {{%bold%}}4{{%/bold%}}{{%/link%}}.{{%/note%}} <br /> You can now open the application in a browser using the local URL of the client displayed in the CLI. You will initially be redirected to the login page. If you configure a sign-up action on your own, you can sign up first, then log in to the application. Alternatively, you can also log in using the *Zoho Social Login*. <br /> You will be redirected to the permissions page. Accept the permissions requested by the app to access your Zoho account details. You will then be redirected back to the application. Click the **Zoho CRM** icon in this page to connect to Zoho CRM. <br /> You must now **choose the CRM account** that you wish to connect with the Lead Manager app, then click **Submit**. <!-- <br /> --> All your existing developer, sandbox, and production accounts will be listed. Click **Accept** to allow the *Lead Manager* app to access your Zoho CRM modules. <br /> You will be redirected back to the application. You can now create and manage leads in your configured Zoho CRM account directly from this application. To add a lead, enter the details of the lead in the *Add a Lead* section and click **Add Lead**. <br /> A confirmation pop-up will display the status every time you add, edit, or delete a lead. <br /> You can click the **Manage Leads** tab to view all your leads from the *Leads* module. You can **edit** or **delete** any of them by clicking their respective icons in the table. <br /> You can update a lead’s information, then click **Edit**. <br /> If you click the **delete** icon, you must confirm the action in the confirmation pop-up. <br /> You can also check the *Refresh Token* and {{%badge%}}userID{{%/badge%}} values populated in the **Data Store** from your Catalyst console. Navigate to the **Data View** section of the *Token* table to view the record that was added. <br /> If you delete this entry, you will have to authenticate your credentials in the client application and establish a connection to your CRM account again. You can log out of the application by clicking **Logout**. You can quit the {{%badge%}}serve{{%/badge%}} session in your terminal by executing the command to kill a running process, based on your OS. If this setup is working correctly, we can deploy the application to production. -------------------------------------------------------------------------------- title: "Deploy the Application" description: "Build a Lead Manager application and host it on AppSail. The app connects to your Zoho CRM account using Catalyst connectors, and enables you to view, create, update, or delete leads from the Leads module in your CRM." last_updated: "2026-03-18T07:41:08.688Z" source: "https://docs.catalyst.zoho.com/en/tutorials/leadmanager-appsail/express/deploy-app/" service: "All Services" related: - CLI Help Documentation (/en/cli/v1/cli-command-reference/) - Deploy Resources (/en/cli/v1/deploy-resources/introduction/) - AppSail Help Documentation (/en/serverless/help/appsail/introduction/) -------------------------------------------------------------------------------- # Deploy the Application You can now deploy the application to the remote console. {{%note%}}{{%bold%}}Note:{{%/bold%}} Since you had already logged into the {{%bold%}}Lead Manager{{%/bold%}} application from the local server, a {{%italics%}}Refresh Token{{%/italics%}} would have already been generated. This token will continue to authenticate your access.{{%/note%}} To {{%link href="/en/cli/v1/deploy-resources/introduction" %}}deploy your Catalyst project from the CLI{{%/link%}}, run the following command in your terminal from your project directory: {{%cli%}}catalyst deploy{{%/cli%}} The function is deployed first, followed by the client component. The app URLs of the components will be displayed. <br /> The application is now deployed to the Catalyst console. Now, if you once again navigate to the AppSail component located under the *Serverless* section, you will be able to acquire the application's invocation URL. <br /> In this section you will also have access to a live dashboard denoting the number of instances the Lead Manager app service has spawned at any given moment. Using this section you will also be able configure and manage the AppSail service. You can find out more about this {{%link href="/en/serverless/help/appsail/console/introduction/" %}}here{{%/link%}}. You can use the invocation URL in a browser to access the deployed application. Lead Manager application can now be accessed from its {{%link href="/en/cloud-scale/help/web-client-hosting/introduction" %}}web app URL{{%/link%}}. <br />