# Nano Banana Browser POC This repo includes a small browser-driven POC for inspecting Nano Banana's free-tool flow without trying to bypass Turnstile, login, or rate limits. ## What it does - Opens the Nano Banana page in a real browser - Optionally prefills a public image URL - Optionally clicks the primary action button - Captures requests and responses for the relevant private endpoints - Saves screenshots, console logs, downloads, and browser storage state ## What it does not do - It does not bypass Cloudflare Turnstile - It does not bypass login - It does not try to evade rate limits - It is not a production API adapter ## Commands Remove background: ```bash pnpm poc:nanobanana --mode remove-background --auto-submit ``` Upscale: ```bash pnpm poc:nanobanana --mode upscale --auto-submit ``` Use a custom image URL: ```bash pnpm poc:nanobanana \ --mode upscale \ --image-url "https://example.com/demo.jpg" \ --auto-submit ``` ## Useful flags - `--locale en` - `--headless` - `--no-auto-fill` - `--auto-submit` - `--close-on-success` - `--timeout-ms 300000` - `--out-dir /absolute/path/to/output` ## Output By default, artifacts are written to: ```text playwright/nanobanana-poc/-/ ``` The folder includes: - `summary.json` - `session-plan.json` - `storage-state-initial.json` - `storage-state-final.json` - `requests/*.json` - `responses/*.json` - `logs/*.json` - screenshots such as `01-loaded.png` and `99-final.png` ## Current endpoints observed - `/api/img/rmbg` - `/api/img/upscale` - `/api/img/result/{taskId}?type=img` - `/api/img/image-safety` - `/api/presigned-urls` ## Current findings (2026-05-21) These findings were confirmed from the live frontend bundle and manual browser validation. ### Remove background Frontend schema: - `imageSource`: `"upload"` or `"url"` - `imageUrl`: optional string - `turnstileToken`: optional string Observed request shape: ```json { "imageSource": "url", "imageUrl": "https://...", "turnstileToken": "..." } ``` Observed endpoint behavior: - `POST /api/img/rmbg` - `Content-Type: application/json` - success path reads `response.data` as the final output image URL - after success the page clears `turnstileToken` - `403` with `message === "nsfw"` is handled as an NSFW block Manual validation in the in-app browser produced a successful result and exposed a final image URL hosted on `replicate.delivery`, which suggests the private backend may fan out to third-party storage or processing before returning the final asset URL. ### Image upscaler Frontend schema: - `imageSource`: `"upload"` or `"url"` - `imageUrl`: optional string - `scale`: number, min `1`, max `8`, default `4` - `turnstileToken`: optional string Observed submit request shape: ```json { "imageUrl": "https://...", "scale": "4", "turnstileToken": "..." } ``` Upload mode can also send an `image` field populated from the uploaded asset URL. Observed endpoint behavior: - `POST /api/img/upscale` - `Content-Type: application/json` - success path reads `taskId` from `response.data.taskId` or `response.taskId` - the frontend then polls `GET /api/img/result/{taskId}?type=img` - polling treats `code === 1` or `status === 1` as success - final output is read from `data.imgAfterSrc` or `imgAfterSrc` - polling treats `code === 2` or `status === 2` as failure - the polling loop waits 2 seconds and retries up to 60 times - `402` is handled as an upgrade/paywall condition - `403` with `message === "nsfw"` is handled as an NSFW block ### Turnstile Observed Cloudflare site key: - `0x4AAAAAAAh8CLI0IWTYOWMY` Observed frontend behavior: - when `turnstileToken` is missing, the frontend renders or executes Turnstile before submitting - after a successful request, the frontend clears `turnstileToken` - this means the free-tool flow is not designed as a stable unattended API ### Upload helper Observed upload helper behavior: - `POST /api/presigned-urls` with JSON like `{ "count": 1, "fileType": "" }` - response returns `urls` - the browser `PUT`s the file to the returned presigned URL - the frontend then derives a public asset URL in the form: ```text https://temp.videostudioai.com/ ``` ### Practical takeaway This is enough to build an internal unofficial wrapper, but not enough to remove the core operational risk: - the flow still depends on Turnstile - Turnstile tokens are intentionally short-lived and cleared after use - the frontend contract may change at any time - upscaling still appears more likely to require session state than remove-background ## Suggested use Use this only as an internal validation tool to answer questions like: - Does the browser session create anonymous or guest state? - When does Turnstile appear? - Which cookies or local storage values appear before the request? - Does upscaling require an authenticated session? - What request and polling shape does the frontend use today?