Visitor Counter Using PHP: Powerful Live Viewers & Pageview Tracking


Visitor Counter Using PHP

Visitor Counter Using PHP with MySQLi, live online viewers, total pageviews and website hit tracking. Learn how to build and update this PHP project.

 

Visitor Counter Using PHP: Powerful Live Viewers & Pageview Tracking

If you are building a PHP website and want to know how many people are visiting your pages, a simple visitor counter can be a useful little project to learn from.

In this tutorial, we are going to build a Visitor Counter Using PHP that displays three useful numbers: total visitors, visitors currently online, and total pageviews.

The project uses PHP, MySQLi, MySQL, jQuery and AJAX. The older database functions commonly found in old PHP tutorials have also been replaced with modern MySQLi code, making the project much more suitable for current PHP environments.

The idea is simple. When someone visits the page, PHP creates a session and stores visitor information in MySQL. The pageview counter records the visit, while an AJAX request periodically checks the visitor’s activity and updates the online counter without refreshing the entire page.

What This Visitor Counter Using PHP Project Does

The finished project contains three counters:

Total Visitors
Shows the number of visitor sessions recorded by the system.

Visitors Online
Shows visitors who have been active within the last 60 seconds.

Total Pageviews
Counts page requests recorded by the application.

The online counter is particularly interesting because it uses AJAX. Instead of forcing the visitor to reload the page, JavaScript sends a small request to the PHP script every few seconds and updates the displayed number.

jQuery’s AJAX API is designed for making asynchronous requests without requiring a full page refresh.


YouTube Tutorial

â–¶ Watch the Full PHP Tutorial

Follow the complete tutorial to understand how the visitor counter works and how to configure it on your PHP website.

Watch Tutorial on YouTube


How the Visitor Counter Works

The application follows a straightforward process.

First, PHP starts a session for the visitor. The session ID is used to identify that browser session.

Next, the application connects to MySQL using the mysqli extension. If the visitor’s session does not already exist in the database, a new record is created.

If the visitor already exists, the timestamp is updated.

The application then checks which visitors have been active during the previous 60 seconds. Those records are treated as currently online.

At the same time, a pageview is inserted into the pageviews table.

Finally, jQuery sends an AJAX request periodically to the same PHP file. That request returns the current online visitor count and updates the number on the page.

This approach keeps the project small and easy to understand.


Requirements

Before installing the project, make sure your development environment has:

  • PHP 7.4+ or PHP 8.x
  • MySQL or MariaDB
  • Apache
  • XAMPP, WAMP, Laragon or another PHP server
  • phpMyAdmin
  • Basic PHP knowledge

The project uses the mysqli extension rather than the old mysql_* functions.

PHP’s official documentation provides a current quick-start guide for the MySQLi extension and its database operations.


Create the MySQL Database

Create a database named:

demo

Then import the following SQL file through phpMyAdmin.

database.sql

CREATE DATABASE IF NOT EXISTS `demo`
    CHARACTER SET utf8mb4
    COLLATE utf8mb4_unicode_ci;

USE `demo`;

CREATE TABLE IF NOT EXISTS `total_visitors` (

    `id` INT(11) NOT NULL AUTO_INCREMENT,

    `session` VARCHAR(128) NOT NULL,

    `time` INT(11) NOT NULL,

    PRIMARY KEY (`id`),

    UNIQUE KEY
        `uq_total_visitors_session`
        (`session`),

    KEY
        `idx_total_visitors_time`
        (`time`)

) ENGINE=InnoDB
  DEFAULT CHARSET=utf8mb4;


CREATE TABLE IF NOT EXISTS `pageviews` (

    `id` INT(11) NOT NULL AUTO_INCREMENT,

    `page` VARCHAR(255) NOT NULL,

    `ip` VARCHAR(45) NOT NULL,

    PRIMARY KEY (`id`),

    KEY
        `idx_pageviews_page`
        (`page`)

) ENGINE=InnoDB
  DEFAULT CHARSET=utf8mb4;

The first table stores visitor sessions and activity timestamps. The second table stores pageview information.


Main PHP File

Now create a file named index.php.

This file handles the database connection, visitor session, visitor counting, pageview tracking, AJAX request and HTML interface.

index.php

<?php

session_start();

$_SESSION['session'] = session_id();


/*
 * Database configuration
 */

$host = "localhost";
$username = "root";
$password = "";
$databasename = "demo";


/*
 * MySQLi database connection
 */

$connect = new mysqli(
    $host,
    $username,
    $password,
    $databasename
);


if ($connect->connect_error) {

    die(
        "Database connection failed: "
        . $connect->connect_error
    );

}


$connect->set_charset("utf8mb4");


/*
 * Calculate online visitors
 */

function total_online(mysqli $connect): int
{

    $current_time = time();

    $timeout = $current_time - 60;

    $session_id = $_SESSION['session'] ?? '';


    if ($session_id === '') {

        return 0;

    }


    /*
     * Check existing session
     */

    $stmt = $connect->prepare(
        "SELECT id
         FROM total_visitors
         WHERE session = ?
         LIMIT 1"
    );


    $stmt->bind_param(
        "s",
        $session_id
    );


    $stmt->execute();


    $result = $stmt->get_result();


    $session_check = $result->num_rows;


    $stmt->close();


    /*
     * Insert new visitor
     */

    if ($session_check === 0) {

        $stmt = $connect->prepare(
            "INSERT INTO total_visitors
             (session, time)
             VALUES (?, ?)"
        );


        $stmt->bind_param(
            "si",
            $session_id,
            $current_time
        );


        $stmt->execute();


        $stmt->close();

    }


    /*
     * Update existing visitor
     */

    else {

        $stmt = $connect->prepare(
            "UPDATE total_visitors
             SET time = ?
             WHERE session = ?"
        );


        $stmt->bind_param(
            "is",
            $current_time,
            $session_id
        );


        $stmt->execute();


        $stmt->close();

    }


    /*
     * Count active visitors
     */

    $stmt = $connect->prepare(
        "SELECT COUNT(*) AS total
         FROM total_visitors
         WHERE time >= ?"
    );


    $stmt->bind_param(
        "i",
        $timeout
    );


    $stmt->execute();


    $result = $stmt->get_result();


    $row = $result->fetch_assoc();


    $stmt->close();


    return (int)($row['total'] ?? 0);

}


/*
 * AJAX online visitor request
 */

if (isset($_POST['get_online_visitor'])) {

    echo total_online($connect);

    $connect->close();

    exit;

}


/*
 * Current online visitors
 */

$total_online_visitors =
    total_online($connect);


/*
 * Total visitors
 */

$result = $connect->query(
    "SELECT COUNT(*) AS total
     FROM total_visitors"
);


$row = $result->fetch_assoc();


$total_visitors =
    (int)($row['total'] ?? 0);


/*
 * Record pageview
 */

$user_ip =
    $_SERVER['REMOTE_ADDR'] ?? '';

$page =
    $_SERVER['PHP_SELF'] ?? '';


$stmt = $connect->prepare(
    "INSERT INTO pageviews
     (page, ip)
     VALUES (?, ?)"
);


$stmt->bind_param(
    "ss",
    $page,
    $user_ip
);


$stmt->execute();


$stmt->close();


/*
 * Total pageviews
 */

$result = $connect->query(
    "SELECT COUNT(*) AS total
     FROM pageviews"
);


$row = $result->fetch_assoc();


$total_pageviews =
    (int)($row['total'] ?? 0);


$connect->close();

?>

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta
    name="viewport"
    content="width=device-width, initial-scale=1.0"
>

<title>Visitor Counter Using PHP</title>


<style>

* {

    margin: 0;

    padding: 0;

}


body {

    text-align: center;

    width: 66%;

    margin: auto;

    background:
        url(assets/background2.png);

    font-family:
        Helvetica,
        Arial,
        sans-serif;

}


h1 {

    font-size: 60px;

    margin-top: 80px;

    color: #fff;

    text-shadow:
        2px 2px 0px rgba(255,255,255,.7),
        5px 7px 0px rgba(0,0,0,0.1);

}


.container {

    height: 250px;

    width: 31%;

    float: left;

    margin-top: 40px;

}


.round {

    width: 160px;

    height: 160px;

    border-radius: 50%;

    background: #fff;

    margin: 20px auto;

}


.values {

    color: #888;

    line-height: 3.8em;

    font-size: 40px;

}


p {

    font-size: 32px;

    color: #fff;

    font-weight: bold;

}


@media (max-width: 900px) {

    body {

        width: 94%;

    }


    h1 {

        font-size: 42px;

    }


    .container {

        width: 100%;

        float: none;

    }

}

</style>


<script
src="https://code.jquery.com/jquery-3.7.1.min.js">
</script>


<script>

$(document).ready(function () {


    /*
     * Refresh online visitor count
     * every 10 seconds.
     */

    setInterval(function () {


        $.ajax({

            type: 'POST',

            url: '',

            data: {

                get_online_visitor:
                    "online_visitor"

            },

            success: function (response) {


                if (response != "") {

                    $("#online_visior_val")
                        .html(response);

                }

            }

        });


    }, 10000);


});

</script>

</head>


<body>


<h1>
    Visitor Counter
</h1>


<div class="container">

    <div class="round">

        <p class="values">

            <?php

            echo $total_visitors;

            ?>

        </p>

    </div>


    <p>
        Total Visitors
    </p>

</div>


<div class="container">

    <div class="round">

        <p
            class="values"
            id="online_visior_val"
        >

            <?php

            echo $total_online_visitors;

            ?>

        </p>

    </div>


    <p>
        Visitors Online
    </p>

</div>


<div class="container">

    <div class="round">

        <p class="values">

            <?php

            echo $total_pageviews;

            ?>

        </p>

    </div>


    <p>
        Total Pageviews
    </p>

</div>


</body>

</html>

Why MySQLi Is Used in This Updated Version

If you have followed older PHP tutorials, you may have seen functions such as mysql_query(), mysql_connect() and mysql_num_rows().

Those old mysql_* APIs should not be used in a modern project. This updated version uses mysqli, which is supported by current PHP versions.

The code also uses prepared statements for database operations involving visitor session values and pageview information. PHP’s documentation explains that prepared statements use placeholders and bound parameters and can help protect database queries from SQL injection.

For example:

$stmt = $connect->prepare(
    "UPDATE total_visitors
     SET time = ?
     WHERE session = ?"
);

$stmt->bind_param(
    "is",
    $current_time,
    $session_id
);

$stmt->execute();

This is much cleaner than concatenating user-controlled values directly into SQL queries.


How the Live Online Counter Works

The Visitors Online number is based on activity during the previous 60 seconds.

Every visitor receives a PHP session ID. When they visit the page, the application checks whether that session exists.

If it is a new session, the visitor is inserted into the database.

If the session already exists, its timestamp is updated.

The application then counts records where the timestamp is newer than the 60-second timeout.

The browser also sends an AJAX request every 10 seconds.

This means the visitor can keep the page open and see the online count change without manually refreshing the browser.

The jQuery $.ajax() method supports asynchronous requests and callbacks for handling returned data.


How the Total Pageview Counter Works

The pageview counter is intentionally simple.

Whenever index.php loads normally, the script records:

  • Current page
  • Visitor IP address
  • Database record ID

The total pageview number is then calculated with:

SELECT COUNT(*) AS total
FROM pageviews

This gives you a basic website hit counter without requiring a large analytics platform.

For a production website, you may eventually want to add additional fields such as user agent, referrer, country, device type and timestamp.


Project Folder Structure

Your project can use the following structure:

visitor-counter/
│
├── index.php
│
├── database.sql
│
└── assets/
    │
    └── background2.png

Keep the background2.png file inside the assets directory because the CSS references it using:

background: url(assets/background2.png);

How to Install the Visitor Counter

Installation is straightforward.

First, copy the project folder into your XAMPP htdocs directory.

For example:

C:\xampp\htdocs\visitor-counter\

Start Apache and MySQL from the XAMPP Control Panel.

Open phpMyAdmin and create/import the demo database using the supplied database.sql file.

Next, check the database configuration inside index.php.

For a default XAMPP installation, the configuration is normally:

$host = "localhost";
$username = "root";
$password = "";
$databasename = "demo";

Finally, open:

http://localhost/visitor-counter/

You should see the three counter boxes.

Open the page in multiple browser windows or devices and allow a few seconds for the online visitor number to change.


Important Note About Visitor Counting

This is a lightweight visitor counter rather than a replacement for a complete analytics platform.

A session is not necessarily the same thing as a unique human visitor. Someone using another browser, clearing cookies or opening a different session can be counted separately.

Likewise, the IP address stored by this example is useful for basic tracking but should be handled according to your privacy requirements and applicable laws.

If you publish this project publicly, consider adding a privacy policy explaining what information is collected and why.


Easy Improvements You Can Add

Once the basic Visitor Counter Using PHP is working, you can extend it with several useful features.

For example, you could add:

  • Today’s visitors
  • Yesterday’s visitors
  • Monthly visitors
  • Unique IP tracking
  • Country detection
  • Browser detection
  • Operating-system detection
  • Mobile/desktop detection
  • Referral URL tracking
  • Last visitor information
  • Admin dashboard
  • Graphs and statistics
  • Daily pageview reports
  • Most-viewed pages
  • Online visitor list

You could also separate the AJAX endpoint into its own PHP file. That can make a larger application easier to maintain.


Useful Resources

For the database portion, the official PHP MySQLi documentation is a useful reference when adapting this project to your own application.

For the live counter, the jQuery AJAX documentation explains how asynchronous requests work and how returned data can be handled.

If you are publishing the code inside WordPress, WordPress also provides a dedicated Code block for displaying source code while preserving spacing and formatting.


Final Thoughts

Building a Visitor Counter Using PHP is a great beginner-to-intermediate PHP project because it combines several important web-development concepts in one small application.

You get practical experience with PHP sessions, MySQL databases, MySQLi connections, prepared statements, SQL queries, JavaScript, jQuery and AJAX.

The most useful part is that the project can start small and grow with your website. Once the basic counter is working, you can turn it into a complete visitor analytics dashboard with charts, filters, daily reports and administrator controls.

If you are working with an older PHP visitor counter tutorial, updating its database layer from deprecated mysql_* functions to MySQLi is also an important modernization step.

The result is a lightweight and understandable project that you can use as a learning exercise or customize for your own PHP website.



Like it? Share with your friends!

0
CodeKool