{"id":370553,"date":"2026-09-20T07:55:17","date_gmt":"2026-09-20T07:55:17","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/changetrace\/"},"modified":"2026-10-02T11:09:24","modified_gmt":"2026-10-02T11:09:24","slug":"changetrace","status":"publish","type":"plugin","link":"https:\/\/fur.wordpress.org\/plugins\/changetrace\/","author":23567970,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"0.4.1","stable_tag":"0.4.1","tested":"7.1.2","requires":"6.2","requires_php":"8.1","requires_plugins":null,"header_name":"ChangeTrace","header_author":"ChangeTrace","header_description":"Connects your WordPress\/WooCommerce site to ChangeTrace: baseline snapshot, hourly heartbeat, a bounded event queue, change detection, and error capture (PHP fatals, JS errors, HTTP 5xx\/timeouts) with PII stripping.","assets_banners_color":"71292c","last_updated":"2026-10-02 11:09:24","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/change-trace.com","header_author_uri":"","rating":0,"author_block_rating":0,"active_installs":0,"downloads":180,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"0.3.0":{"tag":"0.3.0","author":"changetrace","date":"2026-09-20 07:54:42","revision":3703996},"0.3.1":{"tag":"0.3.1","author":"changetrace","date":"2026-09-21 15:23:49","revision":3705858},"0.4.0":{"tag":"0.4.0","author":"changetrace","date":"2026-10-01 07:39:25","revision":3722588},"0.4.1":{"tag":"0.4.1","author":"changetrace","date":"2026-10-02 11:09:24","revision":3724631}},"upgrade_notice":{"0.4.1":"<p>Fixes JavaScript error capture on cached sites, where every report was silently rejected.\nAlso stops installing the PHP error handler on sites that never connected, and names the\nvisitor data a JS error report carries. Recommended for all sites.<\/p>","0.4.0":"<p>Adds plugin-install, theme-update and watched-option change detection, and corrects the\ndata-collection disclosure to list WooCommerce\/EDD commerce data. Option values are never\ntransmitted. Recommended for all sites.<\/p>","0.3.1":"<p>Fixes WooCommerce\/EDD order, refund, and failed-payment tracking, which never registered\non the usual plugin load order. Recommended for all WooCommerce and EDD sites.<\/p>","0.3.0":"<p>Adds error capture (PHP, JS, HTTP) with PII stripping. No action required after upgrading.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3705858,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3705858,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256},"icon-512x512.png":{"filename":"icon-512x512.png","revision":3705858,"resolution":"512x512","location":"assets","locale":"","width":384,"height":384}},"assets_banners":{"banner-1544x500.jpg":{"filename":"banner-1544x500.jpg","revision":3705858,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-2316x750.jpg":{"filename":"banner-2316x750.jpg","revision":3705858,"resolution":"2316x750","location":"assets","locale":"","width":2316,"height":750},"banner-772x250.jpg":{"filename":"banner-772x250.jpg","revision":3705858,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["0.3.0","0.3.1","0.4.0","0.4.1"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3705858,"resolution":"1","location":"assets","locale":"","width":2858,"height":2404},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3705858,"resolution":"2","location":"assets","locale":"","width":2858,"height":5208},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3705858,"resolution":"3","location":"assets","locale":"","width":2858,"height":1966},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3705858,"resolution":"4","location":"assets","locale":"","width":2880,"height":1800},"screenshot-5.gif":{"filename":"screenshot-5.gif","revision":3705858,"resolution":"5","location":"assets","locale":"","width":760,"height":475},"screenshot-6.gif":{"filename":"screenshot-6.gif","revision":3705858,"resolution":"6","location":"assets","locale":"","width":900,"height":563},"screenshot-7.gif":{"filename":"screenshot-7.gif","revision":3705858,"resolution":"7","location":"assets","locale":"","width":900,"height":563}},"screenshots":[]},"plugin_section":[],"plugin_tags":[281664,29196,5603,248562,286],"plugin_category":[45,54],"plugin_contributors":[281665],"plugin_business_model":[],"class_list":["post-370553","plugin","type-plugin","status-publish","hentry","plugin_tags-change-detection","plugin_tags-error-tracking","plugin_tags-monitoring","plugin_tags-observability","plugin_tags-woocommerce","plugin_category-ecommerce","plugin_category-security-and-spam-protection","plugin_contributors-changetrace","plugin_committers-changetrace"],"banners":{"banner":"https:\/\/ps.w.org\/changetrace\/assets\/banner-772x250.jpg?rev=3705858","banner_2x":"https:\/\/ps.w.org\/changetrace\/assets\/banner-1544x500.jpg?rev=3705858","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/changetrace\/assets\/icon-128x128.png?rev=3705858","icon_2x":"https:\/\/ps.w.org\/changetrace\/assets\/icon-256x256.png?rev=3705858","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/changetrace\/assets\/screenshot-1.png?rev=3705858","caption":""},{"src":"https:\/\/ps.w.org\/changetrace\/assets\/screenshot-2.png?rev=3705858","caption":""},{"src":"https:\/\/ps.w.org\/changetrace\/assets\/screenshot-3.png?rev=3705858","caption":""},{"src":"https:\/\/ps.w.org\/changetrace\/assets\/screenshot-4.png?rev=3705858","caption":""},{"src":"https:\/\/ps.w.org\/changetrace\/assets\/screenshot-5.gif?rev=3705858","caption":""},{"src":"https:\/\/ps.w.org\/changetrace\/assets\/screenshot-6.gif?rev=3705858","caption":""},{"src":"https:\/\/ps.w.org\/changetrace\/assets\/screenshot-7.gif?rev=3705858","caption":""}],"raw_content":"<!--section=description-->\n<p>ChangeTrace watches your WordPress and WooCommerce site for meaningful changes and\nerrors and sends them to the ChangeTrace service (a cloud dashboard at\nhttps:\/\/app.change-trace.com), where they are correlated against metrics to surface\nthe most likely cause of a movement, with evidence.<\/p>\n\n<p>This plugin is the on-site agent. It does nothing until you connect it: you paste a\nsite token generated in the ChangeTrace dashboard, and only then does the plugin begin\nsending data to the ChangeTrace API.<\/p>\n\n<p><strong>What it collects (once connected):<\/strong><\/p>\n\n<ul>\n<li>A one-time <strong>baseline snapshot<\/strong> on connect: your active plugins and theme and their\nversions, plus WordPress, PHP, and WooCommerce versions.<\/li>\n<li>An hourly <strong>heartbeat<\/strong> so the dashboard knows the site is alive.<\/li>\n<li><strong>Change detection<\/strong> \u2014 plugins installed, activated, deactivated, updated or removed;\ntheme changed or updated; WordPress core updated; PHP version changed.<\/li>\n<li><strong>Watched site options<\/strong> \u2014 a short, fixed allowlist (permalink structure, siteurl, home,\nactive plugins, template, stylesheet, blog_public, core auto-update policy, and\nWooCommerce payment gateway settings). Only the option NAME and a summary of its shape\n(type, size\/length, and a short one-way hash) are sent \u2014 never the option's value.<\/li>\n<li><strong>Error capture<\/strong> \u2014 PHP fatals\/errors (shutdown + error handler, fails silently),\nfrontend JS errors (window.onerror, unhandled rejections, failed\/5xx fetch &amp; XHR;\nsampled), and 5xx\/timeouts on WordPress's outbound HTTP and its own REST API.<\/li>\n<li><strong>Commerce activity<\/strong> \u2014 if WooCommerce or Easy Digital Downloads is active: orders,\nfailed orders, failed payments, refunds, and checkouts started\/failed. Each carries the\norder id, the amount, the store currency, the payment method and the order status. No\ncustomer names, addresses, emails or line items are collected.<\/li>\n<\/ul>\n\n<p>All error payloads are <strong>PII-stripped<\/strong> (emails, credentials, form values, card numbers)\nand size-capped before they are queued and sent. Events are held in a bounded local queue\nand sent in batches (roughly every 5 minutes) with retry\/backoff.<\/p>\n\n<p><strong>Performance:<\/strong> collection is event-driven and adds no scheduled work beyond two WP-Cron\njobs (an hourly heartbeat and a 5-minute queue flush). The queue is a single non-autoloaded\noption capped at 500 events. The plugin does not measure page speed on your server \u2014 page\nperformance is measured by ChangeTrace from outside, so nothing runs in your visitors'\nbrowsers except the small sampled JavaScript error handler.<\/p>\n\n<p><strong>A ChangeTrace account is required.<\/strong> ChangeTrace is a third-party SaaS. See the\n\"External services\" section below for exactly what is sent and where.<\/p>\n\n<h3>External services<\/h3>\n\n<p>This plugin connects to the ChangeTrace service to send monitoring data. This connection\nis required for the plugin to do anything, and only starts after you connect the plugin\nwith a site token from the ChangeTrace dashboard.<\/p>\n\n<p><strong>Services used<\/strong><\/p>\n\n<ul>\n<li><strong>ChangeTrace API<\/strong> \u2014 https:\/\/api.change-trace.com<\/li>\n<li><strong>ChangeTrace dashboard (web app)<\/strong> \u2014 https:\/\/app.change-trace.com<\/li>\n<\/ul>\n\n<p><strong>What data is sent, and when<\/strong><\/p>\n\n<ul>\n<li>On connect (once): a baseline snapshot \u2014 your active plugins and theme with versions,\nand your WordPress, PHP, and WooCommerce versions.<\/li>\n<li>Every hour: a heartbeat (site is alive) plus your site token in the request header.<\/li>\n<li>Roughly every 5 minutes (when there is activity): a batch of events \u2014 detected changes\n(plugin\/theme\/core\/PHP\/watched options), captured errors (PHP\/JS\/HTTP), and, when\nWooCommerce or Easy Digital Downloads is active, commerce events carrying the order id,\namount, store currency, payment method and status. Error payloads are PII-stripped and\nsize-capped. Watched-option values are never sent \u2014 only the option name and a summary\nof its shape.<\/li>\n<li>A front-end JavaScript error is reported with the visiting browser's user-agent string\nand the address of the page it happened on, with the query string removed. Nothing a\nvisitor typed is read or sent.<\/li>\n<li>On connect, your browser is sent to https:\/\/app.change-trace.com to sign in and approve\nconnecting this site.<\/li>\n<\/ul>\n\n<p>Your site token is stored on your site and only ever sent to the API as an Authorization\nheader; the API stores only a hash of it. No data is sent before you connect.<\/p>\n\n<p>This service is provided by ChangeTrace. By connecting your site you agree to their terms\nand privacy policy:<\/p>\n\n<ul>\n<li>Terms of Service: https:\/\/change-trace.com\/terms-of-service<\/li>\n<li>Privacy Policy: https:\/\/change-trace.com\/privacy-policy<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Install and activate the plugin from the Plugins screen (or upload the folder to\n   wp-content\/plugins\/).<\/li>\n<li>Open <strong>ChangeTrace<\/strong> in the admin menu.<\/li>\n<li>Create an account at https:\/\/app.change-trace.com, generate a site token (it starts\nwith <code>site_tok_<\/code>), and paste it into the connect screen.<\/li>\n<\/ol>\n\n<p>Advanced: the API, dashboard, privacy, and terms URLs can be overridden in <code>wp-config.php<\/code>\nvia <code>CHANGETRACE_API_BASE_URL<\/code>, <code>CHANGETRACE_APP_URL<\/code>, <code>CHANGETRACE_PRIVACY_URL<\/code>, and\n    CHANGETRACE_TERMS_URL, or via the matching <code>changetrace_*<\/code> filters.<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"do%20i%20need%20a%20changetrace%20account%3F\"><h3>Do I need a ChangeTrace account?<\/h3><\/dt>\n<dd><p>Yes. ChangeTrace is a hosted service. The plugin is the on-site agent and needs a site\ntoken from https:\/\/app.change-trace.com to do anything.<\/p><\/dd>\n<dt id=\"does%20the%20plugin%20send%20any%20data%20before%20i%20connect%20it%3F\"><h3>Does the plugin send any data before I connect it?<\/h3><\/dt>\n<dd><p>No. Nothing leaves your site until you paste a valid site token and connect. See the\n\"External services\" section for what is sent afterward.<\/p><\/dd>\n<dt id=\"is%20personal%20data%20sent%20to%20changetrace%3F\"><h3>Is personal data sent to ChangeTrace?<\/h3><\/dt>\n<dd><p>Error payloads are PII-stripped (emails, credentials, form values, card numbers) and\nsize-capped before being queued and sent. The baseline snapshot contains software\nversions and plugin\/theme names, not visitor data.<\/p>\n\n<p>A front-end JavaScript error is the one event that carries anything about a visitor: the\nbrowser's user-agent string and the address of the page the error happened on, with the\nquery string stripped. No form values, cookies or identifiers are read.<\/p>\n\n<p>Commerce events carry order totals, currency, payment method and order status, plus the\norder id \u2014 never customer names, addresses, emails, phone numbers or line items. Fields a\ncustomer typed into checkout are discarded outright rather than filtered.<\/p>\n\n<p>Watched-option values are never transmitted; only the option name and a shape summary.<\/p><\/dd>\n<dt id=\"does%20the%20plugin%20slow%20my%20site%20down%3F\"><h3>Does the plugin slow my site down?<\/h3><\/dt>\n<dd><p>Collection is event-driven and the handlers are wrapped so a collector error can never\nbreak a page, a checkout or a purchase. Work on the request path is limited to appending\nto a bounded local queue. Sending happens on WP-Cron, not during a page view. Frontend\nJavaScript error capture is sampled (about 25% of page loads, capped at 5 errors per load).<\/p>\n\n<p>The plugin does not measure page speed on your server; page performance is measured by\nChangeTrace from outside your hosting.<\/p><\/dd>\n<dt id=\"how%20do%20i%20stop%20sending%20data%3F\"><h3>How do I stop sending data?<\/h3><\/dt>\n<dd><p>Deactivate the plugin, or disconnect the site from the ChangeTrace connect screen. You\ncan also delete the plugin; it cleans up its stored token and options on uninstall.<\/p><\/dd>\n<dt id=\"can%20i%20point%20the%20plugin%20at%20a%20self-hosted%20or%20staging%20environment%3F\"><h3>Can I point the plugin at a self-hosted or staging environment?<\/h3><\/dt>\n<dd><p>Yes. Define <code>CHANGETRACE_API_BASE_URL<\/code> (and optionally <code>CHANGETRACE_APP_URL<\/code>) in\n    wp-config.php.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>0.4.1 - 2026-10-02<\/h4>\n\n<ul>\n<li>Fix: front-end JavaScript error capture stopped working on sites with a full-page cache.\nThe REST nonce was printed into the page and served from the cache long after it expired,\nso every report was rejected and silently dropped. The handler now refetches a current\nnonce once per page load and retries. Cached pages keep serving the old handler until the\ncache is purged, so the fix takes effect from the first purge after upgrading.<\/li>\n<li>Fix: the error-capture handler no longer routes its own reports through its own failed\nrequest detector, which could make a failing endpoint report itself.<\/li>\n<li>Change: the PHP error and shutdown handlers are installed only while the site is\nconnected. Sites that never connected were paying for capture whose output was discarded.<\/li>\n<li>Change: the data disclosure on the connect screen, in the suggested privacy-policy text\nand in this readme now states that a JavaScript error report includes the visiting\nbrowser's user-agent string and the page address with the query string removed. No\ncollection behaviour changed \u2014 this was always sent and is now named.<\/li>\n<\/ul>\n\n<h4>0.4.0 - 2026-10-01<\/h4>\n\n<ul>\n<li>New: plugin installs are reported as their own <code>plugin_installed<\/code> event. Previously a\nplugin that appeared on disk without being activated was absorbed silently into the\nbaseline and could never be offered as a possible cause.<\/li>\n<li>New: theme updates are detected. Only a switch to a <em>different<\/em> theme was reported\nbefore, so updating the active theme \u2014 one of the most common ways to break a site \u2014\nproduced no event at all.<\/li>\n<li>New: changes to a short, fixed allowlist of high-signal site options are reported\n(<code>option_changed<\/code>): permalink structure, siteurl, home, active plugins, template,\nstylesheet, blog_public, core auto-update policy, and WooCommerce payment gateway\nsettings. Only the option NAME and a summary of its shape (type, size\/length and a\nshort one-way hash) are sent \u2014 never the option's value, because several of these hold\nlive API keys. No other option is monitored.<\/li>\n<li>New: event types are declared in one place (<code>includes\/Support\/Event_Types.php<\/code>) and\ncompared against the ChangeTrace API's own registry by an automated check, so the\nplugin cannot ship a type the service does not understand.<\/li>\n<li>Change: readme and the connect screen now disclose WooCommerce\/EDD commerce data\n(order id, total, currency, payment method, status, refunds, checkout events), which\nthe plugin has sent since 0.2.0 but did not list. No collection behaviour changed.<\/li>\n<li>Fix: the connect screen and the suggested privacy-policy text claimed the plugin\ncollects performance metrics. It does not and never has \u2014 page performance is measured\nby ChangeTrace from outside your hosting, with nothing running in visitors' browsers.<\/li>\n<\/ul>\n\n<h4>0.3.1 - 2026-09-21<\/h4>\n\n<ul>\n<li>Fix: WooCommerce and EDD event collectors did not register their hooks when the\nplugin loaded before WooCommerce\/EDD (the usual load order), so orders, refunds, and\nfailed payments were never captured. Hook registration is now deferred until\nWooCommerce\/EDD is available.<\/li>\n<li>Fix: capture WooCommerce orders at checkout placement via\n  woocommerce_checkout_order_processed and the block\/Store-API\n  woocommerce_store_api_checkout_order_processed, instead of <code>woocommerce_new_order<\/code>,\nwhich fired at draft creation on block checkout and recorded phantom orders.<\/li>\n<\/ul>\n\n<h4>0.3.0 - 2026-09-20<\/h4>\n\n<ul>\n<li>Error capture: PHP fatals\/errors (shutdown + error handler, fails silently),\nfrontend JS errors (window.onerror, unhandled rejections, failed\/5xx fetch &amp; XHR;\nsampled), and 5xx\/timeouts on WordPress's outbound HTTP + own REST API.<\/li>\n<li>All error payloads are PII-stripped (emails, credentials, form values, card numbers)\nand size-capped before queuing.<\/li>\n<\/ul>\n\n<h4>0.2.0<\/h4>\n\n<ul>\n<li>Baseline snapshot (plugins, theme, WP\/PHP\/WooCommerce versions) sent once on connect.<\/li>\n<li>Bounded local event queue (drops oldest when full) with a scheduled batch sender\n(every 5 minutes) that retries with exponential backoff on failure.<\/li>\n<li>Remote config fetch (enabled modules, sampling, heartbeat interval).<\/li>\n<\/ul>\n\n<h4>0.1.0<\/h4>\n\n<ul>\n<li>Connection layer: connect screen, secure token storage, hourly heartbeat.<\/li>\n<\/ul>\n\n<h4>0.0.0<\/h4>\n\n<ul>\n<li>Initial skeleton. Boots and activates; no detectors wired up yet.<\/li>\n<\/ul>","raw_excerpt":"Detects changes and errors on your WordPress\/WooCommerce site and sends them to ChangeTrace to surface the likely cause of issues, with evidence.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/fur.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/370553","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fur.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/fur.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/fur.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=370553"}],"author":[{"embeddable":true,"href":"https:\/\/fur.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/changetrace"}],"wp:attachment":[{"href":"https:\/\/fur.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=370553"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/fur.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=370553"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/fur.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=370553"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/fur.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=370553"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/fur.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=370553"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/fur.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=370553"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}