Welcome to the second part of our series on how to build your own link tracking system using Payload NextJS. In this article, we'll delve deeper into enhancing our link tracking system. The original video, created by AllAboutPayload, provides a comprehensive walkthrough of the process. You can find the full video linked at the end of this article.
This article is the written companion to our step-by-step video tutorial available on YouTube at https://www.youtube.com/watch?v=7HZ1oKx5UYM. If you're a visual learner or prefer following along with video instructions, the YouTube guide covers the same content with additional context and real-time demonstrations of each implementation step. The video and this article complement each other perfectly for building your own link tracking system.
At this stage, we have a basic prototype that allows us to define a tracked link. For instance, if we define a tracked link for Google, we can set a target URL. When we call our server at localhost:4000/google, we can see the link get redirected while tracking the clicks in a chart. As of now, we recorded two clicks on our last test, and after adding another click, we now have three.
However, there are some issues we need to address. Currently, we can only see the days that received clicks, which doesn't provide a full picture of the link's performance over time. For example, although we had clicks on the 8th of March, today is the 11th, and we can't see the empty days in between. This is one of the first issues we'll tackle today.
Here's what we aim to achieve in this session:
If we don't complete everything today, we'll continue in part three.
The core issue lies in our custom aggregation endpoint. Currently, we only receive days that have at least one click. This means if no clicks occurred on a particular day, that day won't appear in our results. To solve this, we have two options:
For cleaner data, we’ll go with the first option and handle it server-side. First, let’s log the results from our aggregation to understand the data structure.
To track clicks accurately, we need to create an array of dates that spans the start and end dates from our query. Using Moment.js, we can easily generate this array. If a date has clicks, we’ll add those clicks to the respective date in our array.
Next, we’ll merge the newly created array of dates with the results from our query. For each date in our date array, we’ll check if it exists in the Atlas results. If it does, we’ll replace it with the object from the original array; if not, we'll create a new object with zero clicks for that date.
After implementing this logic, we should see our chart display all seven days as expected, including those with zero clicks.
Next, we want to add a range for one day. This will allow users to see clicks that occurred today. We have several options for implementing this:
To keep things simple, we will focus on clicks that occurred today. We will adjust our toggle to include a "Today" option.

Now that we have our daily and one-day ranges working, we want to extend our aggregation endpoint to handle hourly grouping. This will allow us to visualize clicks more granularly, showing how many clicks happen per hour.
We will add a new variable, groupMode, which will determine if we group the data by hour or by day. When the user selects the "Last 24 Hours" option, we will automatically set groupMode to hourly.
We need to modify our aggregation pipeline to group by hour instead of day. This means adjusting the way we structure our queries in MongoDB. By grouping according to the hour, we can accurately reflect when clicks occur throughout the day.
As we implement these features, we must also consider time zones. Since our server and client may operate in different time zones, we need to ensure that the times displayed reflect the user's local time. This involves converting UTC times to the local time zone on the client side.
Next, we want to add a table that displays specific click events below our chart. This table will show the timestamp of each click and will later be enhanced to include additional information like device type and browser.
To enhance our tracking capabilities, we will implement a user agent parser to store details about the device type, browser, and operating system. For this, we will use a library called uap-parser-js.
After extracting the user agent string from the request, we will parse it to gather relevant information. This will allow us to store details about how users access our links, adding valuable insights for future improvements.
We will extend our tracked link clicks collection to include fields for the browser, operating system, and device details. This way, every click will not only track when it happened but also how it happened.
In this part of our series on building a link tracking system with Payload NextJS, we tackled several critical improvements. We fixed the issue of empty days in our click tracking chart, added hourly breakdowns, and implemented a user agent parser to gather valuable information about our users.
These enhancements will provide a more comprehensive understanding of how users interact with our links, allowing for better decision-making in future developments.
Stay tuned for part three, where we will focus on optimizing our table with pagination and further refining our user experience. If you have any questions or feedback, feel free to drop a comment below!
Payload NextJS is a headless CMS that allows developers to build custom applications with ease, integrating seamlessly with Next.js for powerful front-end capabilities.
Creating your own link tracking system allows for tailored analytics, providing insights specifically relevant to your business needs, and it can save costs associated with third-party solutions.
This project primarily utilizes Payload CMS, Next.js, and Tremor charts to create a functional and visually appealing link tracking system.
To get started, visit the Payload CMS documentation for installation and setup instructions.
You can watch the full video on the AllAboutPayload YouTube channel.