GuidesSQUARESPACE
Squarespace CORS errors in custom code
Code blocks and code injection run inside your Squarespace page, so fetch() carries your domain as the origin and only works against APIs that send Access-Control-Allow-Origin. Squarespace runs no server-side code, and its Commerce API refuses browser calls outright: the preflight answers 401 with no CORS header. For public GET requests, prefix the URL with https://proxy.cors.dev/ (no signup, about 600 requests a minute per IP); POST and Authorization need cors.dev Pro at $5 a month for 500,000 requests, with a 7-day trial of 1,000 requests and no card.
Where your code runs on Squarespace
Squarespace runs custom JavaScript in two places: code injection (site-wide header and footer fields, plus per-page fields) and code blocks on a page, with scripts wrapped in <script> tags. Code injection is available on the Core, Plus and Advanced plans and some legacy billing plans, and checkout pages don't support it (Squarespace support, "Customize parts of your site with code injection", updated 16 September 2026).
A code block needs the Core, Plus or Advanced plan to run JavaScript or an iframe. It holds at most 400 KB, about 300,000 characters, and its Mode menu must be set to HTML: a block in CSS or JavaScript mode displays the code as text (Squarespace support, "Code blocks", updated 9 October 2026).
Code blocks render directly in the page, not inside an iframe: on two live Squarespace 7.1 sites checked on 28 October 2026, code block contents sat in the page with zero iframes. So fetch() from a code block or code injection carries the page's own origin: your custom domain, such as https://www.yourdomain.com, or the built-in https://yoursiteid.squarespace.com, which Squarespace says always shows while you are logged in.
Squarespace's support answer on server code: "No. Squarespace doesn't support server-side code, including PHP, Ruby, Ruby on Rails, and SQL." Every request leaves from the visitor's browser, and CORS decides whether your code can read the answer.
What works without a proxy
Adding ?format=json to a Squarespace collection URL returns that page's data as JSON (Squarespace developer docs, URL queries). On your own site that is a same-origin request and needs no proxy. Squarespace's developer docs note that ?format=json-pretty is not static and should not be used as an alternative to its APIs.
Any other request works only when the API sends Access-Control-Allow-Origin for your domain. On 28 October 2026 we called these endpoints with a foreign Origin, directly and through https://proxy.cors.dev/. The blog JSON of https://hester-demo.squarespace.com (48,753 bytes) answered 200 with no CORS header, so a page on another domain cannot read it.
| Endpoint | CORS header for other sites | From your Squarespace page | Through proxy.cors.dev, free |
|---|---|---|---|
| Your own /blog?format=json | None, same origin | Works | Not needed |
| Another site's /blog?format=json | None | Blocked | 200, echoes your origin |
| Steam player count API | None | Blocked | 200 |
| GitHub REST API | * | Works | Not needed |
| Commerce API inventory | None, preflight 401 | Blocked | Authorization refused with 400 |
Check an endpoint before writing code: if the first command prints nothing, the browser will block the response.
# No output: another site's JSON view sends no CORS header, so the browser blocks it
curl -sI -H 'Origin: https://www.example.com' 'https://hester-demo.squarespace.com/blog?format=json' \
| grep -i access-control-allow-origin
# The same URL through the keyless proxy: the header echoes your origin
curl -sI -H 'Origin: https://www.example.com' \
'https://proxy.cors.dev/https://hester-demo.squarespace.com/blog?format=json' \
| grep -i access-control-allow-originLoad another site's JSON in a code block
Put https://proxy.cors.dev/ in front of the full target URL; there is no signup and no key. The blog JSON's items array carries title, fullUrl (a path relative to the site) and publishOn (milliseconds) for each post.
- Add a code block
Place a Code block on the page and keep its Mode menu on HTML.
- Paste the snippet
It loads the other blog's
?format=jsonthrough the proxy and renders the 3 latest posts as links with dates. - Test while logged out
Open the live domain in a logged-out window, because "Disable Scripts in Preview" and safe mode (
/safeafter/config) turn custom code off.
<ul id="latest-posts"><li>Loading posts...</li></ul>
<script>
(async () => {
const list = document.getElementById('latest-posts');
const source = 'https://hester-demo.squarespace.com/blog?format=json';
try {
const response = await fetch('https://proxy.cors.dev/' + source);
if (!response.ok) {
throw new Error(response.headers.get('X-Cors-Error') || 'HTTP ' + response.status);
}
const { items = [] } = await response.json();
list.replaceChildren(
...items.slice(0, 3).map((post) => {
const li = document.createElement('li');
const link = document.createElement('a');
link.href = new URL(post.fullUrl, source).href;
link.textContent = post.title;
li.append(link, ' ', new Date(post.publishOn).toLocaleDateString());
return li;
}),
);
} catch (error) {
list.textContent = 'Posts could not load: ' + error.message;
}
})();
</script>Commerce API keys need a server
Squarespace Commerce APIs live at https://api.squarespace.com/{version}/{path}, take an API key or OAuth token as Authorization: Bearer, and allow 300 requests per minute. The Squarespace API keys article lists the Orders, Inventory and Transactions APIs on the Core, Plus, Advanced and Commerce Advanced plans.
Squarespace support is explicit: "You'll receive a CORS (Cross Origin Resource Sharing) error if you use JavaScript to make requests from a browser. All requests must originate from a server side application. We don't support CORS requests." On 28 October 2026 an OPTIONS preflight to https://api.squarespace.com/1.0/commerce/inventory answered 401 with no Access-Control-Allow-Origin, and the keyless proxy refused the Authorization header with 400 header_not_allowed.
cors.dev Pro would forward the header, but the key would then sit in page code where any visitor can copy it, with access to store data such as orders and inventory. Commerce API calls belong on a server you run elsewhere.
When you need cors.dev Pro
The free tier sends GET and HEAD only; POST answers 405 method_not_allowed. cors.dev Pro adds POST, PUT, PATCH and DELETE with bodies up to 1 MiB, plus the Authorization, Content-Type and custom headers. It can also cache a GET for up to 300 seconds through an X-Cors-Cache request header when the upstream response allows it; cache hits still count as requests.
- Start the trial
Sign up with Google. The 7-day trial includes 1,000 requests and needs no card.
- Register your origins
Add your custom domain exactly as the browser shows it, and
https://yoursiteid.squarespace.comif you test while logged in. A request from an origin that is not on the Connection answers403origin_not_allowed. - Enable hosts and send the key
Enable each API host you call (up to 20) and add the
X-Cors-Keyheader tofetch(). The key is publishable: it identifies the Connection, and every visitor can see it.
Limits on each tier
The free tier allows about 600 requests per minute per IP and answers 429 with a Retry-After header that JavaScript can read; there is no monthly quota. Authorization, and header names containing token, apikey, api-key, api_key, secret or password or ending in -key, answer 400 header_not_allowed; other custom headers, including names containing csrf or xsrf such as X-CSRF-Token, are dropped and listed in X-Cors-Dropped-Headers. When the proxy itself refuses a request, the X-Cors-Error response header names the reason.
| Limit | Free, no key | Pro, $5 a month |
|---|---|---|
| Price | Free, no signup | $5 a month, 7-day trial with 1,000 requests |
| Methods | GET, HEAD | GET, HEAD, POST, PUT, PATCH, DELETE |
| Monthly requests | No quota | 500,000 |
| Throughput | About 600 a minute per IP | 3,000 a minute per account, 100 in flight |
| Request headers | Accept, Accept-Language, If-None-Match, If-Modified-Since, Range | Adds Authorization, Content-Type, custom headers |
| Page origins | Any | Up to 10 exact origins per Connection |
| Response size and deadline | 6 MiB, 30 seconds | Same as free |
| Caching | None | GET up to 300 seconds, when the upstream allows it |
Good questions.
Why does my code block do nothing while I edit the site?
Check that the block's Mode menu is set to HTML and the code sits inside <script> tags; other modes print the code as text. "Disable Scripts in Preview" and safe mode also switch custom scripts off in the editor, so test fetch() calls on the live site in a logged-out window.
Can I call the Squarespace Commerce API from a code block?
No. Squarespace does not support CORS on its Commerce APIs and requires every request to come from a server-side application; the preflight answers 401 with no CORS header. A Commerce API key in page code would expose store data such as orders and inventory to every visitor, so call the API from a server you run elsewhere.
Does ?format=json work from another website?
Only through a proxy. Squarespace sends no Access-Control-Allow-Origin header on the JSON view, so a browser on another domain blocks the response, while the same request from your own Squarespace site is same-origin and works. Prefixing the URL with https://proxy.cors.dev/ returns the JSON with the header set to your page's origin.
Which Squarespace plan do I need to run JavaScript?
Code blocks with JavaScript need the Core, Plus or Advanced plan, and code injection works on those plans plus some legacy billing plans. Checkout pages do not support code injection on any plan. Commerce API keys for a separate server need the Core, Plus, Advanced or Commerce Advanced plan, according to the Squarespace API keys article.
Does cors.dev keep my API key secret on Squarespace?
No. cors.dev never hides an API key: anything in browser JavaScript, in a query string or in a header that cors.dev Pro forwards, is visible to anyone who opens the page. The X-Cors-Key that cors.dev Pro uses is publishable and only identifies your Connection, so secret keys belong on a server.