
Howdy Tech Wizards!
Welcome back to a fresh week of Kaizen!
This time, we are diving into a two-part series where you will learn how to build a Timer and Worklog Widget for Zoho CRM. This widget helps track active work time and log multitasking sessions using Zoho CRM
APIs,
Client Script,
Functions, and
Workflows.
Why It Matters?
Zoho CRM effectively captures stage/status transitions, like tracking when a case moves from Open to In Progress or On Hold. However, in dynamic work environments, employees juggle multiple work items and engage in impromptu tasks or conversations.
Let’s take the On Hold status as an example.
While it can be used to indicate pauses in progress, it does not always align with real-world workflows. Consider these scenarios:
Not all interruptions justify a status change
Moving the case to On Hold for every minor detour (to clarify something with a colleague or respond to another emergency work item) would be impractical and could lead to under reporting actual work hours. Over time, this untracked effort adds up, creating a gap in visibility.
Frequent status changes may dilute their meaning
In many teams, On Hold signifies a legitimate blocker like waiting on customer input or an external dependency. Using it frequently to reflect quick shifts in attention could compromise that clarity.
A timer widget solves this by:
- Capturing hands-on work items.
- Logging context switches (unrelated tasks) with descriptive entries.
- Feeding structured entries into a custom module for reporting and subform sync.
Business Scenario: IT Service Desk & Ticket Resolution
A tech support team uses the Cases module to resolve customer issues. Some tickets are straightforward; others require follow-ups, escalations, or cross-team coordination. While CRM timestamps (like stage transitions or picklist tracking) track when changes happen, they do not reflect how long someone actively worked on a case.
This Timer Widget can be the ultimate solution to track down the active time spent on each case through out the day.
What are we Building?
By the end of this two-part guide, you will know how to:
- Build a timer widget to track time per task or any CRM record.
- Log work sessions into a custom module every time the timer is started/stopped.
- Automatically populate a subform in the corresponding record module using workflows and Deluge functions.
- Leverage the Reports module to analyze work patterns, SLA adherence, and productivity trends.
In Part I, we will focus on:
-> Building and configuring the Timer Widget.
-> Capturing each timed session as a record in a custom module.
Prerequisites
1. Create a Custom Module
Create a custom module named Timer Entries to log work details and generate reports from the Reports module. A new record will be added to this module each time a timer is started.
Set up the following custom fields in the Timer Entries module:
| |
Start Time | DateTime |
End Time | DateTime |
Total Duration (in mins.) | Formula DateBetween(${Timer Entries.Start Time},${Timer Entries.End Time},'Minutes') |
Related to Case | Lookup to Cases module |
Work Description | |
2. Add a custom picklist option
Add a custom picklist option called In Progress to the Status picklist field in the Cases module for precisely identifying the status of the cases.
3. Setup Custom Views for Contextual Filtering
To streamline the widget experience and ensure users only see relevant records to associate while tracking time, set up two smart custom views—one in the Cases module and another in the Timer Entries module.
Active Cases View (Cases Module)
Create a custom view in the Cases module to list only the active tickets the logged-in user is working on. Use the following criteria tips:
- Use the Status field to filter records with values like In Progress, On Hold, or Escalated.
- Use the Case Owner field to show records that are assigned only to the currently logged-in user.
This view powers the drop-down inside the widget where users select the case they want to start the timer for.
Active Timers View (Timer Entries Module)
Set up a second custom view in the Timer Entries module to track entries where the timer has been started but not yet stopped. These represent active timers. Use the following logic for criteria:
- The End Time field is empty (i.e., timer still running).
- Timer Entry owner field matches the logged-in user.
This view is used internally by the widget to detect if a timer is already running and update the same entry once the timer is stopped.
Follow the
Managing List View help page and use the specifications shown in the following image.
Building the Timer Widget
Step -1: Review Basics
Refer to our earlier
Kaizen on CLI Installation, Creating a Widget Project, and Internal hosting of the same.
Step 2 - Develop the Widget
After initializing your widget project using CLI, implement the timer logic:
Fetching Active Cases
On page load, the
populateRecordsDropdown function initiates a
Get Records API call to the Cases module, using the Active Cases custom view ID. This fetches all active case records assigned to the logged-in user.
These records are then listed in a dropdown, allowing users to quickly select the relevant case they are about to work on.
async function populateRecordsDropdown() { const recordsDropdown = document.getElementById("moduleRecords"); recordsDropdown.innerHTML = "";
try { const recordsResponse = await ZOHO.CRM.API.getAllRecords({ Entity: casesModule, cvid: casesCVID, per_page: 10 });
if (recordsResponse.data && recordsResponse.data.length > 0) { recordsResponse.data.forEach(record => { const option = document.createElement("option"); option.value = record.id; option.textContent = record.Subject || "Unnamed Record"; recordsDropdown.appendChild(option); }); } else { const placeholderOption = document.createElement("option"); placeholderOption.value = ""; placeholderOption.textContent = "No records found"; placeholderOption.disabled = true; placeholderOption.selected = true; recordsDropdown.appendChild(placeholderOption); } } catch (error) { console.error("Error fetching records:", error); } } |
Starting the Timer and Creating an Entry
Once the user starts the timer, The
createRecord function triggers a
Create Record API call to log the session in the Timer Entries custom module. The record captures the start time and the related case and description (if provided).
Even if no details are entered or case is selected, a timer entry is still created with the start time. This ensures that spontaneous work sessions are tracked and not lost.
async function createRecord(startTime) { try { const workDescription = document.getElementById("workDescription").value; const selectedRecordId = document.getElementById("moduleRecords").value; const selectedRecordText = document.getElementById("moduleRecords").options[ document.getElementById("moduleRecords").selectedIndex ].text;
const data = { Start_Time: startTime, Owner: currentUserId, Work_Description: workDescription, Related_to_Case: selectedRecordId, Name: selectedRecordText };
const response = await ZOHO.CRM.API.insertRecord({ Entity: timerModule, APIData: data });
console.log("Start time recorded successfully"); } catch (error) { console.error("Error creating record:", error); } }
|
Stopping the Timer and Updating the Entry
When the timer is stopped, the widget uses the Active Timer Entry custom view to locate the most recent Timer Entry record created by the logged-in user that does not have an end time.
The
updateRecord is then triggered to update that active entry using the
Update Record API call. It updates the End time of the session and the related case, descriptions, if it was not already provided when the timer was started.
async function updateRecord(endTime) { try { const workDescription = document.getElementById("workDescription").value; const selectedRecordId = document.getElementById("moduleRecords").value;
const response = await ZOHO.CRM.API.getAllRecords({ Entity: timerModule, cvid: timerEntriesCVID, per_page: 1 });
const latestRecord = response.data[0]; if (latestRecord) { const recordId = latestRecord.id; const data = { id: recordId, End_Time: endTime, Work_Description: workDescription, Related_to_Case: selectedRecordId };
await ZOHO.CRM.API.updateRecord({ Entity: timerModule, APIData: data, RecordID: recordId }); console.log("End time updated successfully"); } } catch (error) { console.error("Error updating record:", error); } } |
Step 3 - Validate and Pack the Widget
- Follow the steps given in the Widget help page to validate and package the widget.
- Go to Zoho CRM > Setup > Developer Hub > Widgets and click Create New Widget.
- Fill in the required details as shown in this image and ensure to select Button as the widget type.
Step 4 - Associate it with Flyout
- Go to Setup > Developer Space > Client Script. Click New Script.
- Enter a name and description for the script. Choose Command type in Category.
- Create a Flyout and render a widget within it using its details like the API name of the widget, title, size, and animation type. You can get the Widget API name from the widget's detail page.
let allowedUserEmails = []; allowedUserEmails.push('user1_email_address'); allowedUserEmails.push('user2_email_address'); allowedUserEmails.push('user3_email_address'); let currentUserEmail = $Crm.user.email; if (allowedUserEmails.indexOf(currentUserEmail) == -1) { ZDK.Client.showMessage('Command access resticted', { type: 'error' }); return false; } ZDK.Client.createFlyout('myFlyout', {header: 'Timer', animation_type: 4, height: '600px', width: '500px', top: '10px', left: '10px', bottom: '10px', right: '10px' }); ZDK.Client.getFlyout('myFlyout').open({ api_name: 'Timer', type: 'widget' }); return true; |
Refer to
Creating a Client Script help page for more details.
Try It Out!
A complete working code sample of this widget is attached to this post.
Now, let us see how this Timer widget works:
1. Start the Timer
Open the widget and select an active case from the dropdown. As soon as you start the timer, a new record will be automatically created in the Timer Entries module to capture the session.
2. Stop the Timer
When the task is complete, provide a description of the work you have done and stop the timer. The same Timer Entry record (created when the timer was started) will be updated automatically with the end time and your work description.
This forms the foundation for accurate time tracking at the record level.
In Part 2, we will show how to:
-> Use a workflow and Deluge function to transfer these entries into the Work Log subform inside the relevant Cases record.
-> Use CRM Reports to slice and dice work time for better SLA and productivity insights.
In the meantime, would you like us to address any of your pain-points or have a topic to discuss? Let us know in the comments or reach out to us via
support@zohocrm.com.
Until next time, Happy Coding!
-----------------------------------------------------------------------------------------------------------------
Related Reading
-----------------------------------------------------------------------------------------------------------------
Recent Topics
Archiving Contacts
How do I archive a list of contacts, or individual contacts?
Cost of good field
Is there a way we can have cost of good sold as a field added to the back end of the invoicing procedure and available in reports?
How to add image to items list in Invoice or Estimate?
Hello! I have just started using Zoho Invoice to create estimates and, possibly to switch from our current CRM/ERP Vendor to Zoho. I have a small company that is installing CCTV systems and Alarm systems. My question is, can I add images of my "items" to item list in Zoho Invoice and Estimates and their description? I would like to show my clients the image of items in our estimates so they can decide if they like these items. And I tell you, often they choose more expensive products just because
Issue with the Permission to Zoho Form
I am getting an error by signing in to zoho form as it is stated that i don't have permission to access this is admin account
CRM templates
Hello everyone, In my company we use Zoho campaigns where we set up all newsletters and we use Zoho CRM for transactional emails. I have created some templates in Zoho campaigns but from my understanding i cannot use those in Zoho CRM, right?
Meet Canvas' Grid component: Your easiest way to build responsive record templates
Visual design can be exciting—until you're knee-deep in the details. Whether it's aligning text boxes to prevent overlaps, fixing negative space, or simply making sure the right data stands out, just ironing out inconsistencies takes a lot of moving parts.
Addin Support in Zoho Sheet
Is there any addin support available in zoho sheet as like google marketplace to enhance productivity by connecting with other apps, providing AI data analysis, streamlining business processes, and more?
Where to integrate Price Book and Product List Price
Hello, We sync zoho crm all modules with all data to zoho analytics. In zoho crm, we have "Price Books" and "Products" modules, where each product is assigned to a few price books with different list prices. From zoho crm, I am able to export a dataset
Pending Sales Order Reports
Pending sale order report is available for any single customer, Individual report is available after 3-4 clicks but consolidated list is needed to know the status each item. please help me.
Zoho Mail SMTP IP addresses
We are using Zoho Mail and needs to whitelist IP for some redirections from your service to another e-mails. You can provide IP address list for Zohomail SMTP servers?
Migrate Your Notes from OneNote to Zoho Notebook Today
Greetings Notebook Users, We’re excited to introduce a powerful new feature that lets you migrate your notes from Microsoft OneNote to Zoho Notebook—making your transition faster and more seamless than ever. ✨ What’s New One-click migration: Easily import
Deluge sendmail in Zoho Desk schedule can't send email from a verified email address
I am trying to add a scheduled action with ZDesk using a Deluge function that sends a weekly email to specific ticket client contacts I've already verified the email address for use in ZDesk, but sendmail won't allow it in its "from:" clause. I've attached
Zoho Campaigns - Why do contacts have owners?
When searching for contacts in Zoho Campaigns I am sometimes caught out when I don't select the filter option "Inactive users". So it appears that I have some contacts missing, until I realise that I need to select that option. Campaigns Support have
One Contact with Multiple Accounts with Portal enabled
I have a contact that manages different accounts, so he needs to see the invoices of all the companies he manage in Portal but I found it not possible.. any idea? I tried to set different customers with the same email contact with the portal enabled and
End Date in Zoho Bookings
When I give my appointments a 30 minutes time I would expect the software not to even show the End Time. But it actually makes the user pick an End Time. Did I just miss a setting?
Zoho Commerce
Hi, I have zoho one and use Zoho Books. I am very interested in Zoho Commerce , especially with how all is integrated but have a question. I do not want my store to show prices for customers that are not log in. Is there a way to hide the prices if not
email forwarding not working
Your email forwarding service does not work. I received the confirmation email and completed the confirmation, after that nothing and nothing since no matter what I have tried. Shame as everything else was smooth. I spose it's harder to run one of these web based internet mail services than you guys thought!!! can you fix the email forwarding asap PLEASE!
Google Ads Conversions Not Being Tracked in Zoho CRM
We have 3 different conversions created in our Google Ads Account. Only one of the 3 conversion types is tracking in Zoho CRM. Our forms are Elementor Forms that are mapped into Zoho CRM. It apprears to me that all leads are showing up in Zoho CRM, but
Zoho Desk KB article embedded on another site.
We embed KB articles from Zoho Desk on another site (our application). When opening the article in a new tab, there is no issue, but if we choose lightbox, we are getting an error "To protect your security, help.ourdomain.com will not allow Firefox to
Enable Locations for Expense
Hi, please enable Locations (ex Branches) for Zoho Expense so that there is consistency between this app and Zoho Books. Thanks in advance.
Currency abbreviations
Hello, Im stuck, and need help. I need the currency fields for example, opportunity value, or total revenue, to be abbreviated, lets say for 1,000 - 1K, 1,000,000 - 1M, and so on, how should I do this?
Losing description after merging tickets
Hello, We merge tickets when they are about the same topic from the same client. It happens sometimes. We recently noticed that after the merger only the description from the master ticket is left in a thread. And the slave-ticket description is erased.
in the Zoho Creator i have File Upload field get the file on submission of the form Get the File and upload to Zoho Books
in the Zoho Creator i have File Upload field get the file on submission of the form Get the File and upload to Zoho Books . how I get the file From zoho creator and upload to Zoho Books . using Api response = invokeUrl [ url: "https://www.zohoapis.com/creator/v2.1/data/hh/l130/report/All_Customer_Payments/"+input.ID
Generate a link for Zoho Sign we can copy and use in a separate email
Please consider adding functionality that would all a user to copy a reminder link so that we can include it in a personalized email instead of sending a Zoho reminder. Or, allow us to customize the reminder email. Use Case: We have clients we need to
Syntax for URLs in HTML Snippets
What are some best practices for inserting a URL in an HTML snippet? I've looked at Zoho Help articles on navigation-based and functional-based URLs, but I'm still unclear on how to incorporate them in an HTML snippet. For example, 1. How do I link to
Rate Limiting in Zoho Flow (OpenAI API)
Hi Everyone, We are facing some issues when using Zoho Flow as we have a deluge script running which is making external calls to OpenAI endpoint. Sometimes the response takes more than 30 seconds meaning the script will timeout. We want to implement a
Placing a condition before converting the LEAD
Hi, I need some assistance with Lead conversion. I need to place certain conditions before allowing the user to convert the lead. For example: up until the certain status's doesn't equal "green" don't allow to convert lead. I tried creating this using
it is possible to open a widget via deluge script function
I have one function that is workflow action I call my fucntion I need to call the internal widget it is possible to open or it have to please tell me the solution
Creator - Portal Custom Domain
I will pay $100 in crypto to anyone who can actually get my Creator Custom Domain to function (actually tell me how you got yours to). Domain verifies, Nothing. I've been fighting it a week, multiple chats to customer service. Clearly I'm doing something wrong. Some datapoints Domain name itself unimportant, can be a string of numbers. I need to know what registrars are working for you because GoDaddy does NOT. Do I need hosting? I've tried both ways and nothing works. I pushed through Cloudflare
Transitioning to API Credits in Zoho Desk
At Zoho Desk, we’re always looking for ways to help keep your business operations running smoothly. This includes empowering teams that rely on APIs for essential integrations, functions and extensions. We’ve reimagined how API usage is measured to give
steps and options to change Domain DNS/Nameservers settings
Please share the options or steps to change Domain DNS/Nameservers settings
Unable to explore desk.zoho.com
Greetings, I have an account with zoho which already has a survey subscription. I would like to explore desk.zoho.com, but when I visit it while logged in (https://desk.zoho.com/agent?action=CreatePortal) I just get a blank page. I have tried different
Employees in Leave Policy exceptions
In the Leave Policies we should be able to add specific employees to the exception list So it will be like All Employees except A,B,C in the exception list, currently we can only add departments etc
Searching customer field
Hello, When entering a receipt, we select customer information. The customer information is synced with Zoho CRM. However, we can't find the customer information because it searches for words that begin with the entered value. It needs to search for words
How I set default email addresses for Sales Orders and Invoices
I have customers that have different departments that handle Sales Orders and Invoices. How can i set a default email for Sales Orders that's different than the default email for Invoices? Is there a way I can automate this using the Contact Persons Departments
Modular Permission Levels
We need more modular Permissions per module in Books we have 2 use cases that are creating problems We need per module export permission we have a use case where users should be able to view the sales orders but not export it, but they can export other
Kaizen #157: Flyouts in Client Script
Hello everyone! Welcome back to another exciting edition of our Kaizen series, where we explore fresh insights and innovative ideas to help you discover more and expand your knowledge!In this post, we'll walk through how to display Flyouts in Client Script
How get stock name from other column ?
How get stock name from other column ? e.g. =STOCK(C12;"price") where C12 is the code of the stock
Adding a developer for editing the client application with a single user license
Hi, I want to know that I as a developer I developed one application and handed over to the customer who is using the application on a single user license. Now after6 months customer came back to me and needs some changes in the application. Can a customer
Download an email template in html code
Hello everyone, I have created an email template and I want to download it as html. How can i do that? I know you can do it via the campaigns-first create a campaign add the template and download it as html from there. But what if i don't want to create
Next Page