I was building a Figma plugin that pulls rows from a public Google Sheet. It looked easy: fetch the CSV, parse it, done. It did not work, and the reason is easy to miss.
The problem
A Figma plugin UI runs in an iframe with a null origin. The Figma docs say this means the plugin can only call APIs that return Access-Control-Allow-Origin: *.
I built a sandboxed iframe with a null origin and tested each way to read the sheet.
| Path | Result |
|---|---|
| docs.google.com gviz/tq?tqx=out:csv | blocked |
| docs.google.com export?format=csv | blocked |
| sheets.googleapis.com v4 | works, but needs an API key |
| gviz/tq?tqx=out:json;responseHandler:cb loaded with a script tag | works, no key, no server |
Why the export URL fails
The final response of the export URL does have the allow header. But the first answer is a 307 redirect, and that redirect has no allow header. The browser checks the first one and stops.
What worked
A script tag is not subject to CORS. So I ask Google for the JSON-with-callback format and load it as a script:
window.cb = (data) => { /* data.table.rows */ };
const s = document.createElement("script");
s.src = "https://docs.google.com/spreadsheets/d/<ID>/gviz/tq?tqx=out:json;responseHandler:cb&headers=0";
document.body.appendChild(s);
Add headers=0, otherwise Google guesses which row is the header and may eat your first data row.
Lesson
Before writing any code that reads someone else's API from a browser extension or plugin, check with curl whether the API sends Access-Control-Allow-Origin: *. If there is a redirect, look at the headers of the first response, not the last one.
The built-in browser pane of my tool could not run nested sandbox iframes, so I had to do this test in a real Chrome. Testing in the real environment saved me from shipping a plugin that fails on first load.
Have you hit a null-origin problem in another plugin platform, and how did you get around it?
I'm a full-stack developer, 13 years, based in Korea (UTC+9). I work in writing only, and use AI translation, so my English is simple. CV: https://cv.namubase.com
Top comments (0)