{"id":316534,"date":"2026-05-26T23:22:50","date_gmt":"2026-05-26T23:22:50","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/insightpulse\/"},"modified":"2026-05-26T23:22:36","modified_gmt":"2026-05-26T23:22:36","slug":"visitstats","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/visitstats\/","author":23503456,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.1.6","stable_tag":"1.1.6","tested":"7.0","requires":"6.2","requires_php":"7.4","requires_plugins":null,"header_name":"VisitStats","header_author":"james333","header_description":"Privacy-first site analytics. No cookies, no Google, data stays in your own database.","assets_banners_color":"fefcfb","last_updated":"2026-05-26 23:22:36","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"","rating":0,"author_block_rating":0,"active_installs":0,"downloads":26,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.1.6":{"tag":"1.1.6","author":"james333","date":"2026-05-26 23:22:36"}},"upgrade_notice":{"1.1.1":"<p>Minor polish \u2014 softened description copy. No functional changes.<\/p>","1.1.0":"<p>Major rename and policy change: all features now free, retention configurable up to 365 days, menu repositioned.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3549863,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3549863,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3549863,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3549863,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.1.6"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3549863,"resolution":"1","location":"assets","locale":"","width":2474,"height":1218},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3549863,"resolution":"2","location":"assets","locale":"","width":2480,"height":1218},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3549863,"resolution":"3","location":"assets","locale":"","width":2470,"height":1218},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3549863,"resolution":"4","location":"assets","locale":"","width":1714,"height":1226},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3549863,"resolution":"5","location":"assets","locale":"","width":1842,"height":1072}},"screenshots":{"1":"The main dashboard with real-time visitors, summary cards, and pageviews chart.","2":"Top pages, sources, devices, and browsers reports.","3":"Top referrers showing the actual external URLs sending traffic.","4":"Settings page with tracking, exclusions, and retention controls.","5":"Feedback page for feature requests and bug reports."}},"plugin_section":[],"plugin_tags":[232,20315,131785,396,521],"plugin_category":[36,54],"plugin_contributors":[264545],"plugin_business_model":[],"class_list":["post-316534","plugin","type-plugin","status-publish","hentry","plugin_tags-analytics","plugin_tags-cookieless","plugin_tags-gdpr","plugin_tags-privacy","plugin_tags-statistics","plugin_category-analytics","plugin_category-security-and-spam-protection","plugin_contributors-james333","plugin_committers-james333"],"banners":{"banner":"https:\/\/ps.w.org\/visitstats\/assets\/banner-772x250.png?rev=3549863","banner_2x":"https:\/\/ps.w.org\/visitstats\/assets\/banner-1544x500.png?rev=3549863","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/visitstats\/assets\/icon-128x128.png?rev=3549863","icon_2x":"https:\/\/ps.w.org\/visitstats\/assets\/icon-256x256.png?rev=3549863","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/visitstats\/assets\/screenshot-1.png?rev=3549863","caption":"The main dashboard with real-time visitors, summary cards, and pageviews chart."},{"src":"https:\/\/ps.w.org\/visitstats\/assets\/screenshot-2.png?rev=3549863","caption":"Top pages, sources, devices, and browsers reports."},{"src":"https:\/\/ps.w.org\/visitstats\/assets\/screenshot-3.png?rev=3549863","caption":"Top referrers showing the actual external URLs sending traffic."},{"src":"https:\/\/ps.w.org\/visitstats\/assets\/screenshot-4.png?rev=3549863","caption":"Settings page with tracking, exclusions, and retention controls."},{"src":"https:\/\/ps.w.org\/visitstats\/assets\/screenshot-5.png?rev=3549863","caption":"Feedback page for feature requests and bug reports."}],"raw_content":"<!--section=description-->\n<p><strong>VisitStats<\/strong> is a lightweight, privacy-first analytics plugin for WordPress. All your data stays in your own WordPress database \u2014 we never see it, no third party sees it.<\/p>\n\n<p><strong>Why VisitStats?<\/strong><\/p>\n\n<ul>\n<li><strong>No cookies, no consent banner needed.<\/strong> Tracking is GDPR-friendly by default.<\/li>\n<li><strong>Self-hosted.<\/strong> All data lives in your WordPress database. No external service, no Automattic, no Google.<\/li>\n<li><strong>Lightweight.<\/strong> Frontend tracker is under 2KB. Loads asynchronously. Won't slow your site.<\/li>\n<li><strong>Zero setup.<\/strong> Install, activate, done. No theme edits, no tag manager, no JS snippets.<\/li>\n<li><strong>Built for WordPress.<\/strong> Reports appear inside your WordPress dashboard \u2014 no separate app to log into.<\/li>\n<\/ul>\n\n<p><strong>Recommended for sites with up to ~10,000 daily pageviews<\/strong> (around 95% of WordPress sites). For very high-traffic sites, consider dedicated analytics services.<\/p>\n\n<p><strong>What you get (all free, all the time):<\/strong><\/p>\n\n<ul>\n<li>Real-time visitor count \u2014 see who's on your site right now<\/li>\n<li>Pageviews, unique visitors, sessions<\/li>\n<li>Top pages<\/li>\n<li>Top traffic sources (direct, search, social, AI, referral)<\/li>\n<li>Top referrers \u2014 actual URLs sending you traffic<\/li>\n<li>Device breakdown (desktop, mobile, tablet)<\/li>\n<li>Browser &amp; operating system detection<\/li>\n<li>Configurable data retention from 1 day up to 1 year<\/li>\n<li>Date range views: today, 7 days, 30 days, 90 days, 1 year<\/li>\n<li>Engagement signals (scroll depth, time on page)<\/li>\n<li>Cookieless visitor identification using daily-rotating salt + SHA-256 hashing<\/li>\n<li>Bot filtering with built-in bot signature detection<\/li>\n<li>Optional administrator \/ logged-in user exclusion<\/li>\n<li>Honors Do Not Track browser signal<\/li>\n<li>Automatic data pruning to keep your database lean<\/li>\n<li>Rate-limited tracking endpoint protects against abuse<\/li>\n<li>IP anonymization before hashing \u2014 actual IPs never stored<\/li>\n<\/ul>\n\n<p><strong>Privacy by design<\/strong><\/p>\n\n<p>VisitStats never:<\/p>\n\n<ul>\n<li>Sets cookies<\/li>\n<li>Stores IP addresses<\/li>\n<li>Sends data to third parties<\/li>\n<li>Fingerprints visitors<\/li>\n<li>Tracks across days<\/li>\n<\/ul>\n\n<p>Visitor identification uses a daily-rotating salt hashed with the (anonymized) IP and User Agent to count unique visits within a 24-hour window. The salt regenerates every 24 hours, making cross-day tracking impossible. This is the same approach used by Plausible Analytics and Fathom Analytics.<\/p>\n\n<p><strong>For developers<\/strong><\/p>\n\n<ul>\n<li>Clean REST API at <code>\/wp-json\/visitstats\/v1\/<\/code><\/li>\n<li>Filter hooks for customizing behavior (rate limiting, bot detection, etc.)<\/li>\n<li>PSR-style class organization<\/li>\n<li>No external dependencies \u2014 pure WordPress core<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin folder to <code>\/wp-content\/plugins\/<\/code> or install via the WordPress plugin directory.<\/li>\n<li>Activate the plugin through the 'Plugins' menu in WordPress.<\/li>\n<li>Visit the new \"VisitStats\" item in your admin sidebar to see your dashboard.<\/li>\n<li>Tracking starts automatically \u2014 no further configuration required.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"is%20this%20really%20gdpr-friendly%3F\"><h3>Is this really GDPR-friendly?<\/h3><\/dt>\n<dd><p>VisitStats is designed to minimize GDPR exposure: no cookies, no IP storage, no fingerprinting, and data stays on your own server. We don't claim \"compliance\" as a legal certainty (that depends on your processing context), but we provide the technical foundations that make compliance achievable without a cookie banner.<\/p><\/dd>\n<dt id=\"will%20this%20slow%20down%20my%20site%3F\"><h3>Will this slow down my site?<\/h3><\/dt>\n<dd><p>For sites up to ~10,000 daily pageviews, no measurable impact. The tracker is under 2KB and uses <code>navigator.sendBeacon()<\/code> so requests never block page interactions. For sites consistently above 10K daily pageviews, we recommend dedicated analytics services.<\/p><\/dd>\n<dt id=\"where%20is%20my%20data%20stored%3F\"><h3>Where is my data stored?<\/h3><\/dt>\n<dd><p>In your own WordPress database. We never see it. There is no cloud component, no SaaS layer, no external service.<\/p><\/dd>\n<dt id=\"will%20my%20database%20get%20huge%3F\"><h3>Will my database get huge?<\/h3><\/dt>\n<dd><p>No. The plugin includes automatic pruning. Raw events are pruned at your configured retention window (default 30 days). Daily aggregates are kept separately and are tiny \u2014 one row per day per metric.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20caching%20plugins%3F\"><h3>Does it work with caching plugins?<\/h3><\/dt>\n<dd><p>Yes. The tracker uses a standard WordPress script and a REST endpoint. Caching plugins won't break it.<\/p><\/dd>\n<dt id=\"can%20i%20run%20this%20alongside%20google%20analytics%3F\"><h3>Can I run this alongside Google Analytics?<\/h3><\/dt>\n<dd><p>Yes. They don't conflict. Many users run both during migration.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20cloudflare%20or%20a%20reverse%20proxy%3F\"><h3>Does it work with Cloudflare or a reverse proxy?<\/h3><\/dt>\n<dd><p>In its current form, the plugin reads <code>REMOTE_ADDR<\/code> for visitor identification. Sites behind Cloudflare or a custom reverse proxy will see all visitors hashed identically, which affects unique-visitor counts. Support for proxy headers is on the roadmap \u2014 submit feedback from the plugin's \"Feedback\" page to prioritize it.<\/p><\/dd>\n<dt id=\"how%20can%20i%20request%20features%3F\"><h3>How can I request features?<\/h3><\/dt>\n<dd><p>There's a \"Feedback\" page inside the plugin with a feature voting form. The most-requested items get worked on first.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.1.6<\/h4>\n\n<ul>\n<li>Properly fixed the PHP 8.1+ ltrim() deprecation: the JavaScript tracker was sending <code>referrer: null<\/code> for direct visits, and WordPress's REST sanitize callbacks ran <code>esc_url_raw(null)<\/code> before our PHP code could intercept. Now the tracker sends empty string, and we use custom null-safe sanitize callbacks server-side as defense in depth.<\/li>\n<\/ul>\n\n<h4>1.1.5<\/h4>\n\n<ul>\n<li>Fixed PHP 8.1+ deprecation warnings when null was passed to esc_url_raw() and ltrim() for direct visits (visitors arriving with no referrer). All URL\/path\/referrer values are now coerced to strings before being passed to WordPress escaping helpers.<\/li>\n<li>Added explicit defaults to REST API parameter definitions so null never reaches the sanitize callback.<\/li>\n<li>Hardened sanitize_path() against null and non-string input.<\/li>\n<\/ul>\n\n<h4>1.1.4<\/h4>\n\n<ul>\n<li>Renamed an internal rate-limit transient key to use the plugin's <code>visitstats_<\/code> prefix (was <code>ip_rl_<\/code>). No user-visible changes.<\/li>\n<\/ul>\n\n<h4>1.1.3<\/h4>\n\n<ul>\n<li>Improved phpcs annotation placement so static analysis tools (Plugin Check, WPCS) correctly recognize the documented exceptions for schema operations in uninstaller and dbDelta in activator. No functional changes.<\/li>\n<\/ul>\n\n<h4>1.1.2<\/h4>\n\n<ul>\n<li>Updated \"Tested up to\" to WordPress 7.0.<\/li>\n<\/ul>\n\n<h4>1.1.1<\/h4>\n\n<ul>\n<li>Polish pass before WordPress.org submission.<\/li>\n<li>Softened description copy to reduce potential trademark concerns.<\/li>\n<li>No functional changes.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Renamed from a previous name to \"VisitStats\" for a cleaner, more descriptive identity.<\/li>\n<li>Made all features unconditionally free and fully functional, matching WordPress.org Plugin Directory guidelines.<\/li>\n<li>Data retention now user-configurable from 1 to 365 days (was previously capped).<\/li>\n<li>All date ranges (today, 7d, 30d, 90d, 1 year) available to everyone.<\/li>\n<li>Engagement \/ scroll-depth tracking now works for all users.<\/li>\n<li>Moved admin menu from position 3 to position 81 (under Settings) to respect WordPress core admin hierarchy.<\/li>\n<li>Replaced upsell page with a Feedback &amp; Feature Requests page.<\/li>\n<\/ul>\n\n<h4>1.0.x<\/h4>\n\n<ul>\n<li>Earlier iterations under previous naming. See full history in the repository.<\/li>\n<\/ul>","raw_excerpt":"Privacy-first site analytics for self-hosted sites. No cookies, no Google, no data leaves your server. Stats live in your own database.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/316534","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=316534"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/james333"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=316534"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=316534"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=316534"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=316534"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=316534"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=316534"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}