When you’re building a Figma plugin, you might notice that making API calls isn’t as straightforward as it is on a regular website. If you’ve run into CORS errors, you’re not alone. In this article, I’ll explain why this happens and show you a solution using a non-null origin iframe.
Figma plugin null origin CORS error
How API Calls Work in Figma Plugin
Figma plugins run inside an iframe. But here’s the catch: Figma uses a special sandboxed iframe that has a null origin. When you try to make an API call directly from the plugin, the request comes from this null origin, triggering the CORS policy. Basically, unless the target API explicitly allows requests from any origin (using something like Access-Control-Allow-Origin: *
), the API call won’t go through.
This is by design, and Figma’s documentation even suggests setting up the API to allow such calls. The problem is, if you don’t control the API or you don’t want to make it universally accessible, you need another approach.
Figma Plugin null origin error
Why the CORS Error Occurs
The root of the problem is that browsers enforce Cross-Origin Resource Sharing (CORS) rules. Since your Figma plugin is loaded from a null origin, most APIs will reject its requests unless they allow all origins. You end up with an error because the API sees a request with no specific origin instead of an expected, allowed one.
Bypassing CORS with a Non-Null Origin Iframe in Figma Plugin
There’s a neat solution. In Figma, you can load an additional iframe that comes from a real website, one with a proper origin. This is using the same idea behind their OAuth flow, where you load an authentication page and retrieve access token in the Figma Plugin environment.
Instead of performing Auth, we are loading a webpage that is making the API call, and then sending the data back to our Figma Plugin.
Bypassing CORS null origin error in Figma Plugin
How It Works
-
Load a Non-Null Origin Iframe
Use Figma’s
showUI
function to open an iframe from our html file. We will need to host this HTML file on a hosting platform. This file will make the API call and return the data back to the plugin.
// Show the UI with your hosted webpage
figma.showUI(
'<script>window.location.href="https://your-webpage-domain.com/index.html";</script>'
);
- Make the API Call from the webpage Since the webpage comes from a proper domain, the browser will send an origin header, and if the API allows that origin (or if you’re using Corsfix to bypass CORS), the API call succeeds. The webpage is just a static HTML file (index.html) you can host on Cloudflare Pages, GitHub Pages, or Netlify. Here's an example of what the HTML file might look like:
<!DOCTYPE html>
<html>
<head>
<title>Figma Plugin Data Fetcher</title>
</head>
<body>
<script>
fetch(`<TARGET_URL>`)
.then((response) => response.json())
.then((data) => {
// Send data back to the Figma plugin
parent.postMessage(
{ pluginMessage: { type: "fetch-result", data }, pluginId: "*" },
"*"
);
})
.catch((error) => {
parent.postMessage(
{
pluginMessage: { type: "fetch-error", error: error.message },
pluginId: "*",
},
"*"
);
});
</script>
</body>
</html>
-
Communicate the Result Back to the Plugin
Once the iframe receives the data, it uses
postMessage
to send the results back to your plugin. This bypasses the direct CORS issue because the call isn’t made from a null origin anymore. Then the plugin will listen for the message and handle the data accordingly.
// Show the UI with your hosted webpage
figma.showUI(
'<script>window.location.href="https://your-webpage-domain.com/index.html";</script>'
);
// Listen for messages from the UI
figma.ui.onmessage = async (msg) => {
if (msg.type === "fetch-result") {
// Handle the successful response
console.log("Data received:", msg.data);
// Do something with the data in your plugin
// For example, create text nodes with the data:
await figma.loadFontAsync({ family: "Inter", style: "Regular" });
const textNode = figma.createText();
textNode.characters = JSON.stringify(msg.data, null, 2);
textNode.x = 100;
textNode.y = 100;
figma.currentPage.appendChild(textNode);
// Optional: close the plugin when done
figma.closePlugin();
} else if (msg.type === "fetch-error") {
// Handle errors
console.error("Error fetching data:", msg.error);
figma.notify(`Error: ${msg.error}`);
}
};
Make sure to add your domain to the allowedDomains
in your manifest.json file.
{
"name": "Your Plugin Name",
"id": "your-plugin-id",
"api": "1.0.0",
"main": "code.js",
"editorType": ["figma"],
"networkAccess": {
"allowedDomains": ["https://your-webpage-domain.com"]
}
}
Remember, CORS policies still apply, even in your non-null origin iframe. If you control the API, you can set the allowed origin to match the domain hosting your static HTML file. But if you don’t control the API, you can use a CORS proxy like Corsfix. Corsfix will fetch the data on your behalf and add the correct CORS headers to the response.
Conclusion
Calling an API from a Figma plugin is not as straightforward as making a request from a typical website. The iframe running with a null origin is the primary reason for triggering CORS errors. By incorporating a non-null origin iframe to handle network requests and using postMessage
to send data back, you can bypass this problem.
If you’re working with an API you don’t control, using Corsfix can help you get around the CORS errors. It's free to get started, and you only need to upgrade when going to production.
Check out our Corsfix Figma plugin integration docs and the complete code example.
Top comments (1)
have you run into null origin error when working with figma plugin?