{"id":305232,"date":"2026-06-29T08:54:49","date_gmt":"2026-06-29T08:54:49","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/easy-server-side-tracking\/"},"modified":"2026-08-24T12:45:54","modified_gmt":"2026-08-24T12:45:54","slug":"jacht-easy-server-side-tracking","status":"publish","type":"plugin","link":"https:\/\/fr.wordpress.org\/plugins\/jacht-easy-server-side-tracking\/","author":23487422,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"5.4.3","stable_tag":"5.4.3","tested":"7.0.4","requires":"5.2","requires_php":"7.2","requires_plugins":null,"header_name":"Easy Server Side Tracking","header_author":"Jacht.Digital Marketing","header_description":"Server-side GA4 tracking via a managed ingestion endpoint. Bypasses content blockers and improves data accuracy. Connect your free account from the settings page.","assets_banners_color":"144042","last_updated":"2026-08-24 12:45:54","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/easyserversidetracking.com\/","header_author_uri":"https:\/\/jacht.digital\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":316,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"5.2.1":{"tag":"5.2.1","author":"jachtdigital2026","date":"2026-06-29 08:54:34"},"5.2.2":{"tag":"5.2.2","author":"jachtdigital2026","date":"2026-07-01 07:35:03"},"5.2.3":{"tag":"5.2.3","author":"jachtdigital2026","date":"2026-07-01 08:02:49"},"5.2.4":{"tag":"5.2.4","author":"jachtdigital2026","date":"2026-07-01 08:19:45"},"5.2.5":{"tag":"5.2.5","author":"jachtdigital2026","date":"2026-07-01 08:28:59"},"5.2.6":{"tag":"5.2.6","author":"jachtdigital2026","date":"2026-07-01 09:27:07"},"5.3.0":{"tag":"5.3.0","author":"jachtdigital2026","date":"2026-08-17 11:56:12"},"5.3.1":{"tag":"5.3.1","author":"jachtdigital2026","date":"2026-08-24 08:52:21"},"5.3.2":{"tag":"5.3.2","author":"jachtdigital2026","date":"2026-08-24 09:26:42"},"5.4.0":{"tag":"5.4.0","author":"jachtdigital2026","date":"2026-08-24 11:39:24"},"5.4.1":{"tag":"5.4.1","author":"jachtdigital2026","date":"2026-08-24 12:24:39"},"5.4.2":{"tag":"5.4.2","author":"jachtdigital2026","date":"2026-08-24 12:39:09"},"5.4.3":{"tag":"5.4.3","author":"jachtdigital2026","date":"2026-08-24 12:45:54"}},"upgrade_notice":{"5.1.2":"<p>The License page now has a persistent consent panel. If you installed before 5.1.0 you&#039;ll see an unticked consent checkbox \u2014 tick it to record explicit consent and re-enable the Re-provision button. Tracking is not interrupted.<\/p>","5.1.0":"<p>WordPress.org compliance release: explicit opt-in for provisioning, logs moved to uploads directory, stricter sanitization and unique prefixes. No tracking behavior change.<\/p>","5.0.4":"<p>Fixes a tracker init TypeError introduced by 5.0.3&#039;s orphaned method calls. Upgrading is required for tracking to function. Cache-buster bump.<\/p>","5.0.3":"<p>Privacy &amp; security: removes third-party geo-IP fallbacks, adds CSRF protection on the encryption-key endpoint, prefixes the legacy <code>event_count<\/code> option, and documents external services. No tracking behavior change. Migration runs automatically on next admin pageload.<\/p>","5.0.2":"<p>Removes client-side event-limit enforcement; quota is now exclusively server-side. License page fix.<\/p>","5.0.0":"<p><strong>Major refactor:<\/strong> the plugin no longer requires a customer-hosted Cloudflare Worker. Events post directly to the managed ingestion endpoint. Old event queue tables are dropped on upgrade. Test thoroughly after upgrading.<\/p>"},"ratings":[],"assets_icons":{"icon-256x256.png":{"filename":"icon-256x256.png","revision":3592261,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3592261,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3592261,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["5.2.1","5.2.2","5.2.3","5.2.4","5.2.5","5.2.6","5.3.0","5.3.1","5.3.2","5.4.0","5.4.1","5.4.2","5.4.3"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[],"plugin_tags":[232,986,5926,550,286],"plugin_category":[36,45],"plugin_contributors":[269386],"plugin_business_model":[],"class_list":["post-305232","plugin","type-plugin","status-publish","hentry","plugin_tags-analytics","plugin_tags-conversion-tracking","plugin_tags-server-side","plugin_tags-tracking","plugin_tags-woocommerce","plugin_category-analytics","plugin_category-ecommerce","plugin_contributors-jachtdigital2026","plugin_committers-jachtdigital2026"],"banners":{"banner":"https:\/\/ps.w.org\/jacht-easy-server-side-tracking\/assets\/banner-772x250.png?rev=3592261","banner_2x":"https:\/\/ps.w.org\/jacht-easy-server-side-tracking\/assets\/banner-1544x500.png?rev=3592261","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/jacht-easy-server-side-tracking\/assets\/icon-256x256.png?rev=3592261","icon_2x":"https:\/\/ps.w.org\/jacht-easy-server-side-tracking\/assets\/icon-256x256.png?rev=3592261","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p><strong>Ad blockers and browser privacy settings block Google Analytics on a large share of your visits \u2014 commonly 30-50%.<\/strong> Those visitors still browse, still add to cart, and still buy. You just never see them. Your reports under-count traffic, your best-converting channels look worse than they are, and every decision you make from that data is made from an incomplete picture.<\/p>\n\n<p>Easy Server Side Tracking closes that gap. Instead of the browser talking straight to <code>google-analytics.com<\/code> \u2014 the request blockers are built to recognise \u2014 events go to a tracking endpoint that isn't on any blocklist, and are forwarded to Google Analytics 4 from there.<\/p>\n\n<p><strong>What you get back<\/strong><\/p>\n\n<ul>\n<li>The visits, add-to-carts and purchases that were previously invisible<\/li>\n<li>Channel and campaign reporting based on close to all of your traffic, not the fraction that got through<\/li>\n<li>WooCommerce revenue that matches your actual orders far more closely<\/li>\n<li>A dashboard showing every event received, so you can see what is arriving instead of guessing<\/li>\n<\/ul>\n\n<h4>How it works<\/h4>\n\n<ol>\n<li>A small script collects the event in the visitor's browser \u2014 event name, page URL, referrer, and anonymous client and session IDs.<\/li>\n<li>It posts to <code>collect.easyserversidetracking.com<\/code> over HTTPS, signed with a short-lived token so only your site can send as your site.<\/li>\n<li>The endpoint validates the request, filters obvious bots, and <strong>forwards the event straight on to Google Analytics 4<\/strong> using Google's Measurement Protocol.<\/li>\n<li>A copy is kept so you can see your own event stream on the dashboard.<\/li>\n<\/ol>\n\n<p><strong>We are a proxy, not a data broker.<\/strong> Your analytics data is forwarded to your own Google Analytics property and kept so you can look at it. It is not sold, not shared with third parties, not used to build profiles, and not combined across customers.<\/p>\n\n<h4>What we do and do not store<\/h4>\n\n<p>Stored per event: event name, page URL, referrer, user agent, country, consent state, anonymous client and session IDs, and a bot score.<\/p>\n\n<p><strong>Raw IP addresses are never stored.<\/strong> The IP is hashed with a salt that rotates every day and truncated, which is enough to rate-limit abuse and nothing more \u2014 the hash cannot be reversed, and the same visitor produces a different hash tomorrow.<\/p>\n\n<p>Events are deleted automatically according to your plan's retention period.<\/p>\n\n<h4>Privacy and consent<\/h4>\n\n<ul>\n<li><strong>Nothing is sent anywhere until you explicitly connect.<\/strong> Installing and activating the plugin contacts no external service. You see exactly what will be shared, tick a box, and press a button \u2014 until then the plugin is inert.<\/li>\n<li>The visitor's real consent choice is read from Google Consent Mode and passed through with every event, rather than assumed.<\/li>\n<li>When consent is denied, data is anonymised before it goes anywhere: identifiers are dropped and location is reduced. You keep a basic visit count and nothing personal.<\/li>\n<li>Works with your existing cookie banner. Complianz, Cookiebot and Iubenda are detected automatically; anything else can be pointed at your accept and reject buttons.<\/li>\n<\/ul>\n\n<h4>What you need<\/h4>\n\n<ul>\n<li>A <strong>GA4 Measurement ID<\/strong> and a <strong>Measurement Protocol API Secret<\/strong> from your Google Analytics property. Both are required \u2014 without them events reach the service but cannot be forwarded to Google, so nothing appears in your reports.<\/li>\n<li>Nothing else. No Google Tag Manager, no server to rent, no container to configure.<\/li>\n<\/ul>\n\n<h4>Setup<\/h4>\n\n<p>A guided setup walks you through it: agree to what is shared and create your free account, enter your two Google Analytics credentials, tell us which cookie banner you use, and answer two questions so the right tracking settings are applied. Most sites are done in a few minutes.<\/p>\n\n<h4>Features<\/h4>\n\n<ul>\n<li>WooCommerce tracking out of the box: <code>view_item<\/code>, <code>add_to_cart<\/code>, <code>begin_checkout<\/code>, shipping and payment steps, and <code>purchase<\/code><\/li>\n<li>Click, scroll, engagement and form-submission tracking<\/li>\n<li>Server-side bot filtering, so automated traffic does not pollute your reports<\/li>\n<li>Consent-aware anonymisation built in<\/li>\n<li>Event dashboard with your live event stream<\/li>\n<li>Free tier: 10,000 events per month, fully functional, indefinitely<\/li>\n<\/ul>\n\n<h4>Pricing<\/h4>\n\n<p>The free tier is not a trial and does not expire. Paid plans raise the monthly event allowance and extend dashboard retention; they are bought on the dashboard and applied to your site automatically. <strong>No licence key is ever entered in WordPress, and no plugin feature is locked, disabled or degraded on the free tier.<\/strong><\/p>\n\n<h3>External services<\/h3>\n\n<p>This plugin connects to the following external services. Each is necessary for the functionality described and is only contacted as documented below.<\/p>\n\n<h4>collect.easyserversidetracking.com (managed ingestion worker)<\/h4>\n\n<ul>\n<li><strong>Provider:<\/strong> Easy Server Side Tracking (operated by Jacht.Digital Marketing).<\/li>\n<li><strong>What it does:<\/strong> Receives event posts from the in-browser tracker, normalizes and deduplicates them, applies bot filtering and consent rules, then forwards to Google Analytics 4 and stores a copy for the dashboard.<\/li>\n<li><strong>What is sent:<\/strong> Each event payload \u2014 event name, page URL, page title, referrer, anonymized client\/session IDs, consent state, event-specific parameters, and the visitor IP. The IP is used for country lookup and rate limiting and is <strong>never stored in raw form<\/strong> \u2014 only as a hash of the IP with a salt that rotates daily, truncated, which cannot be reversed and does not link the same visitor across days.<\/li>\n<li><strong>When:<\/strong> Every time a tracked event fires in the visitor's browser.<\/li>\n<li><strong>Required:<\/strong> Yes \u2014 the plugin's core function is to send events here.<\/li>\n<li><strong>Terms of service:<\/strong> https:\/\/dashboard.easyserversidetracking.com\/terms-of-service\/<\/li>\n<li><strong>Privacy policy:<\/strong> https:\/\/dashboard.easyserversidetracking.com\/privacy-policy\/<\/li>\n<\/ul>\n\n<h4>dashboard.easyserversidetracking.com (management &amp; provisioning server)<\/h4>\n\n<ul>\n<li><strong>Provider:<\/strong> Easy Server Side Tracking (operated by Jacht.Digital Marketing).<\/li>\n<li><strong>What it does:<\/strong> Provisions a site ID and signing secret for this site so the ingestion worker will accept its events. Your plan, usage, and limits are managed here when you log in to the dashboard.<\/li>\n<li><strong>What is sent:<\/strong> Site URL and admin email (during provisioning \/ re-provisioning only), and the site ID.<\/li>\n<li><strong>When:<\/strong> Only when you click <strong>Create free account<\/strong> or <strong>Re-provision<\/strong>. Activating the plugin sends nothing.<\/li>\n<li><strong>Required:<\/strong> Yes, but only once you choose to connect. Activation alone sends nothing; the account is created when you press <strong>Create free account<\/strong> during setup.<\/li>\n<li><strong>Terms of service:<\/strong> https:\/\/dashboard.easyserversidetracking.com\/terms-of-service\/<\/li>\n<li><strong>Privacy policy:<\/strong> https:\/\/dashboard.easyserversidetracking.com\/privacy-policy\/<\/li>\n<\/ul>\n\n<h4>Google Analytics 4 (Measurement Protocol)<\/h4>\n\n<ul>\n<li><strong>Provider:<\/strong> Google LLC.<\/li>\n<li><strong>What it does:<\/strong> Receives analytics events forwarded by the managed worker (or, when configured locally, sent by the WordPress site directly).<\/li>\n<li><strong>What is sent:<\/strong> GA4 Measurement Protocol payloads \u2014 event name, parameters, client_id, optional user_id, optional consent flags. Sent to <code>https:\/\/www.google-analytics.com\/g\/collect<\/code> or <code>https:\/\/www.google-analytics.com\/mp\/collect<\/code>.<\/li>\n<li><strong>When:<\/strong> Every event the worker forwards (or every event your WP site forwards in direct-mode).<\/li>\n<li><strong>Required:<\/strong> Yes if you want events to appear in GA4. The plugin does not function as an analytics tool without GA4 (or another Measurement Protocol target).<\/li>\n<li><strong>Terms of service:<\/strong> https:\/\/marketingplatform.google.com\/about\/analytics\/terms\/us\/<\/li>\n<li><strong>Privacy policy:<\/strong> https:\/\/policies.google.com\/privacy<\/li>\n<\/ul>\n\n<h4>googletagmanager.com (gtag.js)<\/h4>\n\n<ul>\n<li><strong>Provider:<\/strong> Google LLC.<\/li>\n<li><strong>What it does:<\/strong> Serves the <code>gtag.js<\/code> library to the visitor's browser for client-side GA4 measurement.<\/li>\n<li><strong>What is sent:<\/strong> Standard <code>gtag.js<\/code> telemetry while the script is loaded (page views, automatic events). Its measurement requests are routed through your own site rather than straight to Google.<\/li>\n<li><strong>When:<\/strong> On every pageload, <strong>after<\/strong> the visitor has given consent. No request is made before consent, and none is made at all until you have connected your site.<\/li>\n<li><strong>Required:<\/strong> Yes. <code>gtag.js<\/code> provides the GA4 session and engagement signals the plugin cannot reproduce on its own.<\/li>\n<li><strong>Terms of service:<\/strong> https:\/\/marketingplatform.google.com\/about\/analytics\/terms\/us\/<\/li>\n<li><strong>Privacy policy:<\/strong> https:\/\/policies.google.com\/privacy<\/li>\n<\/ul>\n\n<h3>Privacy<\/h3>\n\n<p>This plugin does not collect or store personal data on the WordPress site itself. All event data is sent to the external services listed above and stored there subject to those services' privacy policies.<\/p>\n\n<p>The plugin stores the following non-personal data in WordPress options for its own operation:<\/p>\n\n<ul>\n<li><code>esst_site_id<\/code> \u2014 the site identifier returned by the management server.<\/li>\n<li><code>esst_signing_secret<\/code> \u2014 the HMAC signing secret for the managed ingestion endpoint (encrypted at rest).<\/li>\n<li><code>esst_collect_url<\/code>, <code>esst_plan_summary<\/code> \u2014 operational state from the management server (collect endpoint URL and the plan name shown in the admin).<\/li>\n<li><code>jachtsst_user_opt_in_at<\/code>, <code>jachtsst_user_opt_in_by<\/code>, <code>jachtsst_user_opt_in_text<\/code> \u2014 the record of who agreed to the data sharing, when, and the exact wording they agreed to. This is kept so the consent can be evidenced later, and includes the WordPress user ID of the administrator who ticked the box. It is never sent anywhere.<\/li>\n<li><code>jachtsst_setup_completed_at<\/code>, <code>jachtsst_cmp_choice<\/code> \u2014 setup progress, so the guided setup does not reappear.<\/li>\n<\/ul>\n\n<p>No cookies are set by the plugin itself; the in-browser tracker uses a first-party cookie named <code>_ga<\/code> (the standard GA4 client identifier) when present.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Install the plugin from <strong>Plugins \u2192 Add New<\/strong>, or upload the folder to <code>\/wp-content\/plugins\/<\/code>.<\/li>\n<li>Activate it. <strong>Nothing is transmitted at this point<\/strong> \u2014 the plugin does not contact any external service until you ask it to.<\/li>\n<li>The guided setup opens automatically. Step one shows exactly what will be shared and asks you to agree before your free account is created.<\/li>\n<li>Enter your GA4 Measurement ID and Measurement Protocol API Secret. Both are in Google Analytics under <strong>Admin \u2192 Data streams \u2192 your web stream<\/strong>.<\/li>\n<li>Choose your cookie banner, answer two short questions about how you want tracking configured, and you are done.<\/li>\n<\/ol>\n\n<p>To check data is arriving, open <strong>Realtime<\/strong> in Google Analytics and load a page on your site.<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"how%20do%20i%20set%20up%20and%20connect%20my%20site%3F\"><h3>How do I set up and connect my site?<\/h3><\/dt>\n<dd><ol>\n<li>Install and activate the plugin.<\/li>\n<li>Go to <strong>Easy SST \u2192 Connection<\/strong> and click <strong>Create free account<\/strong>. This sends your site URL and admin email to easyserversidetracking.com and provisions your site (you'll see a <strong>Site ID<\/strong> appear on the Connection page). Tracking begins on the free tier.<\/li>\n<li>Your site is automatically linked to the dashboard account whose email matches the WordPress admin email used at step 2. So if you sign in to https:\/\/dashboard.easyserversidetracking.com\/ with that same email, your site already appears under your account \u2014 nothing else to do.<\/li>\n<li>If your dashboard account uses a <em>different<\/em> email, link the site manually: on the dashboard go to <strong>Account \u2192 Websites \u2192 Add site<\/strong>, paste the <strong>Site ID<\/strong> shown on the plugin's Connection page, and click <strong>Add site<\/strong>. The Site ID is what proves the site is yours.<\/li>\n<\/ol><\/dd>\n<dt id=\"how%20do%20i%20upgrade%2C%20or%20change%20a%20site%27s%20plan%3F\"><h3>How do I upgrade, or change a site's plan?<\/h3><\/dt>\n<dd><p>Plans are managed entirely on the dashboard \u2014 you never enter a license key in WordPress. Buy or change a plan at https:\/\/dashboard.easyserversidetracking.com\/, then on <strong>Account \u2192 Websites<\/strong> use the <strong>Plan<\/strong> dropdown next to a site to assign it the plan (or switch it back to the <strong>Default<\/strong> free plan). The new monthly limit is applied to the tracking service automatically; no change is needed in WordPress.<\/p><\/dd>\n<dt id=\"do%20i%20need%20an%20account%3F\"><h3>Do I need an account?<\/h3><\/dt>\n<dd><p>You do not need to sign up anywhere first. During setup you press <strong>Create free account<\/strong> and the plugin provisions your site for you \u2014 that click is the only moment anything is sent. The free tier is fully functional and does not expire. A paid plan at https:\/\/dashboard.easyserversidetracking.com\/ raises your monthly event allowance and dashboard retention.<\/p><\/dd>\n<dt id=\"does%20this%20replace%20gtag.js%3F\"><h3>Does this replace gtag.js?<\/h3><\/dt>\n<dd><p>It can run alongside <code>gtag.js<\/code> (hybrid mode), or you can rely entirely on the server-side path. The script is loaded from <code>googletagmanager.com<\/code> only when hybrid mode is enabled in the Settings screen.<\/p><\/dd>\n<dt id=\"what%20data%20is%20sent%20to%20the%20managed%20worker%3F\"><h3>What data is sent to the managed worker?<\/h3><\/dt>\n<dd><p>Each event includes: event name, page URL, page title, referrer, anonymized client ID and session ID, consent state, and event-specific parameters (e.g. WooCommerce order IDs, scroll percentages, click targets). The visitor's IP address is processed by the worker for geo-resolution and rate limiting but is not stored long-term. No personally identifiable information (name, email, address) is sent unless you explicitly configure user-data fields.<\/p><\/dd>\n<dt id=\"where%20can%20i%20see%20my%20events%3F\"><h3>Where can I see my events?<\/h3><\/dt>\n<dd><p>After activation the License page shows your <code>site_id<\/code> and a link to the management dashboard, where you can view your live event log, monthly usage, and configure plan options.<\/p><\/dd>\n<dt id=\"can%20i%20uninstall%20cleanly%3F\"><h3>Can I uninstall cleanly?<\/h3><\/dt>\n<dd><p>Yes. Deactivating the plugin stops event collection. The plugin's options can be deleted via the standard WordPress plugin uninstall flow.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>5.4.3<\/h4>\n\n<ul>\n<li>Housekeeping: internal test tooling only, no change to how the plugin behaves.<\/li>\n<\/ul>\n\n<h4>5.4.2<\/h4>\n\n<ul>\n<li>Fix: setup no longer moves on when your Google Analytics credentials fail to reach the tracking service. Previously the credentials were saved locally and setup continued, leaving a site that looked finished while nothing could be forwarded to Google. Setup now stays on that step and shows exactly why it failed.<\/li>\n<li>New: if the delivery keeps failing \u2014 the service limits how often a site may reconnect \u2014 you can continue anyway. A reminder then stays in place until the credentials are delivered, so it cannot be forgotten.<\/li>\n<\/ul>\n\n<h4>5.4.1<\/h4>\n\n<ul>\n<li>Fix: the Settings Templates button did nothing. The template data is published to the page while it renders, but the script that reads it was loaded earlier, so the data never reached it and the button had no effect at all. The templates picker and its two-question helper now open and apply correctly.<\/li>\n<li>Fix: reading your saved GA4 API Secret no longer logs \"GA4 Key Decryption Error\" when debug mode is on. The secret was always decrypted correctly, but it was first run through a check meant for a different kind of key, which failed and wrote an alarming line to the log. Anyone troubleshooting why data was not reaching Google was being pointed at a decryption failure that had not happened.<\/li>\n<\/ul>\n\n<h4>5.4.0<\/h4>\n\n<ul>\n<li>New: a guided setup walks you through getting tracking working. Agree to what is shared and create your free account, enter your two Google Analytics credentials, pick your cookie banner, and answer two questions so the right settings are applied. Until the first two steps are done the plugin's other screens stay out of the way, so there is one obvious thing to do at any moment. Sites that are already set up never see it.<\/li>\n<li>New: your cookie banner is detected automatically. Complianz and Cookiebot fill in their accept and reject buttons for you; CookieYes and Iubenda are recognised too. Any other banner can still be pointed at your own buttons, and every field stays editable.<\/li>\n<li>Fix: saving your Google Analytics credentials no longer crashes the settings page. The credentials were stored and then the page died with a fatal error, which also meant they were never delivered to the tracking service - so server-side forwarding stayed broken no matter how many times you saved. Present since 5.3.0.<\/li>\n<li>Fix: the settings pages can no longer clear each other's checkboxes. Saving one section previously wrote every checkbox it knew about, so a form that did not show a box could silently switch it off. Each form now only saves what it actually displays.<\/li>\n<li>Improvement: events that fail to reach the tracking service are now retried once and, if they still do not arrive, counted and reported in the admin. Previously delivery was fire-and-forget: the plugin never looked at the result, so a brief outage silently under-counted your usage and nothing anywhere said so.<\/li>\n<li>Improvement: while setup is unfinished the plugin's other menu items are hidden, so there is one obvious thing to do. Their URLs still work and lead back into setup rather than an error page.<\/li>\n<li>Improvement: the plugin listing on WordPress.org has been rewritten. Several statements were wrong, including one that said no Google Analytics Measurement ID was needed - it is required, and without it nothing reaches your reports.<\/li>\n<\/ul>\n\n<h4>5.3.2<\/h4>\n\n<ul>\n<li>New: \"Never collect or send visitor IP data\" and \"Test Mode\" are now ordinary settings you can see and change on the Settings page. Until now they could only be set by applying a settings template, and nothing in the interface showed whether they were on.<\/li>\n<li>Fix: the settings templates no longer describe things the plugin does not do. Several promised \"no Google Analytics cookies\" or full logging in an Event Monitor screen that no longer exists, and six of the ten were identical to one another in effect. There are now three templates that genuinely differ: Recommended, Maximum Privacy, and Testing &amp; Debug.<\/li>\n<li>Fix: saving the settings page no longer silently clears options it has no field for.<\/li>\n<li>Housekeeping: removed settings that no longer had any effect, and the unused code behind them. Tracking behaviour is unchanged - if you apply a template, it now does exactly what its description says.<\/li>\n<\/ul>\n\n<h4>5.3.1<\/h4>\n\n<ul>\n<li>Fix: deactivating and reactivating the plugin silently switched off two settings. \"Disable IP geolocation\" was switched off, so visitor IP data was collected again on sites set up for maximum privacy, and Test Mode was switched off, so events that were meant to be held back started being sent to Google Analytics for real. Neither change was announced and neither was visible in the interface. Both settings now survive activation. If you rely on either one and have reactivated the plugin at any point since 5.0, re-apply your settings template to restore it.<\/li>\n<\/ul>\n\n<h4>5.3.0<\/h4>\n\n<ul>\n<li>Fix: the GA4 Measurement ID and API Secret were never sent to the tracking service. They are now included when a site connects and, because they are usually filled in afterwards, re-sent automatically whenever you save them. Server-side forwarding to your own GA4 property could not work before this.<\/li>\n<li>Fix: events forwarded through the gtag proxy lost all of their parameters. Purchase value, currency, transaction ID and the full item list are now preserved, so ecommerce reporting works for sites tracking through the proxy.<\/li>\n<li>Fix: a consent override stored in lower case (\"denied\") was not recognised and fell back to granting consent. Consent values are now normalised, and anything unrecognised fails closed to DENIED.<\/li>\n<li>Fix: the admin consent-override setting had two conflicting defaults depending on which part of the plugin read it first. Both now default to DENIED.<\/li>\n<li>Improvement: connection problems are reported instead of passing silently. Saving GA4 settings shows an explicit warning when they could not be delivered, and dropped events are written to the plugin log with the reason.<\/li>\n<\/ul>\n\n<h4>5.2.6<\/h4>\n\n<ul>\n<li>Fix: events failed to send on sites where a theme\/plugin defines a global <code>function fetch(){\u2026}<\/code> (e.g. the common admin-ajax \"data_fetch\" live-search snippet), which overwrites the browser's native window.fetch. The tracker now detects a shadowed fetch and recovers a pristine native fetch (via a hidden same-origin iframe) so events send normally. Init marker advanced to \"v5\".<\/li>\n<\/ul>\n\n<h4>5.2.5<\/h4>\n\n<ul>\n<li>Fix: prevent an uncaught JavaScript error (\"Cannot read properties of undefined (reading 'then')\") when a content blocker, privacy extension or browser tracking-protection neutralises window.fetch for the collector domain. The tracker now detects that the request was blocked and drops the event gracefully instead of throwing. Init marker advanced to \"v4\".<\/li>\n<\/ul>\n\n<h4>5.2.4<\/h4>\n\n<ul>\n<li>Maintenance: rebuild the public tracker bundle so aggressive JS optimizers\/CDNs (e.g. WP Rocket's content-hashed cache) generate a fresh file and stop serving an older cached copy. The initialization marker was advanced to \"v3\" so the loaded build is verifiable in the browser console. No functional code changes.<\/li>\n<\/ul>\n\n<h4>5.2.3<\/h4>\n\n<ul>\n<li>Maintenance: version bump to change the tracker script's cache-busting query string, forcing browsers and CDNs to reload the corrected public bundle from 5.2.2. No functional changes to the plugin.<\/li>\n<\/ul>\n\n<h4>5.2.2<\/h4>\n\n<ul>\n<li>Fix: resolve a JavaScript error (\"Cannot read properties of undefined (reading 'then')\") when sending events; rebuild the public tracker bundle so the corrected code is served.<\/li>\n<\/ul>\n\n<h4>5.2.1<\/h4>\n\n<ul>\n<li>COMPLIANCE: Neutralised the worker quota notice. When the managed service pauses a site (after it reaches its plan's monthly event volume), the admin notice now states the service paused tracking and links to the dashboard \u2014 the \"monthly limit reached \/ Upgrade your plan\" wording and the pricing link were removed. The plugin itself locks no features; all tracking is free and fully functional, and the volume is enforced by the external service, not the plugin.<\/li>\n<li>DOCS: Added setup\/connection and plan-change FAQ entries to the readme.<\/li>\n<\/ul>\n\n<h4>5.2.0<\/h4>\n\n<ul>\n<li>COMPLIANCE (WordPress.org Guideline 5 \u2014 Trialware): Removed the entire client-side license subsystem. Deleted the license manager and tamper-detection guard, removed the in-WordPress license-key field, and removed all local tracking and caching of event counts and plan limits. The plugin is free and fully functional with no license key.<\/li>\n<li>Plans, usage, limits, and upgrades are now managed entirely on the dashboard (easyserversidetracking.com). Limits are applied and enforced server-side by the managed worker; the plugin only provisions the site and sends events. The admin \"License\" screen is now a \"Connection\" screen that links to the dashboard.<\/li>\n<li>Cleanup: all obsolete license, event-count, plan-limit, permission, and tamper-hash options are removed on upgrade.<\/li>\n<\/ul>\n\n<h4>5.1.7<\/h4>\n\n<ul>\n<li>COMPLIANCE FIX: Two <code>wp_head<\/code> outputs (the googletagmanager preconnect hint and the early gtag consent script) were still gated on the provisioning id alone, so they could fire on grandfathered or consent-withdrawn sites. Both now require explicit consent AND provisioning, matching the tracker.<\/li>\n<li>HARDENING: The page-token REST endpoint now refuses to mint a worker token without consent (defense-in-depth, mirroring the \/g\/collect proxy).<\/li>\n<li>RELIABILITY: The browser's collect URL is now normalized to a single \/collect path before use, so a stored value without that suffix can't send events to the wrong endpoint. The token-refresh request no longer builds a double-slash URL.<\/li>\n<li>NOISE: The \"Not provisioned\" frontend message is now debug-gated instead of warning on every event.<\/li>\n<\/ul>\n\n<h4>5.1.6<\/h4>\n\n<ul>\n<li>HOTFIX: The 5.1.4 consent gate replaced the provisioning check on the frontend tracker and the periodic license refresh instead of adding to it. On sites that had a consent record but were not provisioned, the tracker loaded and then dropped every event as \"Not provisioned\". Both paths now correctly require BOTH explicit consent AND a provisioning id before loading or phoning home.<\/li>\n<\/ul>\n\n<h4>5.1.5<\/h4>\n\n<ul>\n<li>MAINTENANCE: Internal refactor (no change to behavior). Centralized all outbound service calls behind a single HTTP helper, extracted the consent logic (site-owner opt-in gate + visitor gcs\u2192consent mapping) into a dedicated, unit-tested class, and split the admin notices into their own class.<\/li>\n<li>TESTS: Fixed the native unit-test bootstrap (it never defined <code>WPINC<\/code>, which silently aborted the suite) and added coverage for the consent mapping.<\/li>\n<\/ul>\n\n<h4>5.1.4<\/h4>\n\n<ul>\n<li>PRIVACY\/COMPLIANCE: Explicit opt-in consent is now the single gate for ALL connections to the service and ALL tracking. Until the site administrator gives consent, the plugin does not contact the service, does not run the periodic license\/usage refresh, does not load any tracking script, and rejects the <code>\/g\/collect<\/code> proxy. The mere presence of a provisioning id (<code>esst_site_id<\/code>, which can survive an upgrade) no longer enables anything. Legacy installs with a provisioning id but no consent record now stay OFF and show a notice prompting the admin to review and enable. Withdrawing consent fully stops tracking.<\/li>\n<li>PRIVACY: Server-side event logs forwarded to the worker now carry the visitor's real GA4 consent state (derived from the gtag <code>gcs<\/code> signal, defaulting to denied) instead of a hardcoded \"granted\" value.<\/li>\n<li>SECURITY: <code>$_GET<\/code> WooCommerce variation attributes are now unslashed, sanitized (<code>sanitize_key<\/code> \/ <code>sanitize_text_field<\/code>) and validated before being passed to WooCommerce's variation matcher.<\/li>\n<\/ul>\n\n<h4>5.1.3<\/h4>\n\n<ul>\n<li>HOTFIX: Resolves a fatal <code>Class \"JachtSST\\\\Admin\\\\GA4_Server_Side_Tagging_Admin\" not found<\/code> on the License page in 5.1.2 \u2014 the consent panel referenced the pre-rename class symbol. Fixed to use the real class name <code>Jachtsst_Server_Side_Tagging_Admin<\/code>.<\/li>\n<\/ul>\n\n<h4>5.1.2<\/h4>\n\n<ul>\n<li>PRIVACY\/UX: The License page now shows a persistent \"Data sharing consent\" panel above Re-provision. It lists exactly what is sent and where, with a checkbox that records explicit consent (timestamp + user + the exact disclosure text shown). Grandfathered installs (provisioned by an older version) see this with an unticked box; ticking it records consent retroactively and unlocks the Re-provision button. The Re-provision AJAX now refuses to phone home without a stored or in-request consent record.<\/li>\n<li>COMPLIANCE: Text domain in source code now matches the actual plugin slug <code>jacht-easy-server-side-tracking<\/code> (previously had a stale reference to the slug originally proposed in the wp.org review).<\/li>\n<li>COMPLIANCE: Restored phpcs:ignore comments on the three settings-handler POST reads so Plugin Check no longer reports false-positive sanitization warnings; the sanitizer callbacks do handle JSON-decode and per-field cleanup.<\/li>\n<li>DOCS: <code>Tested up to: 7.0<\/code>.<\/li>\n<\/ul>\n\n<h4>5.1.1<\/h4>\n\n<ul>\n<li>FIX: Page\/event tokens now sign with the hashed signing key, matching the ingestion endpoint. Resolves <code>bad_page_token<\/code> \/ HMAC verification failures so events are accepted without re-provisioning.<\/li>\n<\/ul>\n\n<h4>5.1.0<\/h4>\n\n<ul>\n<li>Provisioning is now an explicit opt-in; no data is sent until you connect.<\/li>\n<li>Logs are stored in the uploads directory instead of the plugin folder.<\/li>\n<li>Stricter input sanitization and unique internal prefixes for WordPress.org compliance.<\/li>\n<\/ul>\n\n<h4>5.0.4<\/h4>\n\n<ul>\n<li>FIX: Tracker init no longer throws <code>TypeError: setupEventCountFlushHandlers is not a function<\/code>. The orphaned calls (left over from the v5.0.2 client-side limit-enforcement removal) have been deleted, so the tracker reaches the end of its init path again.<\/li>\n<li>UI: License page no longer exposes the management endpoint URL or the <code>ESST_MGMT_BASE_URL<\/code> override note. Customers shouldn't be altering this endpoint.<\/li>\n<li>Cache-bust: the version bump forces fresh JS to be loaded after the v5.0.3 release that introduced the broken init path.<\/li>\n<\/ul>\n\n<h4>5.0.3<\/h4>\n\n<ul>\n<li>SECURITY: Added CSRF nonce verification to the encryption-key regeneration AJAX endpoint.<\/li>\n<li>PRIVACY: Removed the client-side fallback chain to ipapi.co, ipinfo.io, and json.geoiplookup.io. Geo-resolution is performed server-side by the managed worker from the request IP. No visitor IP is sent to third parties by the plugin.<\/li>\n<li>COMPLIANCE: Renamed the unprefixed <code>event_count<\/code> option to <code>ga4_event_count<\/code> (with an automatic one-time migration). Sanitized all <code>$_SERVER<\/code> reads with <code>sanitize_text_field( wp_unslash() )<\/code>. Removed shipped legacy <code>plugin-v4\/<\/code> source tree and the <code>wp-admin\/includes\/upgrade.php<\/code> test mock.<\/li>\n<li>README: Added <code>External services<\/code> section documenting every external endpoint the plugin contacts, with terms and privacy links. Tags revised to remove trademarked terms.<\/li>\n<\/ul>\n\n<h4>5.0.2<\/h4>\n\n<ul>\n<li>REMOVE: Client-side event-limit enforcement. The admin Settings page no longer hides itself when a cached \"limit reached\" flag is set. Quota is enforced exclusively server-side \u2014 the worker returns <code>429 quota_exceeded<\/code>, the management server returns <code>allowed: false<\/code> in report-usage.<\/li>\n<li>FIX: License page shows the paid-plan name and limit immediately after activation \u2014 the management server now propagates <code>plan_id<\/code> onto <code>lm_websites<\/code> on <code>license\/activate<\/code> and <code>report-usage<\/code>.<\/li>\n<\/ul>\n\n<h4>5.0.1<\/h4>\n\n<ul>\n<li>FIX: All events now use a single canonical payload format with top-level <code>client_id<\/code>, <code>session_id<\/code>, <code>user_id<\/code>, <code>consent<\/code>, and <code>context<\/code> \u2014 previously some paths (scroll, click, batched events) sent <code>client_id<\/code> nested under <code>params<\/code> which the central worker rejected with HTTP 400 <code>missing_client_id<\/code>.<\/li>\n<li>FIX: Worker <code>bad_page_token<\/code> (401) responses now trigger a token refresh + retry once, so tabs left open across a re-provision auto-heal.<\/li>\n<li>FIX: Re-provisioning rotates the secret in place on the central worker instead of creating a new <code>cf_site_id<\/code> every time \u2014 no more orphaned worker sites and no more HMAC mismatches.<\/li>\n<li>FIX: Gtag \/g\/collect proxy on the WP site also fires a server-side <code>log_only<\/code> POST to the central worker so events are counted even when content blockers block the JS bundle on the customer's browser.<\/li>\n<li>FIX: License page correctly shows \"Unlimited\" for paid unlimited plans (was showing the free-tier 10,000 cap).<\/li>\n<li>REFACTOR: Removed legacy <code>sendAjaxPayload<\/code> and <code>sendBatchPayload<\/code> \u2014 <code>esstSendEvent<\/code> is the single event-sending path. Worker no longer receives batches; each event is one request.<\/li>\n<li>REFACTOR: Removed all remaining customer-hosted Cloudflare Worker references from the Settings UI.<\/li>\n<\/ul>\n\n<h4>5.0.0<\/h4>\n\n<ul>\n<li>MAJOR: Plugin no longer requires a customer-hosted Cloudflare Worker.<\/li>\n<li>MAJOR: Events post directly to the managed collect endpoint (<code>collect.easyserversidetracking.com<\/code>) using a short-lived per-page HMAC token.<\/li>\n<li>MAJOR: Removed Event Monitor \/ Event Processor \/ Tracking Logs admin pages. All event analytics now live on the management dashboard.<\/li>\n<li>NEW: Auto-provisioning on activation \u2014 no license key required for the free tier.<\/li>\n<li>NEW: Status admin page shows <code>site_id<\/code>, plan, this-month usage. (Merged into the License page in a later release.)<\/li>\n<li>REMOVED: <code>ga4_event_queue<\/code> \/ <code>ga4_event_logs<\/code> tables (data not migrated).<\/li>\n<li>REMOVED: Custom transmission method setting, CF Worker URL setting, JWT encryption setting, test mode toggle, \"disable all IP\" setting.<\/li>\n<li>The client-side session management setting is now always enabled.<\/li>\n<\/ul>\n\n<h4>3.7.x<\/h4>\n\n<p>Earlier 3.7.x releases focused on plugin-check compliance and security hardening. See the GitHub release notes for details. The plugin's data flow and admin surface were rewritten in 5.0.0; users on 3.7.x should re-test after upgrading.<\/p>","raw_excerpt":"Stop losing 30-50% of your analytics to ad blockers. Server-side GA4 and WooCommerce tracking, set up in minutes.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/fr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/305232","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/fr.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/fr.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=305232"}],"author":[{"embeddable":true,"href":"https:\/\/fr.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/jachtdigital2026"}],"wp:attachment":[{"href":"https:\/\/fr.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=305232"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/fr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=305232"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/fr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=305232"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/fr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=305232"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/fr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=305232"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/fr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=305232"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}