Anatomy of a Blender add-on that speaks OAuth and REST — without freezing the UI
Blender's bpy API runs on the main thread. A blocking HTTP call for a 500 MB .blend upload leaves Blender 'not responding' for 90 seconds — most users kill the process. Fix: background worker with a timer callback into the main thread, plus OAuth device flow (no browser callback needed).
Our zer0one-blender-addon (on GitHub) adds a `File → Send to ZER0ONE Lab` menu to Blender. Click and the current scene ships to the Cinema Render backend. First version took ~2 weeks — the first days every iteration came back with "Blender not responding". Three problems to solve, typical for any Blender add-on that talks to external APIs.
Problem 1: auth flow without a browser callback
Standard OAuth: user clicks login, browser opens, provider redirects back to `localhost:8080/callback`, app reads the code. Works for web apps. In Blender it doesn't — you can't reliably start an HTTP server in the Blender process (breaks on Windows firewalls, macOS sandbox, various Linux distros).
Clean solution: OAuth 2.0 Device Flow (RFC 8628). Add-on posts to `/oauth/device/code`, server returns `device_code` + `user_code` + `verification_uri`. Add-on shows the user: "open `https://zer0onelab.com/device\` and enter code `ABCD-1234`". User does it from any device — phone, another laptop. Add-on polls `/oauth/token` every 5 seconds until server returns the access token.
No browser callback, no HTTP server in Blender. Works on studio render machines that don't have a browser.
Implementation note: Blender's embedded Python doesn't ship `requests`, but `urllib.request` covers all OAuth calls. Saves a dependency-bundle question.
Problem 2: async without asyncio (bpy doesn't play nice with asyncio)
Blender runs Python in the main thread. `bpy.ops` and scene modifications must be on the main thread. Background-thread calls to bpy either crash or produce undefined behaviour.
A 500 MB upload at 100 Mbps takes ~45 seconds. On the main thread, Blender is hard-frozen. Users kill the process.
Pattern: an `UploadThread` in the background does the blocking upload with progress callback. Blender-side we register `bpy.app.timers.register(status_poll)` — Blender calls the callback in the main thread every 200 ms. Background thread does the work, timer syncs status back. No asyncio needed, no bpy race conditions.
Problem 3: chunked upload and retry
500 MB uploads over flaky WiFi drop after 3 minutes with connection reset. User has to restart. After the third time the add-on gets uninstalled.
Fix: chunked upload with resume token. 8 MB blocks per HTTP PUT. Server remembers the last successful block index. On reconnect the add-on asks for the last received block and continues from there. We implement it over Cloudflare R2's S3-compatible multipart upload — ~120 lines of client-side code, zero server-side special code.
What else we learned
- Blender 4.2+ has a new extensions system. Old zip format still works, but new add-ons should ship the extensions manifest so Blender can distribute via the Extensions Marketplace. That's the SEO channel for Blender add-ons.
- Version compatibility is a committee. A 4.2 add-on usually runs in 4.3, often not in 5.0. Our `bl_info` block lists exact supported versions.
- Users love a changelog in the add-on itself. We show a short "what's new" popup on first launch after an update. Reduces support tickets noticeably.
Meta-lesson
A good Blender add-on differs from a bad one in three details: auth without a browser (device flow), uploads without freeze (background thread + timer callback), errors with recovery (chunked + resume). All three are standard distributed-systems patterns from web dev but rarely done cleanly in the Blender ecosystem. Do them properly and you stand out from 80 % of cloud integrations in the Blender world.
Full add-on is open source on GitHub, MIT-licensed. It's one of the client layers of ZER0ONE Lab Cinema Render.
Stesso fuoco anche da te?
Probabilmente abbiamo già visto qualcosa di simile. Parliamone.
Iniziamo a parlarne→