{"id":4354,"date":"2025-09-24T10:25:28","date_gmt":"2025-09-24T09:25:28","guid":{"rendered":"https:\/\/ibex.tech\/javascript\/?p=4354"},"modified":"2025-09-24T10:25:29","modified_gmt":"2025-09-24T09:25:29","slug":"detect-page-from-site-open-in-another-tab","status":"publish","type":"post","link":"https:\/\/ibex.tech\/javascript\/page_control\/detect-page-from-site-open-in-another-tab","title":{"rendered":"Detect page from site open in another tab"},"content":{"rendered":"\n<h4 class=\"wp-block-heading\">On the page you want to detect is open<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>  \/\/-------------------------------------------------------------------\n  \/\/----- PAGE PING - RECEVIE PINGS FROM PAGE OPEN IN ANOTHER TAB -----\n  \/\/-------------------------------------------------------------------\n  \/\/(There is seperate code that pings us on another page)\n  &lt;script>\n    function PagePingStartFocusReceiver()\n    {\n      const ChannelName='SiteTabCoord';\n      const SupportsBC=!!window.BroadcastChannel;\n      const BC=SupportsBC ? new BroadcastChannel(ChannelName) : null;\n      const FallbackKey='tabcoord_msg';\n\n      function Send(payload)\n      {\n        const msg={...payload, ts:Date.now()};\n        if(BC)\n        {\n          BC.postMessage(msg);\n        }\n        else\n        {\n          localStorage.setItem(FallbackKey, JSON.stringify(msg));\n          localStorage.removeItem(FallbackKey);\n        }\n      }\n\n      function OnMessageLike(data)\n      {\n        if(!data || typeof data!=='object') return;\n\n        if(data.type==='ping')\n        {\n          \/\/Tell the closing tab that we exist and share our URL\n          Send({type:'here', url:location.href});\n        }\n        else if(data.type==='please-focus')\n        {\n          try { window.focus(); } catch(_) {}\n          \/\/Optional: visual cue\n          \/\/document.title='\u25cf '+document.title;\n          \/\/setTimeout(()=>document.title=document.title.replace(\/^\u25cf\\s*\/,''), 2000);\n        }\n      }\n\n      if(BC)\n      {\n        BC.onmessage=(e)=>OnMessageLike(e.data);\n      }\n      else\n      {\n        window.addEventListener('storage', function(e)\n        {\n          if(e.key===FallbackKey &amp;&amp; e.newValue)\n          {\n            try { OnMessageLike(JSON.parse(e.newValue)); } catch(_) {}\n          }\n        });\n      }\n    }\n    \/\/Run on load\n    document.addEventListener('DOMContentLoaded', PagePingStartFocusReceiver);\n  &lt;\/script><\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">On the page you want to find out if the other page is open<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/-------------------------------------------------------------------------------\n\/\/----- PAGE PING - DETECT IF A PAGE IS ALREADY OPEN IN ANOTHER BROWSER TAB -----\n\/\/-------------------------------------------------------------------------------\n\/\/(There is separate code that we ping on the other page)\n$HtmlOutput .= &lt;&lt;&lt;_END\n  &lt;script>\n    function PagePingStartClosingTab()\n    {\n      const ChannelName='SiteTabCoord';\n      const TabId=(self.crypto &amp;&amp; crypto.randomUUID) ? crypto.randomUUID() : Math.random().toString(36).slice(2);\n      const SupportsBC=!!window.BroadcastChannel;\n      const BC=SupportsBC ? new BroadcastChannel(ChannelName) : null;\n      const FallbackKey='tabcoord_msg';\n      const TimeoutMs=5000;\n      const PingCount=6;\n      const PingInterval=250;\n\n      let GotReply=false;\n      let OtherUrl=null;\n      let DoneCloseAction=false;\n\n      function Send(payload)\n      {\n        const msg={...payload, sender:TabId, ts:Date.now()};\n        if(BC)\n        {\n          BC.postMessage(msg);\n        }\n        else\n        {\n          localStorage.setItem(FallbackKey, JSON.stringify(msg));\n          localStorage.removeItem(FallbackKey);\n        }\n      }\n\n      function OnMessageLike(data)\n      {\n        if(!data || typeof data!=='object') return;\n        if(data.sender===TabId) return;\n\n        if(data.type==='here')\n        {\n          GotReply=true;\n          OtherUrl=data.url || null;\n          Proceed();\n        }\n        \/\/We ignore 'ping' here; this tab is the closer\n      }\n\n      function Proceed()\n      {\n        if(!GotReply) \n          return;\n\n        \/\/----- ANOTHER TAB IS OPEN -----\n\n        \/\/Ask the other tab to try focusing itself (browser may ignore)\n        Send({type:'please-focus'});\n\n        \/\/If this tab was opened via window.open by script, we can usually close it\n        if(window.opener &amp;&amp; !window.opener.closed)\n        {\n          try { window.close(); return; } catch(_) {}\n        }\n\n        \/\/We couldn't close, so inform the user\n        if (DoneCloseAction)\n          return;\n        DoneCloseAction = true;\n        \n        \/\/----- WE COULDN'T CLOSE THE PAGE - DO SOMETHING TO TELL USER HERE? -----\n        \/\/alert('A similar page is already open in another browser tab. Please use that tab to continue.' + (OtherUrl ? 'URL: ' + OtherUrl : ''));\n\n        \/\/&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;\n\n\n      }\n\n      if(BC)\n      {\n        BC.onmessage=(e)=>OnMessageLike(e.data);\n      }\n      else\n      {\n        window.addEventListener('storage', function(e)\n        {\n          if(e.key===FallbackKey &amp;&amp; e.newValue)\n          {\n            try { OnMessageLike(JSON.parse(e.newValue)); } catch(_) {}\n          }\n        });\n      }\n\n      \/\/Burst of pings to find the focus tab\n      for(let i=0;i&lt;PingCount;i++)\n      {\n        setTimeout(()=>Send({type:'ping'}), i*PingInterval);\n      }\n\n      \/\/Give it time to answer; then proceed if we got a reply\n      setTimeout(function()\n      {\n        Proceed();\n      }, TimeoutMs);\n    }\n    \/\/Run on load\n    document.addEventListener('DOMContentLoaded', PagePingStartClosingTab);\n  &lt;\/script><\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>On the page you want to detect is open On the page you want to find out if the other page is open<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[47],"tags":[],"class_list":["post-4354","post","type-post","status-publish","format-standard","hentry","category-page_control"],"_links":{"self":[{"href":"https:\/\/ibex.tech\/javascript\/wp-json\/wp\/v2\/posts\/4354","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ibex.tech\/javascript\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ibex.tech\/javascript\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ibex.tech\/javascript\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ibex.tech\/javascript\/wp-json\/wp\/v2\/comments?post=4354"}],"version-history":[{"count":1,"href":"https:\/\/ibex.tech\/javascript\/wp-json\/wp\/v2\/posts\/4354\/revisions"}],"predecessor-version":[{"id":4355,"href":"https:\/\/ibex.tech\/javascript\/wp-json\/wp\/v2\/posts\/4354\/revisions\/4355"}],"wp:attachment":[{"href":"https:\/\/ibex.tech\/javascript\/wp-json\/wp\/v2\/media?parent=4354"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ibex.tech\/javascript\/wp-json\/wp\/v2\/categories?post=4354"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ibex.tech\/javascript\/wp-json\/wp\/v2\/tags?post=4354"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}