TL;DR. A CivitAI browser modal in the ComfyUI sidebar, backed by a server-side proxy (browsers can’t call the CivitAI API directly) with PKCE OAuth whose tokens never reach the browser. Full-screen lightbox with generation details, like/unlike that mirrors into a collection on your account,@creatorsearch qualifiers, one-click “load workflow onto canvas” (including CivitAI’s.zip-wrapped workflow files), share-with-agent to recreate a reference image, andopen_civitaiso the agent can answer a search with a UI instead of a text dump. The same browser ships in the mobile app.
Why there’s a Python proxy in the middle
The first thing you learn building this: a browser cannot talk to the CivitAI API. CORS blocks the cross-origin calls, and CivitAI’s bot-gate wants request headers a web page isn’t allowed to set. So every network call the browser makes goes to a same-origin route on the ComfyUI Python side (/comfyui_mcp_panel/civitai/*), and that process makes the real calls. Media
comes back the same way — thumbs, full images, and video resolve to same-origin
/media URLs that work directly as <img>/<video> sources and are fetchable
as Blobs when the agent needs the actual pixels.
Sign-in rides the same route. The proxy runs the full PKCE OAuth flow
against CivitAI’s auth service — a public native client, no secret — and the
resulting tokens are stored server-side only, in a JSON file under the
ComfyUI user directory. The browser sees “signed in: yes/no” and nothing else;
access and refresh tokens never cross into page JavaScript. (One migration
note: 0.9.0 widened the OAuth scope to include SocialWrite and CollectionsRead,
because reactions and collections 403’d under the old scope — an existing
sign-in re-consents once.)
The lightbox is the product
Click any image or video and it opens a full-screen lightbox: media on the left, everything you actually came for on the right — author, stats, the prompt and negative prompt, and the generation parameters. Arrow keys and the mouse wheel page through the feed (Esc closes), and the pager is boundary-safe: open the lightbox on one of the last items and it fetches the next page immediately instead of dead-ending. This is the part the website makes you work for. On CivitAI proper, generation details live behind a click and a scroll per image; here, flipping through a hundred results with the settings pinned next to each one turns browsing into research.Likes that actually mean something
Hearts are first-class: hover a card and a heart appears; the lightbox has one too. Signed out, the heart opens sign-in. Signed in, a like does two things — it reacts on CivitAI, and it mirrors into a default likes collection on your account, picked (or created) in the new account sheet. That mirroring exists because of a quirk we hit building the Favorites tab: on the CivitAI website, the ❤ button saves into a collection, while the reactions API only holds hearts made through the API. Read reactions alone and your Favorites tab shows the handful of things you liked in-panel while the hundreds you hearted on the website are invisible. So the feed reads your likes collection — auto-detected from your account if you haven’t picked one — with reactions as the fallback, and shows all your likes with All/Images/Videos filter chips. Like in the panel, like on the website: one list.Finding a creator without a form
Two paths into a creator’s work. The obvious one: the lightbox and the model detail view both grow a “See more from @creator” button that flips the feed to that person. The better one is GitHub-style search qualifiers. Type@ba0zi cyberpunk city rain into the search box and the @ba0zi token becomes
the creator filter while cyberpunk city rain stays a ranked full-text query.
Under the hood the media search is Meilisearch, and user.username is a
filterable attribute — so the qualifier compiles to a filter while the rest of
your terms keep Meili’s typo-tolerant relevance ranking instead of degrading to
brittle exact-match filters. Only the first @token owns the creator slot
(a pasted sentence with a stray @mention can’t silently retarget your filter),
and deleting the token clears it.
There’s also a proper creator filter in the filter sheet: empty, it shows
the site’s top-creators leaderboard; typing runs a debounced username search;
the pick becomes a removable pill that narrows every feed — images, videos,
media search, and the model tabs alike.
From a post to your canvas
Here’s the loop-closer. A lot of CivitAI posts embed the actual ComfyUI workflow that made them. In the lightbox, a post with an embedded UI-format graph gets a “Load onto canvas” action: it confirms before overwriting unsaved changes, then loads through the same undoable path the agent bridge uses — snapshot,loadGraphData, change-tracker checkState — so one load is
one Ctrl+Z. Posts that only carry the API-format prompt say so honestly
(there’s no client-side API→UI converter, and pretending otherwise corrupts
your canvas); you can still save their JSON.
The Workflows tab goes further: every downloadable workflow file on a model
version gets its own “Load onto canvas” button. Raw .json loads directly —
but CivitAI wraps most workflow files in .zip archives (780 of the 844 live
workflow versions at last count), so the panel unpacks the zip in the
browser: a central-directory walk plus DecompressionStream("deflate-raw"),
no new dependency, with a picker when an archive holds several workflows and
zip-bomb caps on entry count and uncompressed size. The download itself streams
through a same-origin proxy route that follows CivitAI’s 307 redirect
server-side behind an SSRF guard — only CivitAI’s https download CDNs, every
DNS answer verified public, OAuth header dropped on the cross-host hop, 100MB
cap. Gated files (CivitAI redirects some downloads to a login page, even on
nominally public versions) come back as a clean 401 with a one-click sign-in,
and every outcome — downloaded, parsed, empty, API-only, gated — surfaces as
both a toast and an inline status line. The action is never a silent no-op.
And when the post doesn’t have a workflow? Share-with-agent hands the
reference image — actual pixels, via the proxy’s Blob route — plus its full
generation settings to the panel agent with one intent: match this. The agent
has the prompt, the negative, the parameters, and the picture to judge itself
against, on your models, on your GPU.
The agent can open it too
The browser isn’t just a human surface. The agent can open it pre-seeded with a query and filters (cmd: open_civitai) — so “find me some good
cyberpunk LoRAs” answers with a scrollable, filterable grid instead of a text
dump of URLs. The actions inside are mute-aware: with the agent listening, a
pick is handed to it; muted, the panel downloads directly.
One more thing: none of this is desktop-only. The panel’s browser is a direct
port of the mobile app’s CivitAI screens — same tabs, same lightbox, same
creator filter — so the phone and the sidebar stay in lockstep.
Closing the loop
The point was never “CivitAI, but in a modal.” It’s that discovery and execution finally live in the same place: the thing you found, its exact recipe, and the graph that runs it are one click apart, with no download folder in between. Browse in the sidebar, heart what’s good, load the workflow, or tell the agent to match the picture — and the queue is already yours.Grab comfyui-mcp and the Panel to try it, or tell us what the browser should do next at artokun/comfyui-mcp.