Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions packages/script/src/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@
// Common script attributes
const API_HOST = script.getAttribute('data-api-host') || 'https://api.dub.co';
const PUBLISHABLE_KEY = script.getAttribute('data-publishable-key');
// Domains on the Public Suffix List that browsers treat as TLDs.
// Cookies cannot be set on these domains — the browser silently drops them.
const KNOWN_PSL_DOMAINS = [
'vercel.app', 'vercel.dev', 'vercel.run', 'now.sh', 'v0.build',
'vusercontent.net', 'netlify.app', 'pages.dev', 'github.io', 'fly.dev',
'railway.app', 'onrender.com', 'web.app', 'firebaseapp.com',
'surge.sh', 'azurewebsites.net', 'amplifyapp.com',
];

const COOKIE_OPTIONS = (() => {
const defaultOptions = {
domain:
Expand All @@ -32,6 +41,19 @@
delete parsedOpts.expiresInDays;
}

if (parsedOpts.domain) {
const bare = parsedOpts.domain.trim().replace(/^\./, '').toLowerCase();
if (KNOWN_PSL_DOMAINS.includes(bare)) {
console.warn(
Comment thread
coderabbitai[bot] marked this conversation as resolved.
`[dubAnalytics] cookieOptions.domain "${parsedOpts.domain}" is on the Public Suffix List. ` +
`Browsers silently reject cookies set on PSL domains. ` +
`Falling back to the default domain "${defaultOptions.domain}". ` +
`Cross-subdomain cookie sharing under a PSL domain is not possible via client-side cookies.`,
);
delete parsedOpts.domain;
}
}

return { ...defaultOptions, ...parsedOpts };
})();

Expand Down
2 changes: 2 additions & 0 deletions packages/web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ The `cookieOptions` prop accepts the following keys:
| `expiresInDays` | `90` | Specifies the number (in days) to be the value for the `Expires` Set-Cookie attribute. | `90` |
| `path` | `/` | Specifies the value for the `Path` Set-Cookie attribute. By default, the path is considered the "default path". | `/` |

> **Note:** Domains on the [Public Suffix List](https://publicsuffix.org/) (PSL) — such as `.vercel.app`, `.netlify.app`, `.github.io`, or `.pages.dev` — **cannot** be used as cookie domains. Browsers silently reject cookies set on PSL entries because these suffixes are treated like top-level domains (`.com`, `.io`). If you pass a PSL domain, the script will log a `console.warn` and fall back to the current hostname. Cross-subdomain cookie sharing under a PSL domain is not achievable via client-side cookies.

For example, to set a 60-day cookie window, you can use the following code:

```tsx
Expand Down
8 changes: 8 additions & 0 deletions packages/web/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ export interface AnalyticsProps {
* By default, the domain is set to the current hostname (including all subdomains).
*
* @default `.` + window.location.hostname
*
* **Warning:** Domains listed on the {@link https://publicsuffix.org/|Public Suffix List} (PSL) —
* such as `.vercel.app`, `.netlify.app`, `.github.io`, or `.pages.dev` — cannot be used as
* cookie domains. Browsers silently reject `document.cookie` writes that target a PSL entry,
* because these suffixes are treated equivalently to top-level domains like `.com`.
* If you provide a PSL domain, the script will log a warning and fall back to the default
* hostname-derived domain. Cross-subdomain cookie sharing under a PSL domain is not achievable
* via client-side cookies.
*/
domain?: string | undefined;

Expand Down
Loading