I have a small LLM client that runs client-side in the browser for personal use: https://github.com/david-crespo/llm-web (yes, I understand the security implications, see the README).
I was trying to convert it to use the Interactions API in @google/genai, but every call fails with No 'Access-Control-Allow-Origin' header is present on the requested resource. The following was largely written by LLM but edited by me.
🤖 Summary
The next-gen client (Interactions/Agents/Webhooks) adds an Api-Revision header to every request:
|
function applyApiRevision( |
|
hookCtx: BeforeRequestContext, |
|
headers: Headers, |
|
): void { |
|
if (headers.get("api-revision") === null) { |
|
headers.set( |
|
"Api-Revision", |
|
hookCtx.options.api_revision ?? GOOGLE_GENAI_API_REVISION, |
|
); |
|
} |
|
} |
In the browser that triggers a CORS preflight, and generativelanguage.googleapis.com doesn't list api-revision in its Access-Control-Allow-Headers. The preflight comes back 403 with no Access-Control-Allow-Origin, so the request never goes out.
Verified with direct curl preflights (no SDK, no browser) — the allowlist accepts content-type / x-goog-api-key / x-goog-api-client / authorization but rejects api-revision:
# allowed headers → 200, with ACAO
$ curl -si -X OPTIONS \
-H 'Origin: http://localhost:5173' \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: content-type,x-goog-api-key' \
https://generativelanguage.googleapis.com/v1beta/interactions | grep -i '^HTTP/\|access-control-allow'
HTTP/2 200
access-control-allow-origin: http://localhost:5173
access-control-allow-headers: content-type,x-goog-api-key
# add api-revision → 403, no ACAO
$ curl -si -X OPTIONS \
-H 'Origin: http://localhost:5173' \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: content-type,x-goog-api-key,api-revision' \
https://generativelanguage.googleapis.com/v1beta/interactions | grep -i '^HTTP/\|access-control-allow'
HTTP/2 403
Scope is browser-only. In Node there's no preflight, so the Interactions API works server-side, and the legacy models.generateContent path works in the browser because it never sets Api-Revision.
The SDK already drops a browser-incompatible header in this same spot — it skips user-agent under isBrowserLike, with a comment naming the CORS constraint:
|
// Only set user agent header in non-browser-like environments since CORS |
|
// policy disallows setting it in browsers e.g. Chrome throws an error. |
|
if (!isBrowserLike) { |
|
headers.set( |
|
conf.uaHeader ?? "user-agent", |
|
conf.userAgent ?? SDK_METADATA.userAgent, |
|
); |
|
} |
But I'm not sure whether the same guard can just be copied for Api-Revision. The real fix might be on the server: add api-revision to Access-Control-Allow-Headers for generativelanguage.googleapis.com. Happy to be corrected if there's a client-side workaround I'm missing.
I have a small LLM client that runs client-side in the browser for personal use: https://github.com/david-crespo/llm-web (yes, I understand the security implications, see the README).
I was trying to convert it to use the Interactions API in
@google/genai, but every call fails withNo 'Access-Control-Allow-Origin' header is present on the requested resource. The following was largely written by LLM but edited by me.🤖 Summary
The next-gen client (Interactions/Agents/Webhooks) adds an
Api-Revisionheader to every request:js-genai/src/gaos/hooks/google-genai-auth.ts
Lines 195 to 205 in eeee711
In the browser that triggers a CORS preflight, and
generativelanguage.googleapis.comdoesn't listapi-revisionin itsAccess-Control-Allow-Headers. The preflight comes back403with noAccess-Control-Allow-Origin, so the request never goes out.Verified with direct
curlpreflights (no SDK, no browser) — the allowlist acceptscontent-type/x-goog-api-key/x-goog-api-client/authorizationbut rejectsapi-revision:Scope is browser-only. In Node there's no preflight, so the Interactions API works server-side, and the legacy
models.generateContentpath works in the browser because it never setsApi-Revision.The SDK already drops a browser-incompatible header in this same spot — it skips
user-agentunderisBrowserLike, with a comment naming the CORS constraint:js-genai/src/gaos/lib/sdks.ts
Lines 239 to 246 in d791388
But I'm not sure whether the same guard can just be copied for
Api-Revision. The real fix might be on the server: addapi-revisiontoAccess-Control-Allow-Headersforgenerativelanguage.googleapis.com. Happy to be corrected if there's a client-side workaround I'm missing.