
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
Formula to return string "WK 26 - 6.2.25 - 6.8.25
Here's what I've got but syntatic failure: if(not(isnull(${Deals.GS_Due})), "Week " + Tostring(ceil(dayofyear(${Deals.GS_Due}) / 7)) + " - " + Tostring(month(${Deals.GS_Due})) + "." + Tostring(day(${Deals.GS_Due})) + "." + Tostring(year(${Deals.GS_Due}))
Introducing LeadChain in Bigin to sync leads from Social Ads easily
We're excited to introduce a new topping in Bigin called LeadChain by Zoho Social. LeadChain instantly syncs lead information from social media lead ads to Bigin, making it easier to turn them into customers. It also helps you send conversion data back
Templates Access
There should be an option to grant users access to templates but not allow them to edit/delete templates. In setup there is only one tick option for templates. This will give any user access to view as well as delete/edit. This doesnt make sense as they
Generate a Zoho Sign link
From time to time I get a response "I never received your you e-document for electronic signature" is there a way to generate a Zoho Sign link to share.
Power of Automation :: Autocomplete the Project upon Task closure.
Hello Everyone, A Custom function is a user-written set of code to achieve a specific requirement. Set the required conditions needed as when to trigger using the Workflow rules (be it Tasks / Project) and associate the custom function to it. Requirement:
Unable to send email through Gmail
So I had a custom domain email from Zoho and I was able to send emails from this account through my gmail. 2 days ago I added another user. This user is not able to receive any emails, that's the first issue, moreover, even though I haven't changed anything else other than adding this user, now I am unable to send email through my gmail account with the first user either! I have opened a case with priority "I am stuck, need assistance", haven't got a single reply in about 36 hours. I am unable to
"Invalid Credentials(Failure)" when configuring IMAP (Outlook)
Getting the below response when attempting to configure Zoho mail in Outlook 2016: Notes (what I've done so far): Zoho mail on web client is working with no issues. Though I was certain the username & PW were correct (was using same credentials on web client as I was attempting to utilize in Outlook 2016), just in case, I went ahead and changed my password on the web client and re-attempted Outlook configuration; same error response. IMAP for my email account was enabled on the web client (and POP
Custom service report or Zoho forms integration
Hello, So far the experience with Zoho FSM and the integration with Books has been good, however there are limitations with service reports. As with my business, many organisations send technicians to different types of jobs that call for a different
Pre-fill Email field on Zoho Forms
Hello there, How do we automatically pre-fill the email address field of a Zoho Form from the data that is in CRM? Thanks, Joel
Webhook Trigger for New Messages in Cliq Channels
Hello, I would like to request a feature to enable webhook triggers when a new message is added to a Cliq channel. This functionality would allow us to seamlessly send important information from Cliq to other relevant systems. This webhook trigger can
Unable to add subdomain email account under the main email account
Hi, Is it possible to add a subdomain email account, like sky@agent.rebrightrental.com from the Admin Console of admin@rebrightrental.com in Zoho Mail? Or is that not possible? I want to create at least 3, like oak@agent.rebrightrental.com, bliss@agent.rebrightrental.com,
How to delete a large number of emails
Since no one else seems to be asking this, there must be something in the zoho mail interface that I am failing to see. Not looking for an automatic method. Instead, when I sort email by sender, I want to be able to select all emails from a sender and
want to renew my account
I am not getting email - it seems renewal of account is required. pls check and advise how to renew the account and what would be the charges
Mail app and desktop on chrome not syncing properly.
Yesterday I spent a significant amount of time on the computer moving emails to different folders, and deleting several. This morning, I realized on my zoho mail app it still showed all the emails in the inbox. Nothing had synced. I couldn't find a sync
Can't connect to Thunderbird
Setting up Thunderbird I get an error message: "Unable to log in at server. Probably wrong configuration, username or password". The password and email address are definitely correct as I used them to log in to webmail. My settings are definitely correct
Can't receive emails, but can send
I setup a mail using the domain @shopik.io. I set this up using the correct CNAME record on Namecheap. When I tried to send a test mail from my Gmail account it was not able to send and I got the following error; The response from the remote server was:
Unable to send message;Reason:550 5.4.6 Unusual sending activity detected. Please try after sometime
Hello i'm unable to send any email because i keep getting this error Unable to send message;Reason:550 5.4.6 Unusual sending activity detected. Please try after sometime i have literally sent less than 10 emails today i'm not sure why i'm getting this
Partial refunds
I am trying to process refund for a one item invoice, however the refund is partial: i am getting this error while creating credit note, can anyone share some wisdom about this
Tickets are enabled but not showing in zoho desk widget
Hi, I have a Zoho Desk ASAP JWT widget inside my app. I enabled the KB, tickets, and salesIQ chat (screenshot 1), but only the KB and chat are showing on my app widget (screenshot 2). Can you help? Thank you
default to display images in mail
How do I set my mail settings to default to display images, rather than asking me each time I open a message? Thanks, Sup
Zoho CRM Theme Color?
I've read multiple articles stating it's possible to change Zoho CRM theme colour (top menu bar) from personal settings menu, however, my zoho has no options for this at all and I've looked everywhere........has this feature been removed? I'm currently
US Zipcode Mapping for Sales Tax areas
In its current form, Zoho Commerce maps tax percentage to different states. Due to the wide variety of tax areas within each state, it would be much better to map sales tax against each individual zip code. In addition, it would be highly desirable to
New Emails not being received in Zoho Email account
I have built a new website for my client, who has an email address like his_address@zohomail.eu (example). When his customers use the Contact Form on his website, the notification emails are sent to an address as his domain name, and the Webhost automatically
Custom Function : Copy multilookup field to text field
Hi, I'm a newbie on function programming, I try to copy text from a multi lookup field named "societe" to a text field named "societe2". I've used this code. In deluge script it seems to work, but when I trigger this function it doesn't work (Societe2
Relocating the server from Europe to the UAE
We are experiencing issues with the sales templates and attempted to collaborate with the companies you recommended to assist with the templates. Unfortunately, we were unable to add their email addresses to our panel due to an error (The ERROR is: USER
get statement as file pdf to send in whatsapp template
hello i have the following url which sends an email with the statement attached sendStatement = invokeurl [ url: "https://www.zohoapis" + dc + "/books/v3/contacts/" + customerID + "/statements/email?start_date=" + start_date + "&end_date=" + end_date
I already configured DKIM Records, and other records as well
I already configured DKIM Records, and other records as well but it is still going like a spam mail
No recibo correos
Buena tarde. No estoy recibiendo correo en Zoho mail, pero si puedo enviar. Como puedo solucinarlo?
Email not sending on Iphone on (1) account. Works with the others and set up thesame.
When I attempt to send an email on one of our accounts on my iphone, It doesn't and. then comes back with an error message.. I've reviewed my other two accounts, and they both work fine on my iphone, it's just this one account.. I've also looked at the
Receive the incoming emails of my users
Guys, I need some help. As an admin, can I receive all the incoming emails from my users?
I couldn't create new email "connect@cafeconnet.lk"
Dear Manager, I want to create new email "connect@cafeconnect.lk" but I can't do that. Please help me for that.
didnt add my soho account Mail
i cant add my soho account arturo@thrivechile.com in Mail (apple)
How to apply customized Zoho Crm Home Page to all users?
I have tried to study manuals and play with Zoho CRM but haven't found a way how to apply customized Zoho CRM Home Page as a (default) home page for other CRM users.. How that can be done, if possible? - kipi Moderation Update: The option to mark a customized
Zoho Projects > Workdrive Integration - Where can you find your files in Workdrive?
Following the instructions here: https://help.zoho.com/portal/en/kb/projects/integration/zoho-apps/articles/zoho-workdrive-integration#Benefits Put a file in the Documents section of a Project. Then Trying to navigate to the Team Folder in WorkDrive and
How to set custom Sales Order numbers
I am trying to create Sales Orders with data from Jotform submissions. Auto number generation is disabled within Books. Whereas the flow Input recognizes the number (40732 in this example), the Output does not. How can I fix this? I'd like the number
Zoho desktop problem when using 2 displays
I have a Microsoft Surface Pro with a second display attached. When I open Zoho mail desktop and place the window on on the second display and I keep the display attached, everything works fine. HOWEVER: when I then detach the second display (the Zoho
Assign Multilpe Owners to a Single Deal and Split Revenue Between the Two
Hello, In our business, it is common for 2 sales reps to co-manage a deal. As such, I would like to add 2 co-owners to a deal within CRM, and then split the revenue generated by a deal between both owners in our analytics. We are currently tracking this
Mix and Match Email Plan
Dear Zoho Sales Team, I hope you’re doing well. I am currently subscribed to Zoho Mail Premium with one account. However, I would like to modify my plan by adding two Mail Lite (10GB) accounts alongside my existing subscription. Could you please confirm
Comprehensive guide to add users
We've received quite a few questions regarding adding users to the Zoho Sprints workspace. So we decided to address it through a comprehensive post covering the locations (modules or tabs) from which you can add your users. Adding users to your workspace
How to monitor hybrid projects?
Hybrid project management sounds great, but, with projects being run on different project management methods, how can we monitor the overall progress and derive insights from them? If you've got this question as well, Zoho Projects Plus’ dashboards have
Next Page