GuidesFRAMER

Framer Fetch and CORS errors

Framer Fetch and code components both call APIs from the visitor's browser and from the editor, with no Framer server in between, so an API must send Access-Control-Allow-Origin for your site and the canvas. Of 4 public APIs tested from a framer.website page, 2 sent the header and 2 did not. Paste https://proxy.cors.dev/ in front of the URL in the Fetch field to fix the rest for free (about 600 requests a minute per IP); code components can also use cors.dev Pro, $5 a month for 500,000 requests, for POST and auth headers.

Where Framer makes the request

Framer Fetch pulls API data into a site without code. Framer's developer docs say Fetch "makes a GET request to the endpoint URL", and its help center says cached responses "are stored in the visitor's browser". The request leaves from the visitor's browser on the published site, and from the editor while you design, which is why Framer tells you to handle CORS yourself.

Framer's docs: "Like with all static websites, any API endpoints that are used with Fetch need to be configured to be safely accessed from within the Framer editor, as well as from the published site it will be used on. This means you'll likely need to configure the CORS of your backend." When the API is not yours, you cannot add that header, and the browser blocks the response.

Fetch has two more limits that shape the fix. It reads String, Boolean and Number values plus Image URLs and Colors, and the docs say: "Arrays cannot be iterated over, but the values within them can be manually accessed from within the Fetch UI." The response must also be a JSON object; a bare value is not picked up in the Path selector. The docs describe no way to add request headers to a Fetch call.

Framer features that call APIs, checked October 2026
FeatureWhere it runsCan send custom headerscors.dev tier
FetchVisitor's browser and the editorNoFree only
Code componentVisitor's browser, canvas and previewYesFree or Pro
OverrideVisitor's browser and preview, not the canvasYesFree or Pro
Custom CodeVisitor's browser, not the canvasYesFree or Pro

Fix Framer Fetch with the keyless proxy

Fetch cannot send the X-Cors-Key header that cors.dev Pro needs, so Fetch uses the free tier: no signup, no key, GET and HEAD only, about 600 requests per minute per IP.

  1. Prefix the URL

    In the Fetch URL field, put https://proxy.cors.dev/ in front of the full API URL, for example https://proxy.cors.dev/https://api.steampowered.com/ISteamUserStats/GetNumberOfCurrentPlayers/v1/?appid=730.

  2. Pick the value

    The Steam endpoint returns {"response":{"player_count":...,"result":1}}, so choose response, then player_count, in the Path selector.

  3. Check the editor and the live site

    The value should load in both, because the proxy answers every page origin.

On 28 October 2026 we called four public APIs with Origin: https://portfolite.framer.website, a live Framer site. The Steam player count API sent no Access-Control-Allow-Origin; through the proxy it answered 200 (47 bytes) with the header echoing https://portfolite.framer.website. Yahoo Finance's chart API (https://query1.finance.yahoo.com/v8/finance/chart/MSFT) behaved the same way.

Public APIs called from a framer.website page, checked October 2026
APIAccess-Control-Allow-OriginIn Framer Fetch
Steam player countNoneWorks through the proxy, 200
Yahoo Finance chartNoneWorks through the proxy, 200
GitHub REST API*Works directly
npm downloads API*Works directly

The free tier forwards Accept, Accept-Language, If-None-Match, If-Modified-Since and Range, and refuses Authorization with 400 header_not_allowed. A key placed in the query string is forwarded as it is, and anyone who opens the page can read it. Responses can be up to 6 MiB, within a 30 second upstream deadline.

Code components and overrides

Code components are React components, and overrides are functions that change a layer. Code components run on the canvas, in preview and on the published site; overrides are applied on the canvas but only active in preview and on the published site. Both share the browser runtime and DOM with the rest of the page. Custom Code (Project Settings, head and body) also runs in the visitor's browser, but only on the published site, not in the canvas or preview.

Framer pre-renders pages on the server, so code that touches window or document, and requests meant for the visitor's browser, belong inside useEffect. Unlike Fetch, a code component can read arrays, handle errors and send headers.

PlayerCount.tsx: a code component that fetches through the proxy
import { useEffect, useState } from 'react';

const TARGET =
  'https://api.steampowered.com/ISteamUserStats/GetNumberOfCurrentPlayers/v1/?appid=730';

export default function PlayerCount() {
  const [text, setText] = useState('Loading...');

  useEffect(() => {
    const controller = new AbortController();

    fetch('https://proxy.cors.dev/' + TARGET, { signal: controller.signal })
      .then(async (response) => {
        if (!response.ok) {
          throw new Error(response.headers.get('X-Cors-Error') ?? `HTTP ${response.status}`);
        }
        const { response: stats } = await response.json();
        setText(`${stats.player_count.toLocaleString()} playing now`);
      })
      .catch((error) => {
        if (error.name !== 'AbortError') setText(`Unavailable: ${error.message}`);
      });

    return () => controller.abort();
  }, []);

  return <span>{text}</span>;
}

When the proxy itself refuses a request, the X-Cors-Error response header names the reason, and the component above puts it in the error message. X-Cors-Source: upstream marks status codes that came from the API.

Origins your Framer site runs on

Every published Framer site gets a framer.app address automatically. A free Framer subdomain ends in framer.website, framer.photos, framer.media or framer.wiki. Connecting your own domain needs a paid Framer plan (Basic or higher). Staging, which Framer's Pro plan and higher include once a custom domain is connected, serves the staged version on the site's framer.app base domain.

Framer's network allowlist lists framercanvas.com among the domains the editor needs. Framer does not document the exact origin that canvas requests send, so read it from the Origin request header in your browser's network panel.

When you need cors.dev Pro

A code component, override or Custom Code that must send POST, PUT, PATCH or DELETE, a request body up to 1 MiB, or Authorization and custom headers needs cors.dev Pro. It costs $5 a month for 500,000 requests, with a 7-day trial of 1,000 requests and no card. It can cache a GET for up to 300 seconds when the upstream response allows it, and cache hits still count as requests. Throughput is 3,000 requests a minute per account and 100 in flight.

You sign up with Google, create a Connection with up to 10 exact page origins and up to 20 target hosts, and send its key in an X-Cors-Key header. The key is publishable: every visitor can see it. Register every exact origin the component runs on:

  • Published site: Your custom domain or your framer.website address.
  • framer.app: Your site's framer.app address, if visitors or staging use it.
  • Canvas: The origin from the network panel, if the component should load in the editor.

A request from an origin that is not on the Connection answers 403 origin_not_allowed, and Origin: null never matches.

Good questions.

Can Framer Fetch send an API key or Authorization header?

No. Framer's docs describe no way to add request headers to a Fetch call. A key in the query string is forwarded by the free proxy, but anyone who opens the page can read it. Framer's docs say such a key is "impossible to use securely on the front-end" and put a small worker, such as a Cloudflare Worker, between Fetch and the API.

Why does my Fetch value load on the published site but not in the editor?

The editor is not your published domain, and Framer's docs say Fetch endpoints must allow both the editor and the published site. An API that allows only your domain fails in the editor. The keyless proxy answers every origin, so the same prefixed URL loads in both.

Can Framer Fetch show a list from a JSON array?

No. Fetch reads single String, Boolean and Number values plus Image URLs and Colors from a JSON object, and Framer's docs say arrays cannot be iterated over. Framer's help points list data to CMS Collections; for a live list, write a code component that fetches the array and maps it to elements.

Does Framer have a backend for API calls?

Not one that runs your code. Fetch, code components, overrides and Custom Code all send requests from the visitor's browser. When an API needs a key or reshaped data, Framer's developer docs point to a function-as-a-service platform such as Cloudflare Workers or Val Town.

Where should fetch code go in a Framer code component?

Inside a useEffect hook. Framer pre-renders pages on the server, where window and document do not exist, so browser code has to start after the component mounts. The component then fetches in the browser on the canvas, in preview and on the published site.