Kaizen #187 - Building a Timer and Worklog Widget (Part 1)

Kaizen #187 - Building a Timer and Worklog Widget (Part 1)



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:

Custom Fields
Data Type
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
Multi Line


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. 

Follow this Add/Remove Picklist Values help section for more details. 

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

-----------------------------------------------------------------------------------------------------------------

Idea
Previous Kaizen: Client Script Support for Subforms | Kaizen Collection: Directory



      • Sticky Posts

      • Kaizen #198: Using Client Script for Custom Validation in Blueprint

        Nearing 200th Kaizen Post – 1 More to the Big Two-Oh-Oh! Do you have any questions, suggestions, or topics you would like us to cover in future posts? Your insights and suggestions help us shape future content and make this series better for everyone.
      • Kaizen #226: Using ZRC in Client Script

        Hello everyone! Welcome to another week of Kaizen. In today's post, lets see what is ZRC (Zoho Request Client) and how we can use ZRC methods in Client Script to get inputs from a Salesperson and update the Lead status with a single button click. In this
      • Kaizen #222 - Client Script Support for Notes Related List

        Hello everyone! Welcome to another week of Kaizen. The final Kaizen post of the year 2025 is here! With the new Client Script support for the Notes Related List, you can validate, enrich, and manage notes across modules. In this post, we’ll explore how
      • Kaizen #217 - Actions APIs : Tasks

        Welcome to another week of Kaizen! In last week's post we discussed Email Notifications APIs which act as the link between your Workflow automations and you. We have discussed how Zylker Cloud Services uses Email Notifications API in their custom dashboard.
      • Kaizen #216 - Actions APIs : Email Notifications

        Welcome to another week of Kaizen! For the last three weeks, we have been discussing Zylker's workflows. We successfully updated a dormant workflow, built a new one from the ground up and more. But our work is not finished—these automated processes are

        • Recent Topics

        • Attaching files to emails within CRM Deals.

          Hello, We have recently started using the extension "Workdrive for CRM" (Related List) to view/store our documents for each Deal, instead of using Attachments. Overall it feels like a better way to go but the user experience is not so great when it comes
        • agentid : Where to find?

          I've been looking around for this agenId to check for the total ticket assigned on a specific agent url :"https://desk.zoho.com/api/v1/ticketsCountByFieldValues?departmentId=351081000000155331&agentId=35108xxxxxx132009&field=statusType,status" type :GET
        • Clone entire dashboards

          If users want to customize a dashboard that is used by other team members, they can't clone it in order to customize the copy. Instead they have to create the same dashboard again manually from scratch. Suggestion: Let users copy the entire dashboard
        • Anyone worked out how to export or screengrab a full heatmap?

          I'd love to be able to include a copy of a heatmap in a report but can't work out how to grab the whole thing as there doesn't appear to be an export function? Thanks in advance.
        • Establishing Relationships among contacts/leads with Reciprocal

          Is there any way to create a relationship between contacts and leads and be able to go into just one of the files and have it reciprocate the entry in the other file? For example, if I have two people say John and Jane Smith who are husband and wife.
        • Placeholder for Agent Signature in Email Templates

          Dear Zoho Team, I hope this message finds you well. We currently face a limitation when designing email templates in Zoho Desk. While we can create email templates and include a footer at the end, the agent signature is always appended by default at the
        • Cannot give public access to Html Snippet in Zoho Creator Page

          Hi, I created a form in Zoho Creator and published it. The permalink works but I want to override the css of the form. (style based URL parameters is not good enough) So I created a page and added an Html snippet. I can now override the css, which is
        • Print a document from Zoho Writer via Zoho Creator

          If i use the code below i can get writer to create a new document or email it to me but i want to be able to print it directly from the browser and not have to send it via email and then print. Below is the code im using. Attached options form zoho writer
        • Custom View and Custom Fields on Zoho Books

          Hi, I have some custom fields on Estimates and Invoices. I also use Custom Views so I can have a lot of information at a glance. I want to include my custom fields as columns in my custom views of estimates / invoice, but it looks like is not possible.
        • %PaymentLink%

          Does not work. Software creates a BAD link. ....and yes payment options are turned on. Link on the invoice pdf once opened will work but this template is a joke.
        • World date & time format

          Hello, Is there a timeline to get the worldwide used date and time format ? I mean not the american one... I mean day month year, and 24 hours clock. Regards
        • Allow Global Admin to access/edit all forms without changing owners

          Hi there, Please consider adding a feature where the Global Admin of the account an automatically access/edit any form in the Company Account. I'm the Global Admin on our Zoho One plan, and we have multiple users that use/create forms. But for me to access
        • Actual vs Minimum

          Hi all, I am sure I am not the only one having this need. We are implementing billing on a 30-minute increment, with a minimum of 30 minutes per ticket. My question is, is there a way to create a formula or function to track both the minimum bill vs the
        • Dont want to list inactive items.

          If an item is made inactive, there is no point in showing it in the item list. Please provide an option to hide all inactive items in 'Preferences'. 
        • Can Zoho Marketing Automation send OTP codes via WhatsApp during user registration?

          The flow I would like to implement is: A user signs up in the mobile app and enters their phone number. The system generates a one-time verification code (OTP). The OTP is sent to the user via WhatsApp message. The user enters the code in the app to confirm
        • Related lists New option in missing

          hi I have created quite a few modules and added as related lists to my main module. Some have new, some dont I can not see why?
        • Where to show Customization Field ?

          Dear Sir, I have made some New Field in Item Field Customisation. Now I don't require that field in Estimate, Sales Orders etc. I just wants that field in Sales Invoice to Show/Hide... Is that possible ?
        • What's New in Zoho Analytics - February 2026

          Hello Users! We're back with another round of updates for Zoho Analytics. This month's release focuses on giving you greater flexibility in how you visualize, manage, and act on your data - with new features like custom visualizations, remote MCP server,
        • Zoho Books (and other Finance Suite Apps) - Clickable Item Name on Invoices and Reports

          Hi Zoho Books team, It would be really helpful if the Item Name on Reports were clicable to take me to the item. The same on Invoices, often I am looking at an invoice and I want to look at the deails of a product. A link here would be helpful to jump
        • ZOHO Reports are taking longer time to get refresh

          Hi Team, Since last few days, I'm facing issues in getting updated reports. For eg: right after making an expense entry or even posting a journal, it is taking longer then expected for the updated reports. Refer below: "You are viewing the report that
        • Display actual mileage on an invoice

          My users are creating expenses in Zoho expense. For example, they expense 10 miles and get paid 7 dollars (10 miles * IRS rate of .70). If I look at the expenses in Zoho Books, it does show them at 10 miles at .70 cent When I add these expense to an invoice
        • Can't change form's original name in URL

          Hi all, I have been duplicating + editing forms for jobs regarding the same department to maintain formatting + styling. The issue I've not run into is because I've duplicated it from an existing form, the URL doesn't seem to want to update with the new
        • Can you create relationships BETWEEN contacts within the same module

          I am setting up my CRM, and I want to have a way to connect contacts within the same module.  Is there a way to do this?  If not - how do I decide how to split up contacts to make connections?  What are best practices for this? We have clients who need
        • Zoho Projects - Cloning a task does not trigger task workflow when created

          Hello! I have a Project where my team uses a set of tasks from a tasklist as templates, so we could simply clone it and drag it to another list in kanban view to avoid creating a new one from scratch. The process works well, but after cloning it the new
        • Function and workflow to create customer payment and send receipt

           I am attempting to set up a workflow/custom function for the automatic creation of a customer payment and sending the email receipt, but am receiving the error "Improper Statement Error might be due to missing ';' at end of the line or incomplete expression" I've been over everything several times and cannot see where the error is (code is copied into the attached document).  I haven't used custom functions before with Deluge, so it's very likely something very simple, or I've completely mucked
        • Disable Sign Up option in Zoho Creator Portal and show only Sign In page

          Is it possible to disable the Sign Up option in a Zoho Creator portal? The requirement is to show only the Sign In page and completely remove or hide the Sign Up page, so users cannot create accounts directly from the portal login page. Is there any setting
        • Restrict Payment Methods

          Allow us to restrict certain payment methods specific for each customer.
        • How to install Widget in inventory module

          Hi, I am trying to install a app into Sales Order Module related list, however there is no button allow me to do that. May I ask how to install widget to inventory module related list?
        • Introducing Formula Fields for performing dynamic calculations

          Greetings, With the Formula Field, you can generate numerical calculations using provided functions and available fields, enabling you to derive dynamic data. You can utilize mathematical formulas to populate results based on the provided inputs. This
        • Can I view the KB in the same way as a customer logged in as my Agent?

          Sorry if this seems a mad question.  I have some Articles that I want to be seen by my Agents and the status of these is set to Agents only.  We also have some that are set to Public. When I sign in with my private email address (as a customer) I can
        • What’s New in Zoho Inventory — Latest Features, Integrations & Updates | December 2025

          Zoho Inventory has evolved significantly over the past months, bringing you smarter, faster, and more connected tools to streamline your operations. Whether you’re managing multichannel sales, complex fulfillment workflows, or fast-moving stock, our newest
        • Push Notification for New Bookings in Zoho Bookings App

          when a someone schedules an appointment through the booking page, is there any option to receive a push notification in the mobile app?
        • Which user's capacity is used for Shared Mailbox storage?

          We use shared mailboxes at our company, and their size is increasing daily. Which user(s)'s total mailbox limit is being used up by this space?
        • Incorrect Functioning of Time Logs API (Version 3)

          We need to fetch the list of time logs for each task for our company internal usage. We are trying to achieve it by using the next endpoint: https://projects.zoho.com/api-docs#bulk-time-logs#get-all-project-time-logs Firstly, in the documentation the
        • Evernote (ENEX) import limitations

          I have been with Evernote since 2010, but the latest price increase is ridiculous. I am currently testing Zoho Notebook as a replacement. I am impressed so far - if it were not for critical need to import legacy Evernote notes, I would 100% migrate to
        • Can I create a CODE 128 custom field for my items in Zoho Inventory and then use it for generating Sales Orders?

          Can anyone helps me, I don't want to use the SKU code for scanning my products.  ​Because all my products have a CODE-128 label attached.
        • Prevent duplicate with custom fields?

          I was wondering something about custom field/custom modules in Zoho Desk. For some reason you can make a custom field mandatory but not unique? For example, if I create a custom module to manage equipment and renewal and make a field serial number no
        • Zoho Books' 2025 Wrapped

          Before we turn the page to a new year, it’s time to revisit the updates that made financial management simpler and more intuitive. This annual roundup brings together the most impactful features and enhancements we delivered in 2025, offering a clear
        • Multiple Vendor SKUs

          One of the big concerns we have with ZOHO Inventory is lack of Vendor Skus like many other inventory software packages offer. Being able to have multiple vendor skus for the same product would be HUGE! It would populate the appropriate vendor Sku for
        • Create Invoice automated with Package

          Does anyone knows how to create an invoice from a SO when we have created the package? We do these manually. and validate that the product packed is the product invoiced (if the order is partially packed) Regards, JS
        • Next Page