Overview
StatCounter's event tracking capabilities are fundamentally different from modern event-driven analytics platforms. Rather than supporting custom events with properties and parameters, StatCounter focuses on automatic tracking of page views, downloads, and exit links.
What StatCounter Tracks
Automatic Tracking:
- Page views and pageview sequences
- File downloads (PDF, DOC, ZIP, etc.)
- Exit links (outbound clicks)
- Referrer information
- Visitor navigation paths
Limited Support For:
- Custom events (workarounds required)
- Form submissions (via page redirects)
- Button clicks (manual tracking needed)
- Video interactions (not supported)
- Scroll depth (not supported)
Event Tracking Philosophy
StatCounter uses a page-view-centric model where:
- Each page view is the primary unit of measurement
- Events are tracked as page views or automatic behaviors
- Custom tracking requires creative workarounds
- Focus is on visitor journeys rather than discrete events
Page View Tracking
Automatic Page View Tracking
Once the StatCounter code is installed, all page views are tracked automatically:
<!-- StatCounter automatically tracks this page -->
<!DOCTYPE html>
<html>
<head>
<title>Product Page</title>
</head>
<body>
<h1>Widget Pro</h1>
<script type="text/javascript">
var sc_project=12345678;
var sc_invisible=1;
var sc_security="abcd1234";
</script>
<script type="text/javascript"
src="https://www.statcounter.com/counter/counter.js" async></script>
</body>
</html>
Manual Page View Tracking
For Single Page Applications (SPAs) where content changes without page reloads:
// Trigger page view on route change
function trackPageView() {
if (typeof _statcounter !== 'undefined' && _statcounter.record_pageview) {
_statcounter.record_pageview();
} else {
console.warn('StatCounter not loaded');
}
}
// Call when route changes
window.addEventListener('popstate', trackPageView);
SPA Framework Integration
React Router:
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
function usePageTracking() {
const location = useLocation();
useEffect(() => {
if (typeof _statcounter !== 'undefined') {
_statcounter.record_pageview();
}
}, [location]);
}
// Use in your App component
function App() {
usePageTracking();
return <Router>{/* routes */}</Router>;
}
Vue Router:
router.afterEach((to, from) => {
if (typeof _statcounter !== 'undefined') {
_statcounter.record_pageview();
}
});
Angular:
import { Router, NavigationEnd } from '@angular/router';
constructor(private router: Router) {
router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
if (typeof (window as any)._statcounter !== 'undefined') {
(window as any)._statcounter.record_pageview();
}
}
});
}
Download Tracking
StatCounter can automatically track file downloads when properly configured.
Enable Download Tracking
- Log in to StatCounter dashboard
- Navigate to Config > Configure Stats
- Enable "Track Downloads"
- Select file types to track:
- Documents: PDF, DOC, DOCX, XLS, XLSX, PPT, PPTX
- Archives: ZIP, RAR, TAR, GZ
- Media: MP3, MP4, AVI, MOV
- Custom extensions
How Download Tracking Works
<!-- These links are automatically tracked -->
<a href="/files/whitepaper.pdf">Download Whitepaper (PDF)</a>
<a href="/downloads/data.xlsx">Download Spreadsheet</a>
<a href="/resources/presentation.pptx">Get Presentation</a>
When a user clicks these links:
- StatCounter intercepts the click
- Records the download event
- Logs: filename, file type, source page, visitor info
- Allows download to proceed
Viewing Download Data
In StatCounter Dashboard:
- Navigate to Popular Downloads report
- See list of most downloaded files
- View download counts and trends
- Filter by date range
Download Event Data
For each download, StatCounter records:
- Filename and extension
- Source page URL
- Timestamp
- Visitor information (location, browser, etc.)
- Referrer
Exit Link Tracking
Track when visitors click links that take them away from your site.
Enable Exit Link Tracking
- StatCounter Dashboard > Config > Configure Stats
- Enable "Track Exit Links"
- Exit links are now monitored automatically
What Gets Tracked
<!-- Automatically tracked as exit links -->
<a href="https://external-site.com/page">External Resource</a>
<a href="https://partner.com">Partner Site</a>
<a href="https://social-media.com/share">Share on Social</a>
<!-- NOT tracked as exit links (same domain) -->
<a href="/about">About Us</a>
<a href="https://yourdomain.com/contact">Contact</a>
Exit Link Reports
Access Exit Link Data:
- Dashboard > Exit Links report
- View top exit destinations
- See which pages generate most exits
- Analyze exit patterns
Use Cases:
- Monitor outbound referral links
- Track social media share clicks
- Measure partner link engagement
- Identify content sources users visit
Virtual Page Views
Track events by creating virtual page views.
Concept
Since StatCounter is page-view-centric, create "virtual" page views to represent events:
function trackVirtualPage(pageName) {
if (typeof _statcounter !== 'undefined') {
// Temporarily change the page title
var originalTitle = document.title;
document.title = pageName;
// Trigger page view
_statcounter.record_pageview();
// Restore original title
setTimeout(function() {
document.title = originalTitle;
}, 100);
}
}
Use Cases
Modal/Popup Views:
// Track modal open as virtual page view
document.getElementById('openModal').addEventListener('click', function() {
trackVirtualPage('Modal: Contact Form Opened');
// Open modal
showModal();
});
Tab Switches:
// Track tab changes
document.querySelectorAll('.tab').forEach(function(tab) {
tab.addEventListener('click', function() {
var tabName = this.getAttribute('data-tab-name');
trackVirtualPage('Tab: ' + tabName);
});
});
Form Submissions:
document.getElementById('contactForm').addEventListener('submit', function(e) {
e.preventDefault();
// Track as virtual page
trackVirtualPage('Form Submitted: Contact');
// Submit form
this.submit();
});
AJAX Content Loads:
function loadContent(section) {
// Track content load
trackVirtualPage('Content Loaded: ' + section);
// Load content via AJAX
fetch('/api/content/' + section)
.then(response => response.json())
.then(data => updateUI(data));
}
Custom Event Workarounds
Since StatCounter doesn't have native custom event tracking, use these strategies:
Method 1: URL Parameters
Add tracking data to URLs:
function trackEvent(category, action, label) {
var trackingUrl = window.location.pathname +
'?category=' + encodeURIComponent(category) +
'&action=' + encodeURIComponent(action) +
'&label=' + encodeURIComponent(label);
// Update URL
window.history.pushState({}, '', trackingUrl);
// Trigger tracking
if (typeof _statcounter !== 'undefined') {
_statcounter.record_pageview();
}
// Clean URL after tracking
setTimeout(function() {
window.history.pushState({}, '', window.location.pathname);
}, 500);
}
// Usage
document.getElementById('signup').addEventListener('click', function() {
trackEvent('user_action', 'signup_click', 'header_button');
});
Method 2: Hidden Tracking Pages
Create dedicated pages for specific events:
<!-- /tracking/button-clicked.html -->
<!DOCTYPE html>
<html>
<head>
<title>Event: Button Clicked</title>
<script type="text/javascript">
var sc_project=12345678;
var sc_invisible=1;
var sc_security="abcd1234";
</script>
<script type="text/javascript"
src="https://www.statcounter.com/counter/counter.js" async></script>
</head>
<body></body>
</html>
// Load tracking page in hidden iframe
function trackCustomEvent(eventName) {
var iframe = document.createElement('iframe');
iframe.style.display = 'none';
iframe.style.position = 'absolute';
iframe.src = '/tracking/' + eventName + '.html';
document.body.appendChild(iframe);
// Remove iframe after tracking
setTimeout(function() {
document.body.removeChild(iframe);
}, 3000);
}
// Usage
document.getElementById('purchaseButton').addEventListener('click', function() {
trackCustomEvent('purchase-initiated');
});
Method 3: Page Title Variations
Encode event data in page titles:
function trackAction(actionName, actionValue) {
var originalTitle = document.title;
var eventTitle = '[Event] ' + actionName + ': ' + actionValue;
document.title = eventTitle;
if (typeof _statcounter !== 'undefined') {
_statcounter.record_pageview();
}
setTimeout(function() {
document.title = originalTitle;
}, 200);
}
// Usage
trackAction('Video Play', 'Product Demo Video');
trackAction('Add to Cart', 'Widget Pro');
trackAction('Filter Applied', 'Price: $50-$100');
Button and Click Tracking
Track button clicks and interactions:
Basic Click Tracking
// Track any button click
document.querySelectorAll('[data-track-click]').forEach(function(button) {
button.addEventListener('click', function() {
var eventName = this.getAttribute('data-track-click');
trackVirtualPage('Click: ' + eventName);
});
});
<!-- HTML markup -->
<button data-track-click="Subscribe Button">Subscribe</button>
<button data-track-click="Add to Cart">Add to Cart</button>
<a href="#" data-track-click="Learn More Link">Learn More</a>
CTA Tracking
// Track call-to-action clicks
function trackCTA(ctaName, ctaLocation) {
trackVirtualPage('CTA: ' + ctaName + ' | ' + ctaLocation);
}
// Usage
document.getElementById('headerCTA').addEventListener('click', function() {
trackCTA('Sign Up Free', 'Header');
});
document.getElementById('footerCTA').addEventListener('click', function() {
trackCTA('Sign Up Free', 'Footer');
});
Form Tracking
Form Submission Tracking
Track form completions:
function setupFormTracking(formId, formName) {
var form = document.getElementById(formId);
form.addEventListener('submit', function(e) {
e.preventDefault();
// Track submission
trackVirtualPage('Form Submitted: ' + formName);
// Allow submission to proceed
setTimeout(function() {
form.submit();
}, 500);
});
}
// Setup tracking
setupFormTracking('contactForm', 'Contact');
setupFormTracking('newsletterForm', 'Newsletter Signup');
setupFormTracking('quoteForm', 'Request Quote');
Form Abandonment
Track when users start but don't complete forms:
var formStarted = false;
var formCompleted = false;
document.getElementById('contactForm').addEventListener('focus', function() {
if (!formStarted) {
formStarted = true;
trackVirtualPage('Form Started: Contact');
}
}, true);
document.getElementById('contactForm').addEventListener('submit', function() {
formCompleted = true;
trackVirtualPage('Form Completed: Contact');
});
window.addEventListener('beforeunload', function() {
if (formStarted && !formCompleted) {
trackVirtualPage('Form Abandoned: Contact');
}
});
Validation
Verify Page View Tracking
Browser Console Test:
// Open console and run
if (typeof _statcounter !== 'undefined') {
console.log('StatCounter loaded');
_statcounter.record_pageview();
console.log('Page view tracked');
} else {
console.error('StatCounter not loaded');
}
Check Dashboard:
- Trigger tracking event
- Wait 10-15 minutes
- Check Recent Visitor Activity
- Verify your event appears
Verify Download Tracking
- Click a download link on your site
- Wait 10-15 minutes
- Check Popular Downloads report
- Confirm download appears in list
Verify Exit Link Tracking
- Click an external link
- Wait 10-15 minutes
- Check Exit Links report
- Verify click was recorded
Common Tracking Issues
| Issue | Cause | Solution |
|---|---|---|
| Events not appearing | Tracking not firing | Check console for errors, verify _statcounter defined |
| Delayed data | Normal processing time | Wait up to 30 minutes for data |
| SPA routes not tracked | No manual tracking | Implement route change tracking |
| Downloads not counted | Tracking disabled | Enable in dashboard settings |
| Virtual pages not showing | Title not changed before tracking | Update title before calling record_pageview() |
Best Practices
Naming Conventions
Use clear, consistent naming:
// Good naming
trackVirtualPage('Modal: Sign Up Form');
trackVirtualPage('Tab: Pricing Details');
trackVirtualPage('Filter: Category > Electronics');
// Avoid
trackVirtualPage('thing1');
trackVirtualPage('event');
Event Categorization
Structure virtual page names hierarchically:
// Category: Action: Details
trackVirtualPage('Video: Play: Product Demo');
trackVirtualPage('Form: Submit: Contact');
trackVirtualPage('Button: Click: Add to Cart');
trackVirtualPage('Link: Click: External > Partner Site');
Timing
Give tracking time to fire before navigation:
button.addEventListener('click', function(e) {
e.preventDefault();
// Track event
trackVirtualPage('Button: Purchase');
// Wait before navigating
var href = this.href;
setTimeout(function() {
window.location.href = href;
}, 500);
});
Testing
Test tracking implementation:
// Debug mode
var DEBUG_TRACKING = true;
function trackVirtualPage(pageName) {
if (DEBUG_TRACKING) {
console.log('Tracking:', pageName);
}
if (typeof _statcounter !== 'undefined') {
var originalTitle = document.title;
document.title = pageName;
_statcounter.record_pageview();
setTimeout(function() {
document.title = originalTitle;
}, 100);
}
}
Limitations
What You Cannot Track
StatCounter cannot natively track:
- Custom events with properties
- Event parameters and values
- User engagement metrics (time, scroll depth)
- Video play/pause events
- E-commerce transaction details
- Custom user properties
- Event funnels
- Multi-step interactions
When to Use Alternatives
Consider other platforms for:
- Complex event tracking: Google Analytics 4, Mixpanel
- E-commerce: Enhanced ecommerce platforms
- Product analytics: Amplitude, Heap
- User behavior: Hotjar, FullStory
Hybrid Approach
Use multiple tools together:
<!-- StatCounter for visitor stats -->
<script>/* StatCounter code */</script>
<!-- Google Analytics for events -->
<script>/* GA4 code */</script>
Troubleshooting
Events Not Recording
Check StatCounter Loaded:
setTimeout(function() {
if (typeof _statcounter === 'undefined') {
console.error('StatCounter not loaded');
}
}, 3000);
Verify Tracking Calls:
// Add logging
var originalRecordPageview = _statcounter.record_pageview;
_statcounter.record_pageview = function() {
console.log('StatCounter tracking fired');
return originalRecordPageview.apply(this, arguments);
};
Downloads Not Tracking
- Confirm download tracking enabled in dashboard
- Check file extensions in allowed list
- Verify links use
<a href>tags - Ensure links point to actual files
Data Delays
- Normal delay: 5-30 minutes
- Check correct project in dashboard
- Verify timezone settings
- Wait adequate time before concluding failure