return to homepage@tanselberkant

Adding Visitor Count to Your Website

How to implement and display a dynamic visitor count feature

When I decided to rebuild my website, I wanted to add a visitor count feature to make it feel more interactive and showcase site engagement. In this post, I’ll explain how I added the visitor count feature in my website

Setting Up the Frontend

The visitor count is displayed on the frontend using React state and a custom fetchVisitorCount service function. Here’s how it works:

const [visitorCount, setVisitorCount] = useState<number>(0)
const [loading, setLoading] = useState(true)

useEffect(() => {
	fetchVisitorCount('profile')
		.then(res => {
			setVisitorCount(res.visitCount)
		})
		.finally(() => {
			setLoading(false)
		})
}, [])

return (
	<div className="absolute right-4 mt-4 flex flex-row items-center gap-1">
		{loading ? (
			<LoadingDots color="bg-customBlue" />
		) : (
			<span className="text-customBlue font-bold">{visitorCount.toString()}</span>
		)}
		<span className="mt-[2px] text-sm text-gray-500">Visitor Count</span>
	</div>
)

This component leverages a loading state to ensure the visitor count only displays after it has been fetched.

Why Fetch Visitor Count in a Client Component?

I chose to make the API call from the client component so the visitor count updates in real time without requiring a page refresh. This also allows me to easily handle cookies for tracking returning visitors, ensuring the count is accurate. While fetching the data, a simple "loading" state gives the user some feedback, making the feature feel smooth and interactive.

Creating the API Endpoint

The fetchVisitorCount function communicates with a custom API endpoint to retrieve the visitor count:

interface IVisitorCountResponseData {
	_id: string
	visitCount: number
	pageName: string
}

export const fetchVisitorCount = async (pageName: string): Promise<IVisitorCountResponseData> => {
	try {
		const res = await fetch(`/api/visitor-count?pageName=${pageName}`, {
			method: 'GET',
			credentials: 'include' // Include cookies in the request
		})
		if (!res.ok) {
			throw new Error('Failed to fetch visitor count')
		}
		return await res.json()
	} catch (error) {
		console.error('Error fetching visitor count:', error)
		throw new Error('An error occurred while fetching visitor count data.')
	}
}

Handling Cookies in the API

Here’s the logic in the API endpoint:

export const GET = async (request: NextRequest) => {
	try {
		connectToDb()
		const pageName = request.nextUrl.searchParams.get('pageName')
		const cookieName = `visited_${pageName}`
		const cookies = request.cookies
		const hasVisited = cookies.get(cookieName)

		const visitorCount = await ProfileVisitorCount.findOne({ pageName })
		if (!hasVisited) {
			visitorCount.visitCount += 1
			await visitorCount.save()

			const response = NextResponse.json(visitorCount)
			response.cookies.set(cookieName, 'true', {
				httpOnly: true,
				maxAge: 60 * 60 * 12,
				path: '/'
			})
			return response
		} else {
			return NextResponse.json(visitorCount)
		}
	} catch (err) {
		console.log(err)
		throw new Error('Failed to fetch Visitors count!')
	}
}

Setting Up the MongoDB Model

The MongoDB schema stores visitor count data:

const profileVisitorCount = new mongoose.Schema(
	{
		visitCount: Number,
		pageName: String
	},
	{ timestamps: true }
)

export const ProfileVisitorCount =
	mongoose.models?.ProfileVisitorCount || mongoose.model('ProfileVisitorCount', profileVisitorCount)

Conclusion

By combining frontend and backend techniques with a robust database integration, we’ve created a reliable visitor count feature for your website. This feature not only provides valuable insights but also enhances user engagement by showcasing site activity.

Feel free to customize the code snippets to suit your project’s unique needs!