Ollama, LM Studio and any OpenAI-compatible endpoint
Point the SideBoo Chrome extension at Ollama, LM Studio, vLLM or a company gateway — including the OLLAMA_ORIGINS setting that clears the 403.
9 min read · Last updated 2026-08-27
Fixing the Ollama 403 / OLLAMA_ORIGINS error
Ollama returns 403 to a Chrome extension because it checks the Origin header and, out of the box, only trusts local web origins. A browser extension does not have one: its requests carry Origin: chrome-extension://<extension id>, which is not on the list. Set the OLLAMA_ORIGINS environment variable to include extension origins and restart Ollama, and the 403 goes away.
The value SideBoo needs is chrome-extension://*. How you set it depends on how Ollama is started, and the environment has to be in place before Ollama starts — this is why so many people set the variable, see 403 again, and conclude it did not work.
# macOS — the menu-bar app reads its environment from launchd
launchctl setenv OLLAMA_ORIGINS "chrome-extension://*"
# then quit Ollama from the menu bar and start it again
# Linux — Ollama runs as a systemd unit
sudo systemctl edit ollama.service
# [Service]
# Environment="OLLAMA_ORIGINS=chrome-extension://*"
sudo systemctl daemon-reload
sudo systemctl restart ollama
# Linux / macOS — a one-off foreground run instead
OLLAMA_ORIGINS="chrome-extension://*" ollama serve
On Windows, Ollama picks the value up from your account's environment variables, not from the terminal you happen to be in. Quit Ollama from the system tray first, then search the Start menu for "Edit environment variables for your account", add a user variable named OLLAMA_ORIGINS with the value chrome-extension://*, and start Ollama again. A variable set with set or $env: in a shell only reaches processes that shell launches, so it does nothing for the tray app.
LM Studio has the same guard under a different name: its local server refuses cross-origin requests until you turn CORS on. The switch sits with the rest of the server controls — in recent builds, the Developer tab, beside the port field and the start/stop button. Turn it on, restart the server, and re-run Test service.
When you need a custom endpoint
Any service implementing OpenAI's /v1/chat/completions can be connected. In settings, open "AI assistant", click "Add provider", and choose "Custom OpenAI-compatible service" — the dashed card at the bottom of the dialog. A custom service asks you for three things: a Name, an API endpoint, and an API Key.
The usual cases:
- Local models: Ollama, LM Studio, llama.cpp in server mode.
- Self-hosted inference: vLLM, SGLang, TGI.
- Aggregators: OpenRouter and similar services that put many models behind one address.
- Company gateways: an internal proxy that handles auth, auditing and rate limits.
Local servers usually check no credentials, so the API Key field can stay empty: SideBoo stops asking for one once it sees the endpoint points at localhost or 127.0.0.1. Those two hostnames are also the only ones allowed over plain http — a remote service must be https, and an IPv6 literal such as http://[::1]:11434/v1 is rejected outright.
Getting the endpoint URL right
End the URL at /v1 — do not append /chat/completions, SideBoo adds the rest of the path itself. An extra path segment gives you a 404 rather than a useful error.
# Local Ollama
http://localhost:11434/v1
# Local LM Studio
http://localhost:1234/v1
# OpenRouter
https://openrouter.ai/api/v1
# Self-hosted vLLM
https://llm.internal.example.com/v1
Verify with curl first
Before putting anything into SideBoo, confirm the endpoint and key work on their own. This cleanly separates a server problem from an extension problem:
curl https://your-endpoint.example.com/v1/chat/completions \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "your-model-name",
"messages": [{ "role": "user", "content": "ping" }],
"max_tokens": 8
}'
You want a 200 with choices[0].message.content in the body. If this fails, the problem is your provider or your network, and no extension setting will fix it.
Cross-origin requests and CORS
This is the classic self-hosting trap: curl is perfectly happy and the extension still fails. curl sends no Origin header, so it never trips the check that the browser does. A browser extension issues cross-origin requests from chrome-extension://<extension id>, and the server has to allow that origin explicitly.
Both the preflight (OPTIONS) and the real response need:
- Access-Control-Allow-Origin — echo the request Origin, or set it to *.
- Access-Control-Allow-Headers — at minimum authorization and content-type.
- Access-Control-Allow-Methods — including POST and OPTIONS.
location /v1/ {
if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin $http_origin always;
add_header Access-Control-Allow-Headers "authorization, content-type" always;
add_header Access-Control-Allow-Methods "POST, OPTIONS" always;
add_header Access-Control-Max-Age 86400 always;
return 204;
}
add_header Access-Control-Allow-Origin $http_origin always;
proxy_pass http://127.0.0.1:8000;
}
Extra notes for local models
A local model is cheap and private, and it is also the configuration most likely to disappoint. Three of its failure modes have nothing to do with networking — they come from the model itself being too small for what SideBoo asks of it:
- Ask AI needs the model to emit valid JSON reliably when it groups tabs. Very small models often return something unparseable; below 7B, expect summarising to work and grouping not to.
- Leave at least an 8K context window — sixty tab titles plus the prompt overruns 4K easily.
- A cold model loads on the first request, so the first Test service can time out where the second succeeds. Run it twice before you conclude anything.
Picking the model name
The model name must match the server's identifier exactly, including case, date suffix and vendor prefix. Aggregators almost always need the prefix:
| Service | Example model name |
|---|---|
| Ollama | llama3.1:8b |
| vLLM | Whatever you passed to --served-model-name |
| OpenRouter | anthropic/claude-sonnet-5 |
| Company gateway | Defined by the gateway; usually listed at its /v1/models |
When unsure, request /v1/models on your endpoint — every id in that list is a valid value. If the endpoint has no /v1/models at all, Test service reports "0 models found"; click "Add a model ID manually" and type the name yourself. Chat is unaffected.
Seeing the real error
The message in settings is a summary. To read exactly what the server returned, open the extension's background console:
- Open chrome://extensions Turn on Developer mode in the top right.
- Click the service worker link on the SideBoo card A DevTools window scoped to the extension background opens.
- Switch to Network and trigger the AI action again Find the request to your endpoint; its Response holds the full error body.
Troubleshooting table
Every row below is a real status code or message mapped to the one thing that actually causes it. Match the symptom, not the guess — the most common wasted afternoon here is regenerating an API key to fix a problem that was never about the key.
| Symptom | What to do |
|---|---|
| Test service returns 401 | The key picked up whitespace, got truncated on copy, or has been revoked. Generate a fresh one and paste again. |
| Test service returns 403 from a local Ollama | Origin check. Set OLLAMA_ORIGINS as described at the top of this page and restart Ollama. |
| Test service returns 429 | No balance, or you hit a rate limit. Check quota in the provider console, wait a minute and retry. |
| Test service returns 404 | The endpoint has /chat/completions appended, or is missing /v1. Re-enter it per the section above. |
| Connected but 0 models found | The service does not implement /models. Add the model ID by hand; chat still works. |
| Model not found | The name must match the server identifier exactly. Query /v1/models to see the real ids. |
| curl works but the extension fails | Almost certainly CORS or an origin check. Check the background console for the network error and configure the server as shown above. |
| Grouping results look odd | Thin tab titles leave the model guessing. Move to a stronger model, or close the blank tabs before asking. |
| Parse failure while grouping tabs | The model did not return valid JSON — common with small local models. Use a larger model or a hosted provider. |
| Ask AI says "No model configured" | No provider reached Ready. Go back to settings, run Test service, and tick at least one model. |
Frequently asked questions
Why does Ollama return 403 from a Chrome extension?
Because Ollama validates the Origin header and, by default, only accepts local web origins such as http://localhost. A Chrome extension sends Origin: chrome-extension://<extension id>, which is not on that list, so Ollama rejects the request before it reaches the model. The same request from curl succeeds, because curl sends no Origin at all. Adding extension origins to OLLAMA_ORIGINS and restarting Ollama is the whole fix.
What should OLLAMA_ORIGINS be set to?
chrome-extension://* is the value that lets any Chrome extension through, and it is what SideBoo needs. If you would rather allow one extension only, use its full id — chrome-extension://<extension id> — which you can read off its card on chrome://extensions. OLLAMA_ORIGINS also takes a comma-separated list, so you can keep an existing value and append to it rather than replacing it. Whichever form you pick, Ollama only reads the variable at startup, so restart it afterwards.