{"id":376343,"date":"2026-09-28T12:23:21","date_gmt":"2026-09-28T12:23:21","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/utm-keeper\/"},"modified":"2026-09-28T11:44:48","modified_gmt":"2026-09-28T11:44:48","slug":"utmkeeperflow","status":"publish","type":"plugin","link":"https:\/\/syr.wordpress.org\/plugins\/utmkeeperflow\/","author":21096513,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"0.1.0","stable_tag":"0.1.0","tested":"7.1.2","requires":"6.5","requires_php":"7.4","requires_plugins":null,"header_name":"UTM Keeper","header_author":"Ga Satrya","header_description":"Remember where visitors came from and pass campaign tags to booking or checkout links you choose.","assets_banners_color":"","last_updated":"2026-09-28 11:44:48","external_support_url":"","external_repository_url":"","donate_link":"https:\/\/paypal.me\/satrya","header_plugin_uri":"https:\/\/gasatrya.com\/wp-plugins\/utmkeeperflow\/","header_author_uri":"https:\/\/gasatrya.com\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":41,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"0.1.0":{"tag":"0.1.0","author":"gasatrya","date":"2026-09-28 11:44:48","revision":3717065}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3717065,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3717065,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":[],"assets_blueprints":{"blueprint.json":{"filename":"blueprint.json","revision":3717289,"resolution":false,"location":"assets","locale":"","contents":"{\"landingPage\":\"\\\/wp-admin\\\/options-general.php?page=utmkeeperflow\",\"features\":{\"networking\":true},\"steps\":[{\"step\":\"login\",\"username\":\"admin\",\"password\":\"password\"},{\"step\":\"installPlugin\",\"pluginData\":{\"resource\":\"wordpress.org\\\/plugins\",\"slug\":\"utmkeeperflow\"},\"options\":{\"activate\":true}}]}"}},"all_blocks":[],"tagged_versions":["0.1.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3717065,"resolution":"1","location":"assets","locale":"","width":1891,"height":911}},"screenshots":{"1":"Example UTM Keeper settings with campaign parameters and an illustrative destination hostname; configure your own destination before use."}},"plugin_section":[],"plugin_tags":[9067,7644,175,456,24188],"plugin_category":[55],"plugin_contributors":[226940],"plugin_business_model":[],"class_list":["post-376343","plugin","type-plugin","status-publish","hentry","plugin_tags-attribution","plugin_tags-campaigns","plugin_tags-links","plugin_tags-marketing","plugin_tags-utm","plugin_category-seo-and-marketing","plugin_contributors-gasatrya","plugin_committers-gasatrya"],"banners":[],"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/utmkeeperflow\/assets\/icon-128x128.png?rev=3717065","icon_2x":"https:\/\/ps.w.org\/utmkeeperflow\/assets\/icon-256x256.png?rev=3717065","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/utmkeeperflow\/assets\/screenshot-1.png?rev=3717065","caption":"Example UTM Keeper settings with campaign parameters and an illustrative destination hostname; configure your own destination before use."}],"raw_content":"<!--section=description-->\n<p>Someone clicks your newsletter link, browses a few pages on your site, then clicks through to an external booking site. The campaign tags are no longer in the page URL. How will the booking site know the visitor came from your newsletter?<\/p>\n\n<p>UTM Keeper saves selected campaign tags in the visitor's browser. When they click an external link you choose, it adds those tags to the destination URL. This helps the destination attribute bookings or purchases to your campaigns. It does not keep the tags visible in your site's page URLs or provide analytics itself.<\/p>\n\n<h4>Example: newsletter to booking<\/h4>\n\n<p>A visitor lands on your site with <code>?utm_source=newsletter&amp;utm_campaign=spring<\/code>. After browsing pages without those tags in their URLs, they click your configured link to <code>https:\/\/bookings.example.com\/book<\/code>. UTM Keeper adds <code>utm_source=newsletter&amp;utm_campaign=spring<\/code> to the booking URL, so the booking site can identify the campaign.<\/p>\n\n<h4>Other use cases<\/h4>\n\n<ul>\n<li>An ad brings someone to your site; they later follow your selected link to an external checkout.<\/li>\n<li>A social campaign brings someone to your site; they later follow your selected link to an external registration page.<\/li>\n<\/ul>\n\n<h4>How it works<\/h4>\n\n<p>UTM Keeper is disabled by default. Once an administrator enables it, the plugin stores selected campaign parameters in one expiring localStorage record for this site's browser origin. No plugin account, external service, cookies, or runtime packages are required. The plugin does not create server-side visitor records or send attribution to a plugin service; clicking a targeted link sends the resulting URL to that destination through normal browser navigation.<\/p>\n\n<p>The five standard UTM keys (utm_source, utm_medium, utm_campaign, utm_term, utm_content) are selected by default. gclid and fbclid are optional. Unknown keys, empty\/whitespace-only values, and values longer than 256 UTF-16 code units are ignored. A visit with at least one valid selected key replaces the <em>whole<\/em> previous set (last touch); a visit without valid selected keys leaves it unchanged without extending expiry. Retention is 30 days by default, configurable from 1 to 90 days from capture. Invalid or expired records are removed when checked. Unavailable browser storage means attribution cannot be captured or forwarded; there is no cookie or server fallback.<\/p>\n\n<p>Only external HTTPS links to an exact configured DNS hostname or links marked with the CSS class <code>utm-keeper<\/code> qualify. Both require no embedded credentials and no download attribute. Forwarding happens on ordinary or middle click, including for links inserted after page load, not by rewriting all links on page load. Existing destination query keys (even empty ones) take precedence; the destination path, existing query and fragment remain intact. Internal links, HTTP links, invalid URLs, and other unmarked\/unconfigured links are left unchanged. No hostname is configured by default; marking a link is a separate opt-in.<\/p>\n\n<h4>Privacy and limitations<\/h4>\n\n<p>Campaign parameters can contain personal data. Forwarded URLs may be logged by destination servers and other intermediaries. Site owners are responsible for their own privacy notices, consent requirements, and destination practices. Enabling this plugin is not a consent mechanism and does not guarantee compliance. The plugin does not provide analytics, form-field population, consent management, or automatic forwarding to all outbound links.<\/p>\n\n<p>For testing or to start fresh, use the \"Clear attribution in this browser\" button under Settings &gt; UTM Keeper. It removes only this plugin's localStorage record for the current browser profile and the admin page's origin; it does not change saved settings, unrelated site data, or other visitors' browsers. The button works even when the plugin is disabled, and reports if browser storage is unavailable. If the public site uses a different protocol, hostname, or port from the admin page, its storage is separate and this button cannot clear it. On that public site's origin, you can instead run <code>localStorage.removeItem('utmkeeperflow_attribution')<\/code> in the browser console. Visiting a campaign URL again after reset can capture fresh attribution.<\/p>\n\n<p>Automated JavaScript and PHP shim checks cover the described behavior and settings contract. Local integration was exercised on WordPress 7.1.2 with PHP 8.2.29; the \"Tested up to\" header reflects only the locally verified WordPress 7.1 line. Compatibility with other WordPress\/PHP versions is not established by this single environment.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Install the plugin in <code>wp-content\/plugins\/utmkeeperflow\/<\/code> and activate UTM Keeper in WordPress Plugins. Requires WordPress 6.5 or later and PHP 7.4 or later.<\/li>\n<li>Open Settings &gt; UTM Keeper as an administrator. The plugin remains disabled until you select Enable UTM Keeper and save.<\/li>\n<li>Select which supported campaign keys to capture. By default, five UTM keys are checked; gclid and fbclid are unchecked.<\/li>\n<li>Enter one exact DNS destination hostname per line, for example <code>bookings.example.com<\/code>. Do not include <code>https:\/\/<\/code>, a port, path, wildcard, or IP address. <code>bookings.example.com<\/code> does not match <code>other.bookings.example.com<\/code> or <code>bookings.example.com.evil.test<\/code>.<\/li>\n<li>Alternatively, explicitly mark a link in your site content, for example <code>&lt;a href=\"https:\/\/checkout.example.com\/book\" class=\"utm-keeper\"&gt;Book now&lt;\/a&gt;<\/code>. The HTTPS, external, no-credentials, and no-download restrictions still apply even to marked links.<\/li>\n<li>Set retention (1-90 days), save, and test by visiting <code>\/?utm_source=newsletter&amp;utm_campaign=spring<\/code>, then another page without campaign parameters before clicking an eligible conversion link. The destination receives only missing selected values. For example, <code>https:\/\/bookings.example.com\/book?utm_source=existing#step<\/code> keeps <code>utm_source=existing<\/code> and adds <code>utm_campaign=spring<\/code> before <code>#step<\/code>.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20it%20track%20visitors%20through%20a%20third-party%20service%3F\"><h3>Does it track visitors through a third-party service?<\/h3><\/dt>\n<dd><p>No. Capture uses this site's browser localStorage; the plugin makes no external attribution requests. Normal navigation to an eligible destination can expose forwarded query values to that destination.<\/p><\/dd>\n<dt id=\"can%20i%20reset%20attribution%20for%20all%20visitors%20from%20the%20settings%20page%3F\"><h3>Can I reset attribution for all visitors from the settings page?<\/h3><\/dt>\n<dd><p>No. The reset button affects only this plugin's record in the current browser profile at the admin page's origin; it cannot clear data in other visitors' browsers or at a different site origin.<\/p><\/dd>\n<dt id=\"why%20did%20a%20link%20remain%20unchanged%3F\"><h3>Why did a link remain unchanged?<\/h3><\/dt>\n<dd><p>The plugin must be enabled, storage must be available with an unexpired record, and the link must be an eligible external HTTPS link to an exact configured hostname or have the <code>utm-keeper<\/code> class. Existing destination keys are never overwritten. Download links, links with credentials, and non-HTTPS or internal links are not forwarded.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>0.1.0<\/h4>\n\n<ul>\n<li>Initial browser-local campaign capture, administrator settings, and targeted external link forwarding.<\/li>\n<\/ul>","raw_excerpt":"Remember where visitors came from and pass campaign tags to booking or checkout links you choose.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/syr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/376343","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/syr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/syr.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/syr.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=376343"}],"author":[{"embeddable":true,"href":"https:\/\/syr.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/gasatrya"}],"wp:attachment":[{"href":"https:\/\/syr.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=376343"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/syr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=376343"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/syr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=376343"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/syr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=376343"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/syr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=376343"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/syr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=376343"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}