Skip to content

Guardinary/web2gem

Repository files navigation

web2gem

English | 简体中文

OpenAI-compatible and Google-compatible HTTP adapter for Gemini Web, deployable on Cloudflare Workers or as a Docker service.Zero cost, cross-platform, single file.

TypeScript lives under src/, local quality gates live under scripts/, dist/worker.js is generated by pnpm build for Wrangler deployment, and scripts/docker-server.mjs provides the Docker HTTP adapter.

Contents

Overview

web2gem translates common OpenAI and Google Gemini API shapes into Gemini Web requests. It can run as a Cloudflare Worker or as a Docker-hosted Node service. On Workers it can use cloudflare:sockets for upstream HTTP transport when regular fetch paths are rate-limited; Docker deployments use standard fetch transport by default.

The main compatibility targets are:

Surface Status Routes
OpenAI Chat Completions Supported POST /v1/chat/completions
OpenAI Responses Supported POST /v1/responses
OpenAI Models Supported GET /v1/models, GET /v1/models/{id}
Google Gemini generateContent Supported POST /v1beta/models/{model}:generateContent, POST /v1/models/{model}:generateContent
Google Gemini streamGenerateContent Supported POST /v1beta/models/{model}:streamGenerateContent, POST /v1/models/{model}:streamGenerateContent
Google Models Supported GET /v1beta/models, GET /v1beta/models/{model}
Health Supported GET /

Core Features

Feature Description
Ready-to-use Flash models No authentication or configuration is required; deploy the single file to start using Flash models with no usage limits, completely free.
OpenAI-compatible API Chat Completions and Responses endpoints with streaming support.
Google-compatible API generateContent and streamGenerateContent routes for Gemini-style clients.
Tool calling Converts tool definitions into prompt instructions and parses DSML/XML-style tool-call output back into API responses.
Structured output Validates and canonicalizes final JSON for non-streaming structured responses; streaming structured output is rejected by default.
Large context handling Can upload large prompt context as Gemini text attachments when a Gemini cookie is configured.
Image handling Resolves image inputs through the Gemini provider path where supported by the request shape.
Generic file attachments Request-local input_file and inline non-image data can use Gemini Web upload refs for arbitrary filenames and MIME types; /v1/files persistence is not implemented.
Worker and Docker deployment Deploy with Wrangler to Cloudflare Workers, or self-host with Docker / Docker Compose.
Upstream socket transport Uses cloudflare:sockets on Workers by default, with Docker using standard fetch transport unless a compatible sockets runtime is provided.
CORS and API key gate Handles browser preflight requests and optional bearer/API-key authentication.
Local test bundle Builds a separate dist/worker.test.js so unit tests can inspect internals without leaking test helpers into production.

API Surface

Health

curl https://your-web2gem.example/

Returns service status, version, and the model IDs currently exposed by the adapter.

OpenAI Chat Completions

curl https://your-web2gem.example/v1/chat/completions \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3.5-flash",
    "messages": [
      { "role": "user", "content": "Write a concise project summary." }
    ]
  }'

Set "stream": true to receive Server-Sent Events.

OpenAI Responses

curl https://your-web2gem.example/v1/responses \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3.5-flash",
    "input": "Explain what this worker does in one paragraph."
  }'

Google Gemini API

curl https://your-web2gem.example/v1beta/models/gemini-3.5-flash:generateContent \
  -H "x-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contents": [
      {
        "role": "user",
        "parts": [{ "text": "Return a short deployment checklist." }]
      }
    ]
  }'

For streaming, call :streamGenerateContent on the same model path.

Models

web2gem exposes a fixed model map in src/models/index.ts.

Model ID Description
gemini-3.5-flash Fast general-purpose model.
gemini-3.5-flash-thinking Deep thinking mode with longer output.
gemini-3.1-pro Pro route; requires a valid Gemini cookie for real routing.
gemini-3.1-pro-enhanced Experimental enhanced Pro output mode.
gemini-auto Gemini Web auto model selection.
gemini-3.5-flash-thinking-lite Dynamic thinking with adaptive depth.
gemini-flash-lite Lightweight fast model.

You can override thinking depth per request by appending @think=N to a known model ID, for example gemini-3.5-flash@think=0. Supported override values are 0, 1, 2, 3, and 4.

Quick Start

Both deployment modes can run without secrets. Configure optional secrets only when you need authentication or cookie-backed Gemini Web features.

Option 1: Deploy the release single-file Worker

Download the release build artifact worker.js from the Releases page, open your Cloudflare Worker in the dashboard, and replace the Worker source with the contents of that file. In the Worker dashboard settings, add the nodejs_compat compatibility flag.

Cloudflare Worker settings showing nodejs_compat

Each release publishes these assets:

Asset Use
worker.js Single-file Cloudflare Worker bundle.
web2gem_<tag>_docker_linux_amd64.tar.gz Docker image archive for linux/amd64.
web2gem_<tag>_docker_linux_arm64.tar.gz Docker image archive for linux/arm64.
sha256sums.txt Checksums for the released files.

Secrets are optional. In the Worker dashboard, open the Worker settings and add variables/secrets only for the features you need. Set API_KEYS when you want to protect shared access, and set GEMINI_COOKIE when Pro routing or large-context text attachments are needed.

Cloudflare Worker settings showing secrets

If you build from source instead of using a release artifact, pnpm deploy builds dist/worker.js and deploys it through the checked-in wrangler.toml.

Option 2: Deploy with Docker

Use .env.example as the environment template and compose.yaml as the Compose service definition:

cp .env.example .env
docker compose up -d

The provided compose.yaml pulls ghcr.io/guardinary/web2gem:latest by default, maps ${PORT:-52389}:${PORT:-52389}, and forwards the runtime variables from .env. Set API_KEYS in .env for shared deployments, and set GEMINI_COOKIE when Pro routing or large-context text attachments are needed. To pin a specific image tag, set WEB2GEM_IMAGE=ghcr.io/guardinary/web2gem:<tag> in .env.

After the container starts, verify the local health route:

curl http://127.0.0.1:52389/

If you changed PORT in .env, use that host port instead. Docker deployments default UPSTREAM_SOCKET to false in .env.example because cloudflare:sockets is only available in the Cloudflare Workers runtime. Other runtime variables are the same as the configuration variables listed below.

For one-off local testing without Compose, you can still build and run the image directly:

docker build -t web2gem .
docker run --rm -p 52389:52389 --env-file .env web2gem

Release pages also provide prebuilt Docker image archives. Download the archive matching your platform, load it, and run the tagged image:

gzip -dc web2gem_<tag>_docker_linux_amd64.tar.gz | docker load
docker run --rm -p 52389:52389 --env-file .env web2gem:<tag>

If the upstream Gemini Web path starts returning empty output, first check whether GEMINI_BL needs to be refreshed from the current Gemini Web frontend. If Cloudflare egress is rate-limited, set GEMINI_ORIGIN to your own forwarding service or proxy endpoint.

Configuration

Configuration defaults live in src/config/index.ts. Cloudflare Worker environment variables / secrets and Docker environment variables override those defaults at runtime.

Variable Default Description
API_KEYS empty Comma-separated or JSON-array API keys. Empty disables auth.
GEMINI_COOKIE empty Raw Gemini cookie string; JSON with cookie and optional sapisid; or JSON with secure_1psid, secure_1psidts, and optional sapisid. Needed only for real Pro routing and large-context text attachments.
SAPISID empty Optional SAPISID override. If empty, it is extracted from GEMINI_COOKIE when possible.
GEMINI_BL bundled value Gemini Web build label used by upstream requests. Update if Gemini Web changes and upstream responses become empty.
GEMINI_ORIGIN https://gemini.google.com Upstream origin. Can point to your own forwarding service or proxy endpoint while preserving expected request semantics.
UPSTREAM_SOCKET true Prefer cloudflare:sockets upstream transport when available.
DEFAULT_MODEL gemini-3.5-flash Model used when a request omits model.
RETRY_ATTEMPTS 3 Upstream retry attempts; minimum 1.
RETRY_DELAY_SEC 2 Delay between retry attempts; minimum 0.
REQUEST_TIMEOUT_SEC 180 Upstream request timeout; minimum 1.
LOG_REQUESTS false Enable structured runtime stage logs.
CURRENT_INPUT_FILE_ENABLED true Enable Gemini text attachments for large prompt context.
CURRENT_INPUT_FILE_MIN_BYTES 95000 Inline prompt byte threshold before text attachment handling is attempted.
CURRENT_INPUT_FILE_NAME message.txt Filename used for large message context attachment.
CURRENT_TOOLS_FILE_NAME tools.txt Filename used for large tool-definition context attachment.
GENERIC_FILE_UPLOAD_MAX_BYTES 20971520 Maximum bytes per request-local attachment. The preferred upload path does not send Gemini cookie or SAPISID authorization to content-push.googleapis.com; unavailable or failed request-local uploads are ignored with a prompt note.

When managing a Worker through the Wrangler CLI, optional secrets can be set with:

  • Set API_KEYS for shared deployments. If it is empty, auth is disabled.
  • Set GEMINI_COOKIE when Pro routing or large-context text attachments are needed.
wrangler secret put API_KEYS
wrangler secret put GEMINI_COOKIE

When GEMINI_COOKIE contains __Secure-1PSID, the Worker keeps an in-memory active cookie for the current isolate and lazily calls Google's RotateCookies endpoint when the cookie is stale or an authenticated upstream request fails. Refreshed cookies are kept in memory only; the Worker does not use a database for them or write them back to Worker secrets. A cold start initializes again from GEMINI_COOKIE.

For single-cookie deployments, use the shortest practical cookie form: __Secure-1PSID, __Secure-1PSIDTS, and optional SAPISID. A fresh private-browser Gemini login that is closed after extracting these values tends to be more stable than copying a full everyday-browser cookie header. If a cold start falls back to an expired __Secure-1PSIDTS, the first authenticated request will try to rotate it. If Google rejects that rotation or returns no updated cookie, update the GEMINI_COOKIE secret manually.

Short JSON cookie form:

{
  "secure_1psid": "YOUR_SECURE_1PSID",
  "secure_1psidts": "YOUR_SECURE_1PSIDTS",
  "sapisid": "OPTIONAL_SAPISID"
}

For local development, use Wrangler environment support or pass bindings through the local Worker environment.

Authentication

When API_KEYS is empty, every route except Cloudflare/Wrangler infrastructure is publicly callable. For any shared deployment, set at least one API key.

web2gem accepts:

  • Authorization: Bearer <key>
  • x-api-key: <key>
  • x-goog-api-key: <key>

The health route GET / remains unauthenticated so deployment probes can work without secrets.

Development

Authored source lives under src/. Do not hand-edit generated files under dist/.

pnpm install
pnpm typecheck
pnpm check:arch
pnpm unit
pnpm smoke

The build script emits two bundles:

Bundle Source Purpose
dist/worker.js src/index.ts Production Worker deployed by Wrangler.
dist/worker.test.js src/test-index.ts Local test bundle with internal helper exports.

Testing

Command Description
pnpm typecheck Run TypeScript with strict compiler settings.
pnpm check:arch Enforce import boundaries and detect source dependency cycles.
pnpm unit:quick Rebuild stale test bundles when needed, then run local unit checks under tests/unit/ with Vitest.
pnpm unit Build both bundles and run local unit checks under tests/unit/ with Vitest.
pnpm coverage Build an isolated coverage bundle and write Vitest V8 text, lcov, and JSON summary reports to coverage/.
pnpm coverage:ci Run Vitest V8 coverage with global thresholds plus source line and branch coverage gates.
pnpm smoke Build both bundles, verify public exports, request-level routing checks, health route, and DSML tool-call parsing.
pnpm docker:smoke Build the Docker image, run a temporary container, and verify health, auth, and OpenAI route behavior through the Node adapter.

Coverage builds write sourcemapped test bundles to dist-coverage/ so normal dist/ builds and coverage runs do not share generated artifacts. Vitest discovers tests/unit/*.test.mjs wrappers for pnpm unit; shared case lists live in tests/unit/*.cases.mjs, use Vitest-backed assertions, and coverage uses Vitest's V8 provider against the isolated test bundle. pnpm coverage and pnpm coverage:ci use a Node runner so environment variables are handled consistently across Windows and Unix shells. pnpm coverage:ci also reads coverage/coverage-summary.json through scripts/check-coverage.mjs to catch regressions in key source directories and selected high-risk branch paths.

Recommended pre-commit gate:

pnpm typecheck
pnpm check:arch
pnpm unit
pnpm coverage:ci
pnpm smoke
# Optional when Docker is available:
pnpm docker:smoke

Project Structure

.
├── scripts/                 # Build, architecture, unit, and smoke scripts
├── src/
│   ├── completion/          # Provider-neutral completion runtime
│   ├── config/              # Runtime configuration parsing
│   ├── gemini/              # Gemini Web client, transport, uploads, provider adapter
│   ├── http/                # HTTP boundary, OpenAI and Google protocol adapters
│   ├── models/              # Exposed model map and model resolution
│   ├── promptcompat/        # API request shapes to Gemini prompt text
│   ├── shared/              # Provider-neutral utilities
│   ├── toolcall/            # Tool-call prompt, policy, parser, formatter
│   └── toolstream/          # Streamed tool-call detection state
├── tests/unit/              # Local unit checks
├── wrangler.toml            # Cloudflare Worker deployment config
└── package.json             # Node scripts and dev dependencies

Security Notice

This project adapts Gemini Web behavior and depends on upstream web protocol details that can change without notice. Use it for personal, research, or internal validation scenarios, and review the terms and risk profile of the upstream service before deploying it for shared use.

Never commit Gemini cookies or API keys. Store secrets in Cloudflare Worker secrets, Docker environment management, or another deployment-secret mechanism.

Acknowledgements

LinuxDo

License

MIT

About

OpenAI-compatible and Google-compatible HTTP adapter for Gemini Web, deployable on Cloudflare Workers or as a Docker service.Zero cost, cross-platform, single file.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors