<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: bore.ddev</title>
    <description>The latest articles on DEV Community by bore.ddev (@bored_dev).</description>
    <link>https://dev.to/bored_dev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2100438%2F4d78a0f6-2581-4e8f-9a07-956d56b63324.png</url>
      <title>DEV Community: bore.ddev</title>
      <link>https://dev.to/bored_dev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bored_dev"/>
    <language>en</language>
    <item>
      <title>How to Get the Parent Domain from a Cross-Origin Iframe in JavaScript (Without Losing Your Sanity)</title>
      <dc:creator>bore.ddev</dc:creator>
      <pubDate>Sat, 22 Aug 2026 08:11:48 +0000</pubDate>
      <link>https://dev.to/bored_dev/how-to-get-the-parent-domain-from-a-cross-origin-iframe-in-javascript-without-losing-your-sanity-1885</link>
      <guid>https://dev.to/bored_dev/how-to-get-the-parent-domain-from-a-cross-origin-iframe-in-javascript-without-losing-your-sanity-1885</guid>
      <description>&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;If you are developing an iframe-based widget, embedded tool, or third-party script, you will inevitably run into a question that sounds deceptively simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Which website embedded my iframe?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Knowing the parent domain is essential for domain authorization, analytics, and security origin checks. But here is the catch: &lt;strong&gt;modern web browsers trust nobody — especially not your iframe.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Trying to read &lt;code&gt;window.parent.location.href&lt;/code&gt; across origins is like peeking into your neighbor's window — the browser's security guard (&lt;code&gt;DOMException&lt;/code&gt;) will tackle you immediately. And if you rely on &lt;code&gt;document.referrer&lt;/code&gt;, strict &lt;code&gt;no-referrer&lt;/code&gt; policies will ghost your script faster than a bad Tinder date.&lt;/p&gt;

&lt;p&gt;In this guide, we will cover:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Why &lt;code&gt;window.parent.location&lt;/code&gt; fails (and why Same-Origin Policy is browser-speak for &lt;em&gt;"You can look, but don't touch"&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;Why &lt;code&gt;document.referrer&lt;/code&gt; breaks when websites decide to go full stealth mode.&lt;/li&gt;
&lt;li&gt;How &lt;code&gt;window.location.ancestorOrigins&lt;/code&gt; saves us from nested iframe &lt;em&gt;Inception&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;How to write a robust, production-ready &lt;strong&gt;Vanilla JavaScript helper function&lt;/strong&gt; (&lt;code&gt;getTopParentDomain&lt;/code&gt;) that gets the domain without crashing your app.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkrlfb1inmjhwi485nedd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkrlfb1inmjhwi485nedd.png" alt="Cross origin picture" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Why &lt;code&gt;window.parent.location&lt;/code&gt; Fails (Same-Origin Policy)
&lt;/h2&gt;

&lt;p&gt;When your iframe page (&lt;code&gt;https://my-widget.com&lt;/code&gt;) is embedded inside a host page (&lt;code&gt;https://example.com&lt;/code&gt;), they are &lt;strong&gt;Cross-Origin&lt;/strong&gt; (different domains).&lt;/p&gt;

&lt;p&gt;Because they are cross-origin, the browser enforces the &lt;strong&gt;Same-Origin Policy (SOP)&lt;/strong&gt;. SOP is the browser security rule that basically states: &lt;em&gt;"Scripts can directly access DOM properties across windows only when the relevant documents share the same origin."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you try to bypass this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ DOMException: Blocked a frame with origin "https://my-widget.com" from accessing a cross-origin frame.&lt;/span&gt;
&lt;span class="c1"&gt;// (Also known as: the error message that makes you question your life choices at 2 AM)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parentUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser shuts it down instantly. You cannot read the parent's URL, DOM, or cookies. Security policies in 2026: Google knows who the user is, the ISP knows who the user is, but your own iframe isn't allowed to know what website it's sitting on.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. The &lt;code&gt;document.referrer&lt;/code&gt; Problem (Or: How Referrer Policies Ghost You)
&lt;/h2&gt;

&lt;p&gt;A common first approach is &lt;code&gt;document.referrer&lt;/code&gt;.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;referrer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "https://example.com/blog/page-1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In an ideal world, &lt;code&gt;document.referrer&lt;/code&gt; gives you the host URL. But we don't live in an ideal world; we live in a world of privacy policies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why &lt;code&gt;document.referrer&lt;/code&gt; ghosted you
&lt;/h3&gt;

&lt;p&gt;Websites can strip referrer headers entirely using a meta tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Parent website going full stealth mode --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"referrer"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"no-referrer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or HTTP headers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Referrer-Policy: no-referrer
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or directly on the iframe tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;iframe&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://my-widget.com"&lt;/span&gt; &lt;span class="na"&gt;referrerpolicy=&lt;/span&gt;&lt;span class="s"&gt;"no-referrer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When any of these are active, &lt;code&gt;document.referrer&lt;/code&gt; inside your iframe evaluates to &lt;strong&gt;an empty string (&lt;code&gt;""&lt;/code&gt;)&lt;/strong&gt;. Your iframe enters the DOM wearing dark sunglasses and a trench coat with zero memory of where it came from.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fllfpzgn5josbk9bf6lmu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fllfpzgn5josbk9bf6lmu.png" alt="document.referrer console value" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The Solution: Multi-Tier Parent Domain Resolution
&lt;/h2&gt;

&lt;p&gt;Since no single method works 100% of the time across all browsers, we build a &lt;strong&gt;3-tier survival engine&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                              ┌────────────────────────────────────────┐
                              │     getTopParentDomain() Started       │
                              └───────────────────┬────────────────────┘
                                                  │
                                       Is top-level window?
                                       (window.parent === window)
                                         /                \
                                    YES /                  \ NO (Inside Iframe)
                                       /                    \
                     ┌──────────────────────────┐    ┌───────────────────────────────────┐
                     │ Parse document.referrer  │    │ Check ancestorOrigins[last]       │
                     │ Or return 'Direct Access'│    │ (Chromium / WebKit - Top Domain)  │
                     └──────────────────────────┘    └─────────────────┬─────────────────┘
                                                                       │
                                                                 Found origin?
                                                                  /         \
                                                             YES /           \ NO
                                                                /             \
                                          ┌──────────────────────────┐   ┌────────────────────────────┐
                                          │ Return Top Main Domain   │   │ Check document.referrer    │
                                          └──────────────────────────┘   └──────────────┬─────────────┘
                                                                                        │
                                                                                  Found origin?
                                                                                   /         \
                                                                              YES /           \ NO
                                                                                 /             \
                                                           ┌──────────────────────────┐   ┌───────────────────────────┐
                                                           │ Parse Referrer Origin    │   │ Start postMessage         │
                                                           └──────────────────────────┘   │ Handshake (3s Timeout)    │
                                                                                          └───────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Handling Nested Iframes with &lt;code&gt;ancestorOrigins&lt;/code&gt; (Escaping Iframe &lt;em&gt;Inception&lt;/em&gt;)
&lt;/h2&gt;

&lt;p&gt;What happens if someone puts your iframe inside another iframe inside another iframe? Congratulations — you've created web development Russian nesting dolls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Topmost Main Site A (https://main-portal.com) [Address Bar]
 └── Wrapper Iframe B (https://agency-host.com)
      └── Your Widget C (https://my-widget.com)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you try to inspect immediate parent origins in a nested setup, you get &lt;code&gt;agency-host.com&lt;/code&gt;, which isn't the real website!&lt;/p&gt;

&lt;p&gt;In Chrome, Edge, Safari, and Opera, Chromium gives us &lt;code&gt;window.location.ancestorOrigins&lt;/code&gt;. This is an array of all parent origins up the chain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ancestorOrigins&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
&lt;span class="c1"&gt;// ➔ "https://agency-host.com" (Immediate Parent B)&lt;/span&gt;

&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ancestorOrigins&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ancestorOrigins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
&lt;span class="c1"&gt;// ➔ "https://main-portal.com" (Topmost Main Site A in the Address Bar!)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ancestorOrigins[ancestorOrigins.length - 1]&lt;/code&gt; is your totem in &lt;em&gt;Inception&lt;/em&gt; — it instantly wakes you up at the topmost domain in the address bar.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Note: Chrome gives you &lt;code&gt;ancestorOrigins&lt;/code&gt; generously. Browser support isn't universal, so we need another fallback. Because apparently Firefox would like us to mind our own business. That's why we need Tier 3).&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbpmgnta3a7r7xdr2lo4u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbpmgnta3a7r7xdr2lo4u.png" alt="ancestor origins picture" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  6. The Bulletproof Handshake: Bi-Directional &lt;code&gt;postMessage&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;When &lt;code&gt;no-referrer&lt;/code&gt; strips &lt;code&gt;document.referrer&lt;/code&gt; AND &lt;code&gt;ancestorOrigins&lt;/code&gt; is unsupported (hello, Firefox!), we fall back to a &lt;strong&gt;bi-directional &lt;code&gt;postMessage&lt;/code&gt; handshake&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;postMessage&lt;/code&gt; handshake is basically two introverted browser windows awkwardly waving at each other across cross-origin boundaries until someone confirms their origin.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Handshake Steps:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Widget Mounts&lt;/strong&gt;: The iframe posts a &lt;code&gt;WIDGET_READY&lt;/code&gt; signal to &lt;code&gt;window.parent&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parent Script Listens&lt;/strong&gt;: The host script catches &lt;code&gt;WIDGET_READY&lt;/code&gt; and posts back &lt;code&gt;{ type: 'PARENT_ORIGIN_INIT' }&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser Cryptography Magic&lt;/strong&gt;: The browser automatically attaches &lt;code&gt;event.origin&lt;/code&gt; to the message inside the iframe. The browser supplies event.origin based on the origin of the window that sent the message. JavaScript cannot arbitrarily set this value, but your application should still validate the received origin and message source before trusting the message.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq5i7phjmw6w8cjm8twan.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq5i7phjmw6w8cjm8twan.png" alt="handshake method" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Production-Ready Vanilla JS Solution
&lt;/h2&gt;

&lt;p&gt;Here is the complete, zero-dependency, production-ready Vanilla JavaScript code.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Parent Page Script (Placed on Host Site)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Placed on the host website (or bundled into your embed script)&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Respond only when widget notifies it is ready&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WIDGET_READY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PARENT_ORIGIN_INIT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. The Iframe Domain Helper (&lt;code&gt;getTopParentDomain&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Helper to extract topmost domain from Chromium ancestorOrigins
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getTopmostAncestorDomain&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ancestorOrigins&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ancestorOrigins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;topAncestor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ancestorOrigins&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ancestorOrigins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;topAncestor&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;topAncestor&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;null&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;topAncestor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Detects the available embedding origin, with the top-level ancestor available when ancestorOrigins is supported.
 * @returns {Promise&amp;lt;string&amp;gt;} Resolves to the detected parent domain (e.g. "https://example.com")
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getTopParentDomain&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isEmbedded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// 1. Direct Browser Access (Not inside an iframe)&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isEmbedded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;referrer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;referrer&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;referrer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Direct Access&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// 2. Try Chromium/WebKit ancestorOrigins immediately&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ancestorDomain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getTopmostAncestorDomain&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ancestorDomain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ancestorDomain&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// 3. Try document.referrer immediately&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;referrer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;referrerDomain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;referrer&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;referrerDomain&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;referrerDomain&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;null&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;referrerDomain&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Ignore URL parse error&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// 4. Fallback: Initiate postMessage Handshake (for strict no-referrer policies)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;resolved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;cleanupAndResolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolved&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;resolved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeoutId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleHandshake&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleHandshake&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PARENT_ORIGIN_INIT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;null&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// Prefer ancestorOrigins if available; fallback to browser-verified event.origin&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;topDomain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getTopmostAncestorDomain&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="nf"&gt;cleanupAndResolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;topDomain&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Listen for parent handshake response&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleHandshake&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Notify parent window that widget is ready&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WIDGET_READY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Timeout safety fallback (3 seconds: enough for slow sites without blocking forever)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timeoutId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;cleanupAndResolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unknown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Example Usage:&lt;/span&gt;
&lt;span class="nf"&gt;getTopParentDomain&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Detected Parent Domain:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  8. Summary Checklist for Developers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Detection method&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Supported browser + nested iframe&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ancestorOrigins[last]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Top-level ancestor origin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-origin iframe + referrer available&lt;/td&gt;
&lt;td&gt;&lt;code&gt;document.referrer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Referring origin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Referrer unavailable&lt;/td&gt;
&lt;td&gt;&lt;code&gt;postMessage&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Immediate parent's origin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Direct page access&lt;/td&gt;
&lt;td&gt;&lt;code&gt;document.referrer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Referring origin or empty&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;So, what started as a simple question — &lt;strong&gt;"Which website embedded my iframe?"&lt;/strong&gt; — turns out to involve a few browser security rules, privacy policies, and enough iframe nesting to make you question your life choices.&lt;/p&gt;

&lt;p&gt;The practical approach is to use the browser information available to you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;ancestorOrigins[last]&lt;/code&gt; when you need the &lt;strong&gt;top-level ancestor origin&lt;/strong&gt; and the browser supports it.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;document.referrer&lt;/code&gt; when referrer information is available.&lt;/li&gt;
&lt;li&gt;Use a &lt;code&gt;postMessage&lt;/code&gt; handshake when the parent page can explicitly cooperate and provide its origin.&lt;/li&gt;
&lt;li&gt;If none of these methods can provide the information, return a safe fallback instead of pretending the browser owes you an answer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important part is that there is &lt;strong&gt;no universal way for a cross-origin iframe to freely inspect its parent's location&lt;/strong&gt;. That's not a missing JavaScript API. That's the browser's security model doing exactly what it was designed to do.&lt;/p&gt;

&lt;p&gt;So the next time your iframe asks, &lt;em&gt;"Who is my parent?"&lt;/em&gt;, at least now you have a few ways to investigate before calling it a family issue.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>frontend</category>
      <category>webdev</category>
      <category>security</category>
    </item>
    <item>
      <title>Stop Pasting Your JWT Tokens Into Random Websites</title>
      <dc:creator>bore.ddev</dc:creator>
      <pubDate>Sat, 27 Jun 2026 14:33:40 +0000</pubDate>
      <link>https://dev.to/bored_dev/stop-pasting-your-jwt-tokens-into-random-websites-3ij</link>
      <guid>https://dev.to/bored_dev/stop-pasting-your-jwt-tokens-into-random-websites-3ij</guid>
      <description>&lt;p&gt;I built a 21-tool developer toolkit that runs entirely in your browser. No servers. No sign-ups. No data leaving your machine. Ever. Here's why, and here's what it does.&lt;/p&gt;




&lt;p&gt;You're debugging a broken API response at 11 PM. You've got a JWT token in your clipboard, a JSON payload that won't parse, and a CSS-to-Tailwind conversion you've been putting off since Tuesday.&lt;/p&gt;

&lt;p&gt;So you open a random "online JSON formatter" from Google. Paste your JWT into a text box labeled "Enter your token here." Click "Decode."&lt;/p&gt;

&lt;p&gt;Somewhere, on some server you'll never see, your token is now stored. Along with the 200 other things you've pasted into that tool this month.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That's the problem I kept running into.&lt;/strong&gt; And it's not just JWT tokens. It's API keys in Base64, test data in JSON, regex patterns you don't want logged, passwords you definitely shouldn't be typing into a random input field.&lt;/p&gt;

&lt;p&gt;So I built something different.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is DevClat?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;DevClat is a free, open, client-side developer toolkit with 21 tools&lt;/strong&gt; — and every single one runs in your browser. No backend. No API calls. No "we take your privacy seriously" banner over a tracking script.&lt;/p&gt;

&lt;p&gt;It's a single-page React app. You open it, use it, close it. Your data never touches a server because there is no server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://devclat.vercel.app" rel="noopener noreferrer"&gt;Try the DevClat Developer Toolkit →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tools (All 21 of Them)
&lt;/h2&gt;

&lt;p&gt;I didn't build 21 "me too" utilities. Each tool exists because I personally needed it and got tired of context-switching between 15 browser tabs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Generation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Mock Data Generator&lt;/strong&gt; — The one that started it all. Pick a preset (Users, Products, Orders, Addresses, Transactions, Posts, Employees, Invoices, Reviews) or build a custom schema with any field type. Output as JSON, CSV, or SQL. Powered by faker.js, running entirely client-side. Generate 100 rows of realistic fake data without sending a single byte over the network.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lorem Ipsum Generator&lt;/strong&gt; — Not the usual "lorem ipsum dolor sit amet" generator. Configure paragraph count, copy with one click, done. You've got bigger things to worry about than placeholder text.&lt;/p&gt;

&lt;h3&gt;
  
  
  Editors &amp;amp; Formatters
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;JSON Formatter &amp;amp; Validator&lt;/strong&gt; — Paste broken, minified, or malformed JSON. Get instant pretty-printing, syntax highlighting, and error line highlighting. Collapsible tree view for large payloads. One-click copy. No "Loading..." spinners, no "Your JSON has been saved for analytics."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Text Diff Tool&lt;/strong&gt; — Git-diff style comparison without opening a terminal. Side-by-side view with line-level and word-level highlighting. Unified, split, and words output modes. A statistics panel that actually tells you what changed. Perfect for comparing config files, API responses, or that SQL migration you're afraid to run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Regex Tester&lt;/strong&gt; — Type a pattern, see matches highlighted in real-time. Toggle flags (g, i, m, s, u) without rewriting your regex. Capture groups displayed inline. No more running &lt;code&gt;grep&lt;/code&gt; in the terminal just to test if your email regex actually works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTML Preview Editor&lt;/strong&gt; — Side-by-side HTML/CSS/JS editor with instant live preview. Full-page preview mode for when you need to see what your component actually looks like without deploying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Markdown Preview&lt;/strong&gt; — Write Markdown on the left, see rendered HTML on the right. Real-time. Supports tables, code blocks, headings, links. Zero friction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSS Minifier&lt;/strong&gt; — Paste CSS, get compressed output. Side-by-side size comparison so you can feel smug about those extra 2KB you just saved.&lt;/p&gt;

&lt;h3&gt;
  
  
  Converters
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;CSS to Tailwind Converter&lt;/strong&gt; — This one's special. Paste raw CSS, get Tailwind utility classes. 200+ property mappings, dark mode support, arbitrary value handling, color palette resolution, and &lt;code&gt;@media&lt;/code&gt; block support. Bidirectional — paste Tailwind, get CSS back. I use this daily.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Base64 Encoder/Decoder&lt;/strong&gt; — Real-time conversion. Full Unicode support. One-click copy. Encoding &lt;code&gt;eyJhbGciOiJIUzI1NiJ9&lt;/code&gt; shouldn't require a three-step process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;URL Encoder/Decoder&lt;/strong&gt; — Encode and decode URL components instantly. Handles query parameters, path segments, and special characters. Works in both directions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JWT Token Decoder&lt;/strong&gt; — Paste any JWT, see the header, payload, and signature decoded instantly. Check expiration, algorithm, and claims. Nothing leaves your browser. This is the tool I wish existed three years ago.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design Tools
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;CSS Gradient Builder&lt;/strong&gt; — Linear, radial, and conic gradients with draggable color stops, angle control, and live preview. Copy the CSS output. No more guessing what &lt;code&gt;linear-gradient(135deg, #667eea 0%, #764ba2 100%)&lt;/code&gt; actually looks like.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Box Shadow Generator&lt;/strong&gt; — Multi-layer support, inset mode, blur, spread, and offset. Live preview with copy-ready CSS output. Build complex shadow systems without opening Figma.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Color Contrast Checker&lt;/strong&gt; — WCAG 2.1 AA and AAA compliance checking. Enter foreground and background colors, get instant pass/fail results. Accessibility compliance without the accessibility audit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generators
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;QR Code Generator&lt;/strong&gt; — Enter text or URL, get a downloadable PNG. Canvas-based rendering, no watermarks. Works offline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Password Generator&lt;/strong&gt; — Cryptographically strong passwords with configurable length, character types, and a real-time strength meter. The kind of password generator that actually generates &lt;em&gt;strong&lt;/em&gt; passwords.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UUID Generator&lt;/strong&gt; — Batch generate up to 100 UUID v4 identifiers. Standard (hyphenated) or compact format. One click, done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Timestamp Converter&lt;/strong&gt; — Unix timestamps to human-readable dates and back. Supports seconds and milliseconds, ISO 8601, and custom date formats. Finally, a timestamp tool that doesn't make you count zeros.&lt;/p&gt;

&lt;h3&gt;
  
  
  Utilities
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Flexbox &amp;amp; Grid Playground&lt;/strong&gt; — Drag and drop elements to build flexbox and grid layouts visually. See the Tailwind output update in real-time as you adjust gaps and alignment. Learn CSS layout without reading MDN for the 47th time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Text Tokenizer&lt;/strong&gt; — Count tokens, words, characters, and lines. Visual token breakdown shows exactly how your text gets tokenized. Essential for LLM prompt engineering and staying within context windows.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Interactive Terminal (My Favorite Feature)
&lt;/h2&gt;

&lt;p&gt;Here's something you won't find in any other web-based dev tool: &lt;strong&gt;a working terminal.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;DevClat has a mock CLI built right into the homepage. Type &lt;code&gt;help&lt;/code&gt; to see available commands. Type &lt;code&gt;open generator&lt;/code&gt; to switch tools. Type &lt;code&gt;list&lt;/code&gt; to see everything available.&lt;/p&gt;

&lt;p&gt;It auto-types a demo command when you load the page — &lt;code&gt;devclat mock-data --users 3 --format json&lt;/code&gt; — and shows you the output in real-time with syntax-highlighted JSON.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This isn't a gimmick.&lt;/strong&gt; It's a deliberate UX choice. Instead of forcing you to click through a grid of icons to find what you need, the terminal gives keyboard-first users a fast, predictable way to navigate. Type a command, get a result. No hunting, no scrolling.&lt;/p&gt;

&lt;p&gt;Click "Try CLI" and the terminal focuses, auto-types &lt;code&gt;help&lt;/code&gt;, and shows you exactly how to interact with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It's Built
&lt;/h2&gt;

&lt;p&gt;I'm not going to pretend this is rocket science. The architecture is deliberately simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React 19&lt;/strong&gt; for the UI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vite 6&lt;/strong&gt; for the build&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS 4&lt;/strong&gt; for styling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;faker.js&lt;/strong&gt; for mock data generation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;qrcode&lt;/strong&gt; library for QR code rendering&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every tool is a standalone component. Navigation is managed via a single &lt;code&gt;activeTool&lt;/code&gt; state variable — no client-side router, no URL history, no complex state management. Switching tools is instant because everything is already loaded.&lt;/p&gt;

&lt;p&gt;The theme system uses CSS variables synced with a JavaScript constants file. Dark mode is default. Light mode works. Both are clean.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The key insight:&lt;/strong&gt; you don't need a backend for developer tools. Every tool I listed above can be implemented entirely with JavaScript string manipulation, DOM APIs, and browser-native features. The moment you add a server, you add latency, complexity, privacy concerns, and a maintenance burden. I chose none of those.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;There are hundreds of "free online developer tools" out there. Most of them are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ad-supported&lt;/strong&gt; — banner ads, pop-ups, and "disable your ad blocker" notices&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server-dependent&lt;/strong&gt; — your data gets sent somewhere, processed, and (maybe) deleted&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tracker-heavy&lt;/strong&gt; — analytics scripts, fingerprinting, and retargeting pixels&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offline-hostile&lt;/strong&gt; — try using them on a plane or a spotty coffee shop WiFi&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;DevClat is none of these things. It's a static site. There's nothing to track because there's nothing to send. It works offline because there's nothing to fetch. It's fast because there's nothing to wait for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Privacy isn't a feature. It's the architecture.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;I'm adding more tools. The architecture scales trivially — create a component, add it to the tool list, done. Some ideas in the pipeline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CSS variable inspector&lt;/li&gt;
&lt;li&gt;API response mock server (local, via Service Worker)&lt;/li&gt;
&lt;li&gt;Diff viewer for entire files&lt;/li&gt;
&lt;li&gt;More data presets for the mock generator&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've got ideas, or if you want to contribute, the project is built to be extended.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;No sign-up. No "free trial." No credit card. Just tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://devclat.vercel.app" rel="noopener noreferrer"&gt;Open the Free DevClat Toolkit →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Paste a JWT token. Generate some fake data. Convert CSS to Tailwind. Build a gradient. Check a password's strength. Whatever you need — it's all client-side, all private, all free.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with React, Vite, and a deep distrust of random web utilities that ask you to paste your API keys.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
      <category>security</category>
    </item>
  </channel>
</rss>
