Simple Text-Based Hit Counter Script
Text Counter is a lightweight CGI script that outputs page visit counts as plain text, allowing complete styling freedom through CSS. Unlike graphical counters, it doesn't generate images - just a number you can style however you want.
Text Counter is a minimalist alternative to graphical hit counters. Instead of generating an image with digit graphics, it simply outputs the current count as plain text. This gives webmasters complete control over how the counter appears using standard HTML and CSS styling.
The script maintains a simple data file that stores the current count, incrementing it each time the page is loaded. It's designed to work with Server Side Includes (SSI), embedding the count directly into HTML output.
.shtml extension, or your server must be configured to parse .html files for SSI directives.
Text Counter emerged as an elegant solution to several problems webmasters faced with graphical counters in the mid-1990s:
"The primary advantage of a text counter is simplicity. With no graphics library dependencies and minimal server resources, it was often the only option on restrictive shared hosting."
| 1994 | First CGI counters appear on the web |
| 1995 | Popular CGI script archives emerge with Counter scripts |
| 1996-1999 | Peak hit counter era - nearly every personal site had one |
| 2000 | Free counter services emerge (WebCounter, StatCounter) |
| 2005+ | Analytics tools replace simple counters |
| 2010+ | Google Analytics dominates; counters become nostalgic |
Hit counters were a status symbol in the 1990s web. A high visitor count signified popularity and credibility.
Some webmasters would start their counters at high numbers (like 10,000) to appear more established.
The phrase "You are visitor number X" became an iconic element of early web design.
Outputs just the number - no images, no HTML tags. You control all styling with your own CSS.
No image generation means faster execution and lower server resource usage.
Track different pages independently by specifying different data files.
Works on any server with Perl - no graphics libraries or modules required.
Prevents count corruption from simultaneous visitors using file locking.
Use any font, size, color, or effect available in CSS to display your count.
| Feature | Text Counter | Graphical Counter |
|---|---|---|
| Output Format | Plain text number | GIF/PNG image |
| Server Requirements | Just Perl | Perl + GD/ImageMagick |
| Response Size | ~10-20 bytes | ~2-5 KB per image |
| Styling Control | Full CSS control | Limited to digit styles |
| Digit Themes | Use any web font | Pre-made digit images |
| Caching | Cannot be cached | Image can be cached |
| Accessibility | Screen reader friendly | Requires alt text |
| Copy/Paste | Yes | No |
textcounter.pl to your cgi-bin directory.
#!/usr/bin/perl
chmod 755 textcounter.pl and chmod 666 counter.dat
.shtml extension).
<!-- Simple counter -->
<!--#exec cgi="/cgi-bin/textcounter.pl"-->
<!-- With styling -->
You are visitor number <strong><!--#exec cgi="/cgi-bin/textcounter.pl"--></strong>
<!-- With custom CSS -->
<span class="visitor-count"><!--#exec cgi="/cgi-bin/textcounter.pl"--></span>
<style>
.visitor-count {
font-size: 2rem;
font-family: 'Courier New', monospace;
color: #00ff00;
background: #000;
padding: 5px 15px;
border-radius: 5px;
}
</style>
<!-- Multiple counters for different pages -->
<!--#exec cgi="/cgi-bin/textcounter.pl?page=home"-->
<!--#exec cgi="/cgi-bin/textcounter.pl?page=about"-->
#!/usr/bin/perl
use strict;
use warnings;
use Fcntl qw(:flock);
# Configuration
my $count_file = '/path/to/counter.dat';
# Initialize count
my $count = 0;
# Read and increment counter
if (open(my $fh, '+<', $count_file)) {
flock($fh, LOCK_EX);
$count = <$fh> || 0;
chomp($count);
$count++;
seek($fh, 0, 0);
truncate($fh, 0);
print $fh "$count\n";
close($fh);
}
elsif (open(my $fh, '>', $count_file)) {
$count = 1;
print $fh "1\n";
close($fh);
}
# Output
print "Content-type: text/plain\n\n";
print $count;
exit 0;
<?php
/**
* Text Counter - PHP Version
* Simple text-based hit counter
*/
$count_file = __DIR__ . '/counter.txt';
// Read current count
$count = 0;
if (file_exists($count_file)) {
$count = (int) file_get_contents($count_file);
}
// Increment
$count++;
// Save (with file locking)
$fp = fopen($count_file, 'w');
if (flock($fp, LOCK_EX)) {
fwrite($fp, $count);
flock($fp, LOCK_UN);
}
fclose($fp);
// Output plain text
header('Content-Type: text/plain');
echo $count;
?>
<?php
// Inline counter function
function getVisitorCount($file = 'counter.txt') {
$count = file_exists($file) ? (int) file_get_contents($file) : 0;
$count++;
file_put_contents($file, $count, LOCK_EX);
return $count;
}
?>
<!-- Usage in HTML -->
<p>You are visitor number <strong><?= number_format(getVisitorCount()) ?></strong></p>
/**
* Client-side counter display with number animation
* Note: Actual counting must happen server-side
*/
class AnimatedCounter {
constructor(element, targetValue, options = {}) {
this.element = document.querySelector(element);
this.target = targetValue;
this.options = {
duration: 2000,
separator: ',',
...options
};
this.animate();
}
animate() {
const start = 0;
const startTime = performance.now();
const updateCounter = (currentTime) => {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / this.options.duration, 1);
// Easing function
const easeOut = 1 - Math.pow(1 - progress, 3);
const currentValue = Math.floor(start + (this.target - start) * easeOut);
this.element.textContent = currentValue.toLocaleString();
if (progress < 1) {
requestAnimationFrame(updateCounter);
}
};
requestAnimationFrame(updateCounter);
}
}
// Usage: Fetch count from server and animate
fetch('/api/counter')
.then(response => response.text())
.then(count => {
new AnimatedCounter('#visitor-count', parseInt(count));
});
While hit counters served their purpose in the 1990s, modern websites typically use analytics tools that provide much more insight than a simple number:
Lightweight, privacy-friendly, no cookies, GDPR compliant. Open source and can be self-hosted.
Self-hosted, privacy-focused, simple and fast. Modern alternative to Google Analytics.
Cookie-free, GDPR compliant, beautiful dashboard. Used by GitHub, IBM.
No tracking, no cookies, minimal JavaScript. Truly privacy-focused.
One of the oldest counter services still running. Includes invisible counter option.
Simple, privacy-first analytics. No cookies, no tracking.
Badge-style hit counter for GitHub READMEs and websites.
Simple visitor badge for markdown files and websites.
| Feature | Text Counter (1990s) | Modern Analytics (2024) |
|---|---|---|
| Total page views | ||
| Unique visitors | ||
| Geographic data | ||
| Referrer tracking | ||
| Real-time data | ||
| No external dependencies | Self-hosted only | |
| Visible counter on page | Optional widget |
Main Perl script that outputs the counter value
Installation and configuration instructions
$count =~ s/(\d)(?=(\d{3})+(\D|$))/$1,/g; or use JavaScript after the fact with parseInt(num).toLocaleString().