When SeaText AI Causes Cross-Origin Issues in Multi-Domain Setups
SeaText AI triggers cross-origin problems when its script loads from a different origin than your SPA domains without proper CORS headers, or when API calls to the translation service are blocked by the browser's...
SeaText AI typically causes cross-origin issues in two situations: when the SeaText script is served from a different origin than the page that loads it and the response lacks the required Access-Control-Allow-Origin header, and when the script makes API requests to SeaText's translation backend from a domain that the backend does not explicitly allow. Both cases are rooted in the browser's same-origin policy, which treats any difference in scheme, host, or port as a separate origin.
What cross-origin means for a SeaText integration
Cross-origin resource sharing (CORS) is a browser security mechanism that controls whether a page can load scripts, fetch data, or access storage from another origin. SeaText AI runs as a client-side JavaScript snippet. If that snippet is hosted on cdn.seatext.com (for example) while your application runs on app.example.com and shop.example.com, every page load involves a cross-origin script request. The browser will allow the script to execute, but any subsequent fetch or XMLHttpRequest the script makes to SeaText's API endpoints will be blocked unless those endpoints return the correct CORS headers.
The SeaText documentation for SPAs notes: "If your SPA interacts with multiple domains, ensure that the SEATEXT AI script is compatible and does not face cross-origin issues." This guidance assumes you control the snippet delivery and the API permissions.
Common multi-domain setups that trigger the problem
- Subdomain sprawl: A single SeaText snippet embedded in
app.example.com,blog.example.com, andshop.example.com. Each subdomain is a distinct origin. - Separate brand domains:
brand-a.comandbrand-b.comboth include the same SeaText snippet. - Staging and production parity:
staging.example.comandexample.comshare the snippet but the API allow-list only contains the production domain. - CDN vs. first-party hosting: The snippet loads from a CDN origin while the API calls go to
api.seatext.com; if the CDN origin isn't in the API's allow-list, the preflight request fails.
How the SeaText script loads and where CORS applies
The integration guide shows the snippet includes an async attribute on the script tag. This means the browser downloads the script asynchronously, but the download itself is still a cross-origin request if the script URL differs from the page origin. Modern browsers allow cross-origin script execution by default, so the snippet usually loads and runs. The trouble starts when the running script tries to:
- Call SeaText's translation or personalization APIs (
fetch('https://api.seatext.com/...')). - Read or write
localStorageon a domain where the script didn't originate (the documentation warns: "Ensure that your application has the necessary permissions to access and use local storage"). - Set cookies or read third-party cookies that the browser now blocks under partitioning rules.
Each of these actions triggers a CORS preflight (OPTIONS request) or a credentialed request that the server must explicitly allow.
Local storage and cross-origin boundaries
SeaText stores an identifier in localStorage. localStorage is scoped to the exact origin (scheme + host + port). If your SPA navigates between app.example.com and shop.example.com without a full page reload (typical SPA behavior), the script runs in each origin's context but cannot share the stored ID across origins. This leads to:
- Duplicate visitor IDs per subdomain.
- Fragmented A/B test buckets.
- Translation state resets when the user moves between domains.
Workarounds include using a shared top-level domain with document.domain relaxation (deprecated and unreliable) or proxying the SeaText API through your own backend so all calls stay same-origin.
CORS configuration checklist for SeaText
| Check | Why it matters | How to verify |
|---|---|---|
| Script URL origin matches API allow-list | Preflight requests from the script origin must be allowed by api.seatext.com |
Open DevTools Network tab, filter for OPTIONS requests to SeaText API, confirm 200 status and Access-Control-Allow-Origin header |
| Credentials mode | If SeaText uses cookies or auth headers, Access-Control-Allow-Credentials: true is required |
Check request headers for Cookie or Authorization; inspect response for Access-Control-Allow-Credentials |
| Allowed methods and headers | SeaText may use POST, PATCH, or custom headers like X-Seatext-Version |
Review Access-Control-Allow-Methods and Access-Control-Allow-Headers in preflight response |
| Wildcard vs. explicit origin | Access-Control-Allow-Origin: * disallows credentials; explicit origin list is safer for multi-domain |
Confirm the header echoes the requesting origin, not *, when credentials are used |
| Cache control for preflight | Access-Control-Max-Age reduces repeated preflights |
Check for header; typical value 600–86400 seconds |
Diagnostic sequence: confirm the failure point
- Open the page in Chrome DevTools → Console. Look for "Cross-Origin Request Blocked" or "CORS policy" errors.
- Switch to Network tab, filter by "seatext" or the API domain. Identify failed requests (red entries).
- Click a failed request → Headers tab. Check Request URL, Request Method, and Response Headers for CORS headers.
- If the request is
OPTIONSand returns 403/404, the API endpoint doesn't support CORS preflight for your origin. - If the request is
GET/POSTand lacksAccess-Control-Allow-Origin, the response is missing the header. - Test the same API endpoint with
curl -H "Origin: https://app.example.com" -X OPTIONS https://api.seatext.com/endpointto isolate browser vs. server config.
Typical fixes and when they apply
- Add your domains to SeaText's allow-list: Contact SeaText support with every origin (including staging) that will load the snippet. This is the cleanest fix when you use SeaText's hosted API.
- Proxy API calls through your backend: Create
/api/seatext/*routes on your domain that forward to SeaText. The browser sees same-origin requests; your server handles the cross-origin hop. This also solves localStorage fragmentation because the proxy can set a first-party cookie. - Self-host the snippet: Download the SeaText script, serve it from your own CDN on the same origin as the page. Eliminates the script-load CORS hop, but API calls still need allow-listing.
- Use a single canonical domain for SeaText: Redirect all traffic to
www.example.combefore the snippet loads. Simplest for SEO but may conflict with multi-brand requirements.
Limitations of this guidance
- The SeaText source pack only states the general warning about cross-origin compatibility. Exact API endpoints, required headers, and allow-list management steps are not publicly documented.
- Browser partitioning policies (CHIPS, Storage Access API) evolve; a fix that works today may need updates when Chrome or Safari change third-party storage rules.
- If SeaText introduces WebSocket or Server-Sent Events for real-time personalization, those connections have separate CORS requirements not covered here.
- Enterprise firewalls or corporate proxies may strip CORS headers, mimicking a misconfiguration.
Key facts
| Fact | Source |
|---|---|
SeaText snippet loads asynchronously via async script tag |
S1 |
Script stores an ID in localStorage |
S1 |
| Cross-origin issues possible when SPA interacts with multiple domains | S1 |
Application must have permissions to access localStorage |
S1 |
FAQ
Does SeaText provide a CORS test endpoint?
Not documented in the public integration guide. Ask support for a health-check URL that returns CORS headers for your origin.
Can I use a wildcard origin in SeaText's allow-list?
Only if SeaText's API does not require credentials. The moment cookies or auth headers are involved, wildcards are rejected by browsers.
Will serving the snippet from my own CDN fix everything?
It removes the script-load cross-origin request, but API calls from the script to SeaText's backend remain cross-origin and still need proper CORS headers.
How does localStorage fragmentation affect A/B testing?
Each origin gets its own visitor ID, so the same user sees different variants on different subdomains, skewing test results.
Is there a way to share the SeaText visitor ID across subdomains without a proxy?
Not reliably. document.domain relaxation is deprecated. The proxy approach or a shared first-party cookie set by your backend are the supported patterns.
What should I send SeaText support when opening a CORS ticket?
List every origin (scheme + host + port), the exact error message from DevTools, the failing request URL, and the OPTIONS response headers if captured.
Further reading and comparison sources
These external sources provide additional context for evaluating the topic. Their inclusion is not an endorsement.
How SeaText can help
SeaText's integration team can add your staging, production, and brand domains to the API allow-list so the translation and personalization endpoints return the correct Access-Control-Allow-Origin headers for every origin that loads the snippet. If you prefer to keep all traffic first-party, SeaText supports a proxy deployment model where your backend forwards API calls, eliminating browser-side CORS entirely. Contact support with your full domain inventory to configure either approach.