@prosopo/procaptcha-frictionless 2.12.10 → 2.12.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
 
2
- > @prosopo/procaptcha-frictionless@2.12.10 build:cjs
2
+ > @prosopo/procaptcha-frictionless@2.12.11 build:cjs
3
3
  > NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV
4
4
 
5
5
  ViteCommonJSConfig: .
@@ -61,6 +61,6 @@ rendering chunks...
61
61
  dist/cjs/index.cjs 0.24 kB
62
62
  dist/cjs/sessionInvalidatedRecovery.cjs 0.85 kB
63
63
  dist/cjs/detectorLoader.cjs 1.37 kB
64
- dist/cjs/customDetectBot.cjs 4.01 kB
64
+ dist/cjs/customDetectBot.cjs 4.26 kB
65
65
  dist/cjs/ProcaptchaFrictionless.cjs 9.11 kB
66
- ✓ built in 135ms
66
+ ✓ built in 86ms
@@ -1,8 +1,8 @@
1
1
 
2
- > @prosopo/procaptcha-frictionless@2.12.10 build:tsc
2
+ > @prosopo/procaptcha-frictionless@2.12.11 build:tsc
3
3
  > tsc --build --verbose
4
4
 
5
- 8:57:20 AM - Projects in this build:
5
+ 10:35:14 AM - Projects in this build:
6
6
  * ../../dev/config/tsconfig.json
7
7
  * ../locale/tsconfig.json
8
8
  * ../util/tsconfig.json
@@ -26,49 +26,49 @@
26
26
  * ../procaptcha-react/tsconfig.json
27
27
  * tsconfig.json
28
28
 
29
- 8:57:20 AM - Project '../../dev/config/tsconfig.json' is up to date because newest input '../../dev/config/src/webpack/webpack.config.ts' is older than output '../../dev/config/tsconfig.tsbuildinfo'
29
+ 10:35:14 AM - Project '../../dev/config/tsconfig.json' is up to date because newest input '../../dev/config/src/webpack/webpack.config.ts' is older than output '../../dev/config/tsconfig.tsbuildinfo'
30
30
 
31
- 8:57:20 AM - Project '../locale/tsconfig.json' is up to date because newest input '../locale/src/translationKey.ts' is older than output '../locale/tsconfig.tsbuildinfo'
31
+ 10:35:14 AM - Project '../locale/tsconfig.json' is up to date because newest input '../locale/src/translationKey.ts' is older than output '../locale/tsconfig.tsbuildinfo'
32
32
 
33
- 8:57:20 AM - Project '../util/tsconfig.json' is up to date because newest input '../util/src/url.ts' is older than output '../util/tsconfig.tsbuildinfo'
33
+ 10:35:14 AM - Project '../util/tsconfig.json' is up to date because newest input '../util/src/url.ts' is older than output '../util/tsconfig.tsbuildinfo'
34
34
 
35
- 8:57:20 AM - Project '../util-crypto/tsconfig.json' is up to date because newest input '../util-crypto/src/types.ts' is older than output '../util-crypto/tsconfig.tsbuildinfo'
35
+ 10:35:14 AM - Project '../util-crypto/tsconfig.json' is up to date because newest input '../util-crypto/src/types.ts' is older than output '../util-crypto/tsconfig.tsbuildinfo'
36
36
 
37
- 8:57:20 AM - Project '../types/tsconfig.json' is up to date because newest input '../types/src/provider/api.ts' is older than output '../types/tsconfig.tsbuildinfo'
37
+ 10:35:14 AM - Project '../types/tsconfig.json' is up to date because newest input '../types/src/provider/api.ts' is older than output '../types/tsconfig.tsbuildinfo'
38
38
 
39
- 8:57:20 AM - Project '../detector/tsconfig.json' is up to date because newest input '../detector/src/index.js' is older than output '../detector/tsconfig.tsbuildinfo'
39
+ 10:35:14 AM - Project '../detector/tsconfig.json' is up to date because newest input '../detector/src/index.js' is older than output '../detector/tsconfig.tsbuildinfo'
40
40
 
41
- 8:57:20 AM - Project '../api/tsconfig.json' is up to date because newest input '../api/src/index.ts' is older than output '../api/tsconfig.tsbuildinfo'
41
+ 10:35:14 AM - Project '../api/tsconfig.json' is up to date because newest input '../api/src/index.ts' is older than output '../api/tsconfig.tsbuildinfo'
42
42
 
43
- 8:57:20 AM - Project '../logger/tsconfig.json' is up to date because newest input '../logger/src/index.ts' is older than output '../logger/tsconfig.tsbuildinfo'
43
+ 10:35:14 AM - Project '../logger/tsconfig.json' is up to date because newest input '../logger/src/index.ts' is older than output '../logger/tsconfig.tsbuildinfo'
44
44
 
45
- 8:57:20 AM - Project '../common/tsconfig.json' is up to date because newest input '../common/src/index.ts' is older than output '../common/tsconfig.tsbuildinfo'
45
+ 10:35:14 AM - Project '../common/tsconfig.json' is up to date because newest input '../common/src/error.ts' is older than output '../common/tsconfig.tsbuildinfo'
46
46
 
47
- 8:57:20 AM - Project '../fingerprintjs/tsconfig.json' is up to date because newest input '../fingerprintjs/src/utils/browser.ts' is older than output '../fingerprintjs/tsconfig.tsbuildinfo'
47
+ 10:35:14 AM - Project '../fingerprintjs/tsconfig.json' is up to date because newest input '../fingerprintjs/src/utils/browser.ts' is older than output '../fingerprintjs/tsconfig.tsbuildinfo'
48
48
 
49
- 8:57:20 AM - Project '../fingerprint/tsconfig.json' is up to date because newest input '../fingerprint/src/index.ts' is older than output '../fingerprint/tsconfig.tsbuildinfo'
49
+ 10:35:14 AM - Project '../fingerprint/tsconfig.json' is up to date because newest input '../fingerprint/src/index.ts' is older than output '../fingerprint/tsconfig.tsbuildinfo'
50
50
 
51
- 8:57:20 AM - Project '../load-balancer/tsconfig.json' is up to date because newest input '../load-balancer/src/index.ts' is older than output '../load-balancer/tsconfig.tsbuildinfo'
51
+ 10:35:14 AM - Project '../load-balancer/tsconfig.json' is up to date because newest input '../load-balancer/src/balancer.ts' is older than output '../load-balancer/tsconfig.tsbuildinfo'
52
52
 
53
- 8:57:20 AM - Project '../widget-skeleton/tsconfig.json' is up to date because newest input '../widget-skeleton/src/webComponent/createWidget.ts' is older than output '../widget-skeleton/tsconfig.tsbuildinfo'
53
+ 10:35:15 AM - Project '../widget-skeleton/tsconfig.json' is up to date because newest input '../widget-skeleton/src/constants.ts' is older than output '../widget-skeleton/tsconfig.tsbuildinfo'
54
54
 
55
- 8:57:20 AM - Project '../keyring/tsconfig.json' is up to date because newest input '../keyring/src/keyring/keyring.ts' is older than output '../keyring/tsconfig.tsbuildinfo'
55
+ 10:35:15 AM - Project '../keyring/tsconfig.json' is up to date because newest input '../keyring/src/index.ts' is older than output '../keyring/tsconfig.tsbuildinfo'
56
56
 
57
- 8:57:20 AM - Project '../account/tsconfig.json' is up to date because newest input '../account/src/custom.d.ts' is older than output '../account/tsconfig.tsbuildinfo'
57
+ 10:35:15 AM - Project '../account/tsconfig.json' is up to date because newest input '../account/src/workers/cryptoWorker.ts' is older than output '../account/tsconfig.tsbuildinfo'
58
58
 
59
- 8:57:20 AM - Project '../procaptcha-common/tsconfig.json' is up to date because newest input '../procaptcha-common/src/extensionLoader.ts' is older than output '../procaptcha-common/tsconfig.tsbuildinfo'
59
+ 10:35:15 AM - Project '../procaptcha-common/tsconfig.json' is up to date because newest input '../procaptcha-common/src/tests/defaultEvents.test.ts' is older than output '../procaptcha-common/tsconfig.tsbuildinfo'
60
60
 
61
- 8:57:20 AM - Project '../procaptcha-pow/tsconfig.json' is up to date because newest input '../procaptcha-pow/src/index.ts' is older than output '../procaptcha-pow/tsconfig.tsbuildinfo'
61
+ 10:35:15 AM - Project '../procaptcha-pow/tsconfig.json' is up to date because newest input '../procaptcha-pow/src/index.ts' is older than output '../procaptcha-pow/tsconfig.tsbuildinfo'
62
62
 
63
- 8:57:20 AM - Project '../procaptcha-puzzle/tsconfig.json' is up to date because newest input '../procaptcha-puzzle/src/index.ts' is older than output '../procaptcha-puzzle/tsconfig.tsbuildinfo'
63
+ 10:35:15 AM - Project '../procaptcha-puzzle/tsconfig.json' is up to date because newest input '../procaptcha-puzzle/src/index.ts' is older than output '../procaptcha-puzzle/tsconfig.tsbuildinfo'
64
64
 
65
- 8:57:20 AM - Project '../datasets/tsconfig.json' is up to date because newest input '../datasets/src/tests/mocks/data/captchas.ts' is older than output '../datasets/tsconfig.tsbuildinfo'
65
+ 10:35:15 AM - Project '../datasets/tsconfig.json' is up to date because newest input '../datasets/src/index.ts' is older than output '../datasets/tsconfig.tsbuildinfo'
66
66
 
67
- 8:57:20 AM - Project '../procaptcha/tsconfig.json' is up to date because newest input '../procaptcha/src/index.ts' is older than output '../procaptcha/tsconfig.tsbuildinfo'
67
+ 10:35:15 AM - Project '../procaptcha/tsconfig.json' is up to date because newest input '../procaptcha/src/index.ts' is older than output '../procaptcha/tsconfig.tsbuildinfo'
68
68
 
69
- 8:57:20 AM - Project '../procaptcha-react/tsconfig.json' is up to date because newest input '../procaptcha-react/src/index.ts' is older than output '../procaptcha-react/tsconfig.tsbuildinfo'
69
+ 10:35:15 AM - Project '../procaptcha-react/tsconfig.json' is up to date because newest input '../procaptcha-react/src/index.ts' is older than output '../procaptcha-react/tsconfig.tsbuildinfo'
70
70
 
71
- 8:57:20 AM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
71
+ 10:35:15 AM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
72
72
 
73
- 8:57:20 AM - Building project '/home/runner/work/captcha/captcha/packages/procaptcha-frictionless/tsconfig.json'...
73
+ 10:35:15 AM - Building project '/home/runner/work/captcha/captcha/packages/procaptcha-frictionless/tsconfig.json'...
74
74
 
@@ -1,9 +1,9 @@
1
1
 
2
- > @prosopo/procaptcha-frictionless@2.12.10 build
2
+ > @prosopo/procaptcha-frictionless@2.12.11 build
3
3
  > npm run build:cross-env -- --mode ${NODE_ENV:-development}
4
4
 
5
5
 
6
- > @prosopo/procaptcha-frictionless@2.12.10 build:cross-env
6
+ > @prosopo/procaptcha-frictionless@2.12.11 build:cross-env
7
7
  > vite build --config vite.esm.config.ts --mode production
8
8
 
9
9
  ViteEsmConfig: .
@@ -64,6 +64,6 @@ rendering chunks...
64
64
  dist/index.js 0.11 kB
65
65
  dist/detectorLoader.js 0.11 kB
66
66
  dist/sessionInvalidatedRecovery.js 0.71 kB
67
- dist/customDetectBot.js 3.83 kB
67
+ dist/customDetectBot.js 4.08 kB
68
68
  dist/ProcaptchaFrictionless.js 7.67 kB
69
- ✓ built in 196ms
69
+ ✓ built in 146ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @prosopo/procaptcha-frictionless
2
2
 
3
+ ## 2.12.11
4
+ ### Patch Changes
5
+
6
+ - 85e8857: Record both the top-frame URL and the widget's own iframe URL on frictionless sessions.
7
+
8
+ Previously the client only sent one field (`currentUrl`), which for embedded widgets resolved to the top-frame URL — so we lost visibility into which iframe endpoint the session was actually loaded through. Now the client sends both:
9
+
10
+ - `currentUrl`: the top-frame URL (same resolution rules as before — same-origin iframes read `window.top.location.href` directly; cross-origin iframes fall back to `document.referrer`).
11
+ - `iframeUrl`: the widget's own frame URL when embedded. Undefined when the widget IS the top frame (nothing to distinguish).
12
+
13
+ Both fields are sanitised client- and server-side (origin + path only; query string, fragment and any embedded credentials stripped). The provider persists both on the `Session` record and re-uses them on post-PoW escalation sessions. Only `currentUrl` is gated in the frictionless decision machine (unchanged — missing `currentUrl` still forces an image captcha); `iframeUrl` is recorded for analytics.
14
+
15
+ Both fields are also surfaced to the decision machines as raw signals: `RoutingMachineRawSignals` gains an optional `iframeUrl` populated from the freshly decrypted frictionless payload on the `route` phase, from the persisted Session record on the `postPow` phase, and from the cached Session in the dedup replay path — matching how `currentUrl` is already threaded through.
16
+
17
+ Additionally, sessions carry a new computed boolean `isProtect`, set at session-creation time when the widget iframe was served from `protect.<tenant>` and embedded in a page on the same tenant (subdomain-of matching, dot-boundary safe — see `isProtectDeployment` in `@prosopo/util`). Persisted only when true (same pattern as `isEscalation`) and backed by a sparse `{isProtect, createdAt}` index so analytics can cheaply retrieve Protect sessions without re-parsing URLs. Post-PoW escalation sessions inherit the flag from the origin session.
18
+ - Updated dependencies [85e8857]
19
+ - @prosopo/api@3.5.15
20
+ - @prosopo/types@4.9.8
21
+ - @prosopo/procaptcha-pow@2.10.15
22
+ - @prosopo/procaptcha-puzzle@2.10.30
23
+ - @prosopo/common@3.1.44
24
+ - @prosopo/detector@3.5.9
25
+ - @prosopo/procaptcha-common@2.11.9
26
+ - @prosopo/procaptcha-react@2.9.88
27
+
3
28
  ## 2.12.10
4
29
  ### Patch Changes
5
30
 
@@ -13,27 +13,29 @@ const sanitiseHref = (href) => {
13
13
  return void 0;
14
14
  }
15
15
  };
16
- const getCurrentPageUrl = () => {
16
+ const getCurrentPageUrls = () => {
17
17
  if (typeof window === "undefined" || !window.location) {
18
- return void 0;
18
+ return { currentUrl: void 0, iframeUrl: void 0 };
19
19
  }
20
20
  const local = (() => {
21
21
  const { origin, pathname } = window.location;
22
22
  if (!origin || origin === "null") return void 0;
23
23
  return `${origin}${pathname || ""}`;
24
24
  })();
25
- if (window === window.top) return local;
25
+ if (window === window.top) {
26
+ return { currentUrl: local, iframeUrl: void 0 };
27
+ }
26
28
  try {
27
29
  const topHref = window.top?.location?.href;
28
30
  const sanitised = topHref ? sanitiseHref(topHref) : void 0;
29
- if (sanitised) return sanitised;
31
+ if (sanitised) return { currentUrl: sanitised, iframeUrl: local };
30
32
  } catch {
31
33
  }
32
34
  if (typeof document !== "undefined" && document.referrer) {
33
35
  const fromReferrer = sanitiseHref(document.referrer);
34
- if (fromReferrer) return fromReferrer;
36
+ if (fromReferrer) return { currentUrl: fromReferrer, iframeUrl: local };
35
37
  }
36
- return local;
38
+ return { currentUrl: local, iframeUrl: local };
37
39
  };
38
40
  const withTimeout = async (promise, ms) => {
39
41
  let timeoutId;
@@ -81,6 +83,7 @@ const customDetectBot = async (config, container, restartFn, retryContext) => {
81
83
  provider.provider.url,
82
84
  config.account.address
83
85
  );
86
+ const { currentUrl, iframeUrl } = getCurrentPageUrls();
84
87
  const captchaPromise = providerApi.getFrictionlessCaptcha(
85
88
  detectionResult.token,
86
89
  detectionResult.encryptHeadHash,
@@ -88,7 +91,8 @@ const customDetectBot = async (config, container, restartFn, retryContext) => {
88
91
  userAccount.account.address,
89
92
  config.mode,
90
93
  void 0,
91
- getCurrentPageUrl()
94
+ currentUrl,
95
+ iframeUrl
92
96
  );
93
97
  if (detectionResult.getSimdReadings) {
94
98
  void detectionResult.getSimdReadings(6e4).catch(() => void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"customDetectBot.d.ts","sourceRoot":"","sources":["../src/customDetectBot.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EACX,oBAAoB,EAGpB,MAAM,gBAAgB,CAAC;AA8DxB,eAAO,MAAM,WAAW,GAAU,CAAC,WACzB,OAAO,CAAC,CAAC,CAAC,MACf,MAAM,KACR,OAAO,CAAC,CAAC,CAoBX,CAAC;AAEF,QAAA,MAAM,eAAe,EAAE,oBAwGtB,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"customDetectBot.d.ts","sourceRoot":"","sources":["../src/customDetectBot.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EACX,oBAAoB,EAGpB,MAAM,gBAAgB,CAAC;AA2ExB,eAAO,MAAM,WAAW,GAAU,CAAC,WACzB,OAAO,CAAC,CAAC,CAAC,MACf,MAAM,KACR,OAAO,CAAC,CAAC,CAoBX,CAAC;AAEF,QAAA,MAAM,eAAe,EAAE,oBA0GtB,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -11,27 +11,29 @@ const sanitiseHref = (href) => {
11
11
  return void 0;
12
12
  }
13
13
  };
14
- const getCurrentPageUrl = () => {
14
+ const getCurrentPageUrls = () => {
15
15
  if (typeof window === "undefined" || !window.location) {
16
- return void 0;
16
+ return { currentUrl: void 0, iframeUrl: void 0 };
17
17
  }
18
18
  const local = (() => {
19
19
  const { origin, pathname } = window.location;
20
20
  if (!origin || origin === "null") return void 0;
21
21
  return `${origin}${pathname || ""}`;
22
22
  })();
23
- if (window === window.top) return local;
23
+ if (window === window.top) {
24
+ return { currentUrl: local, iframeUrl: void 0 };
25
+ }
24
26
  try {
25
27
  const topHref = window.top?.location?.href;
26
28
  const sanitised = topHref ? sanitiseHref(topHref) : void 0;
27
- if (sanitised) return sanitised;
29
+ if (sanitised) return { currentUrl: sanitised, iframeUrl: local };
28
30
  } catch {
29
31
  }
30
32
  if (typeof document !== "undefined" && document.referrer) {
31
33
  const fromReferrer = sanitiseHref(document.referrer);
32
- if (fromReferrer) return fromReferrer;
34
+ if (fromReferrer) return { currentUrl: fromReferrer, iframeUrl: local };
33
35
  }
34
- return local;
36
+ return { currentUrl: local, iframeUrl: local };
35
37
  };
36
38
  const withTimeout = async (promise, ms) => {
37
39
  let timeoutId;
@@ -79,6 +81,7 @@ const customDetectBot = async (config, container, restartFn, retryContext) => {
79
81
  provider.provider.url,
80
82
  config.account.address
81
83
  );
84
+ const { currentUrl, iframeUrl } = getCurrentPageUrls();
82
85
  const captchaPromise = providerApi.getFrictionlessCaptcha(
83
86
  detectionResult.token,
84
87
  detectionResult.encryptHeadHash,
@@ -86,7 +89,8 @@ const customDetectBot = async (config, container, restartFn, retryContext) => {
86
89
  userAccount.account.address,
87
90
  config.mode,
88
91
  void 0,
89
- getCurrentPageUrl()
92
+ currentUrl,
93
+ iframeUrl
90
94
  );
91
95
  if (detectionResult.getSimdReadings) {
92
96
  void detectionResult.getSimdReadings(6e4).catch(() => void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"customDetectBot.js","sourceRoot":"","sources":["../src/customDetectBot.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"customDetectBot.js","sourceRoot":"","sources":["../src/customDetectBot.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prosopo/procaptcha-frictionless",
3
- "version": "2.12.10",
3
+ "version": "2.12.11",
4
4
  "author": "PROSOPO LIMITED <info@prosopo.io>",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/index.js",
@@ -30,15 +30,15 @@
30
30
  },
31
31
  "browserslist": ["> 0.5%, last 2 versions, not dead"],
32
32
  "dependencies": {
33
- "@prosopo/api": "3.5.14",
34
- "@prosopo/common": "3.1.43",
35
- "@prosopo/detector": "3.5.8",
33
+ "@prosopo/api": "3.5.15",
34
+ "@prosopo/common": "3.1.44",
35
+ "@prosopo/detector": "3.5.9",
36
36
  "@prosopo/locale": "3.2.6",
37
- "@prosopo/procaptcha-common": "2.11.8",
38
- "@prosopo/procaptcha-pow": "2.10.14",
39
- "@prosopo/procaptcha-puzzle": "2.10.29",
40
- "@prosopo/procaptcha-react": "2.9.87",
41
- "@prosopo/types": "4.9.7",
37
+ "@prosopo/procaptcha-common": "2.11.9",
38
+ "@prosopo/procaptcha-pow": "2.10.15",
39
+ "@prosopo/procaptcha-puzzle": "2.10.30",
40
+ "@prosopo/procaptcha-react": "2.9.88",
41
+ "@prosopo/types": "4.9.8",
42
42
  "@prosopo/widget-skeleton": "2.8.4",
43
43
  "dotenv": "16.4.5",
44
44
  "react": "18.3.1"
@@ -27,22 +27,25 @@ import type {
27
27
  import type { BotDetectionFunctionResult } from "@prosopo/types";
28
28
  import { DetectorLoader } from "./detectorLoader.js";
29
29
 
30
- // The page the widget is rendered on, reduced to origin + path. Deliberately
31
- // built from `origin` + `pathname` (never `href`) so the query string,
32
- // fragment, and any embedded `user:pass@` credentials never leave the browser
33
- // — sites routinely carry tokens / session ids / reset codes in those parts.
34
- // Returns undefined in non-browser contexts (SSR / tests) or for opaque
35
- // origins; the provider then treats the session as having no page URL and
36
- // forces an image captcha.
30
+ // The page(s) the widget is rendered on, reduced to origin + path.
31
+ // Deliberately built from `origin` + `pathname` (never `href`) so the query
32
+ // string, fragment, and any embedded `user:pass@` credentials never leave the
33
+ // browser — sites routinely carry tokens / session ids / reset codes in those
34
+ // parts.
37
35
  //
38
- // When we're loaded inside an iframe (Protect's site-wide embed) the local
39
- // `window.location` is the iframe URL, which conveys nothing about the page
40
- // the user is actually on every session across the tenant ends up
41
- // reporting the same widget endpoint. Same-origin iframes let us read the
42
- // top frame directly; cross-origin iframes fall through to `document.referrer`,
43
- // which the browser fills with the embedding page URL subject to
44
- // Referrer-Policy. Only when both are unavailable do we fall back to the
45
- // iframe's own URL, matching the previous behaviour.
36
+ // Returns two fields:
37
+ // - `currentUrl`: the top-frame URL as best we can determine it. Same-origin
38
+ // iframes read it directly; cross-origin iframes fall back to
39
+ // `document.referrer`, which the browser fills with the embedding page URL
40
+ // subject to Referrer-Policy. When neither is available the field falls
41
+ // back to the local (iframe) URL so the provider still sees a value.
42
+ // - `iframeUrl`: the widget's own frame URL when we're embedded. Undefined
43
+ // when the widget IS the top frame — nothing to distinguish. Emitted so
44
+ // downstream analytics can separate "Protect's site-wide iframe endpoint"
45
+ // from "the page the user was actually on".
46
+ //
47
+ // Both fields are undefined in non-browser contexts (SSR / tests) or for
48
+ // opaque origins.
46
49
  const sanitiseHref = (href: string): string | undefined => {
47
50
  try {
48
51
  const u = new URL(href);
@@ -53,9 +56,14 @@ const sanitiseHref = (href: string): string | undefined => {
53
56
  }
54
57
  };
55
58
 
56
- const getCurrentPageUrl = (): string | undefined => {
59
+ type PageUrls = {
60
+ currentUrl: string | undefined;
61
+ iframeUrl: string | undefined;
62
+ };
63
+
64
+ const getCurrentPageUrls = (): PageUrls => {
57
65
  if (typeof window === "undefined" || !window.location) {
58
- return undefined;
66
+ return { currentUrl: undefined, iframeUrl: undefined };
59
67
  }
60
68
  const local = (() => {
61
69
  const { origin, pathname } = window.location;
@@ -63,14 +71,16 @@ const getCurrentPageUrl = (): string | undefined => {
63
71
  return `${origin}${pathname || ""}`;
64
72
  })();
65
73
 
66
- // Top window — the iframe path doesn't apply.
67
- if (window === window.top) return local;
74
+ // Top window — no iframe distinction, report the local URL only.
75
+ if (window === window.top) {
76
+ return { currentUrl: local, iframeUrl: undefined };
77
+ }
68
78
 
69
79
  // Same-origin iframe — read the top URL directly.
70
80
  try {
71
81
  const topHref = window.top?.location?.href;
72
82
  const sanitised = topHref ? sanitiseHref(topHref) : undefined;
73
- if (sanitised) return sanitised;
83
+ if (sanitised) return { currentUrl: sanitised, iframeUrl: local };
74
84
  } catch {
75
85
  /* cross-origin — fall through */
76
86
  }
@@ -79,10 +89,13 @@ const getCurrentPageUrl = (): string | undefined => {
79
89
  // subject to the parent's Referrer-Policy header.
80
90
  if (typeof document !== "undefined" && document.referrer) {
81
91
  const fromReferrer = sanitiseHref(document.referrer);
82
- if (fromReferrer) return fromReferrer;
92
+ if (fromReferrer) return { currentUrl: fromReferrer, iframeUrl: local };
83
93
  }
84
94
 
85
- return local;
95
+ // Referrer unavailable — fall back to the iframe URL for `currentUrl` so
96
+ // the provider still sees a value, and echo it as `iframeUrl` so
97
+ // downstream can tell the top frame was not observed.
98
+ return { currentUrl: local, iframeUrl: local };
86
99
  };
87
100
 
88
101
  export const withTimeout = async <T>(
@@ -165,6 +178,7 @@ const customDetectBot: BotDetectionFunction = async (
165
178
  // lets it complete in the worker thread while the network round-trip
166
179
  // burns. Readings still attach on the challenge GET and on solution
167
180
  // submit (first-hop-wins server-side).
181
+ const { currentUrl, iframeUrl } = getCurrentPageUrls();
168
182
  const captchaPromise = providerApi.getFrictionlessCaptcha(
169
183
  detectionResult.token,
170
184
  detectionResult.encryptHeadHash,
@@ -172,7 +186,8 @@ const customDetectBot: BotDetectionFunction = async (
172
186
  userAccount.account.address,
173
187
  config.mode,
174
188
  undefined,
175
- getCurrentPageUrl(),
189
+ currentUrl,
190
+ iframeUrl,
176
191
  );
177
192
  if (detectionResult.getSimdReadings) {
178
193
  // Fire-and-forget: triggers the memoised prefetch inside the catcher
@@ -93,7 +93,7 @@ describe("customDetectBot SIMD deferral", () => {
93
93
 
94
94
  expect(mocks.getFrictionlessCaptcha).toHaveBeenCalledTimes(1);
95
95
  const args = mocks.getFrictionlessCaptcha.mock.calls[0];
96
- // args: token, headHash, dappAccount, userAccount, mode, simdReadings, currentUrl
96
+ // args: token, headHash, dappAccount, userAccount, mode, simdReadings, currentUrl, iframeUrl
97
97
  expect(args?.[5]).toBeUndefined();
98
98
  });
99
99