| name | openclaw-zero-token |
| description | Use major AI models (Claude, ChatGPT, Gemini, DeepSeek, Qwen, etc.) without API tokens by leveraging browser authentication instead of paid API keys |
| triggers | ["set up openclaw zero token","use AI models without API keys","configure browser auth for LLMs","run DeepSeek/Claude/Qwen without tokens","onboard web model authentication","start openclaw gateway","use tool calling with web models","query multiple AI models at once"] |
OpenClaw Zero Token
Skill by ara.so — Hermes Skills collection.
OpenClaw Zero Token is a TypeScript-based gateway that lets you use major AI models (Claude, ChatGPT, Gemini, DeepSeek, Qwen, Kimi, Doubao, Grok, GLM, Xiaomi MiMo, Manus) completely free by automating browser-based authentication instead of requiring paid API tokens. It drives official web UIs using Chrome DevTools Protocol (CDP) and Playwright to capture credentials, then proxies requests through a unified OpenAI-compatible API gateway.
What It Does
- Zero-cost LLM access: Log in via browser once, reuse credentials for API calls
- Unified gateway: OpenAI-compatible API endpoint on port 3001
- 11 web models with tool calling:
web_search, web_fetch, exec, read, write, message
- AskOnce multi-model queries: Broadcast one question to all configured providers
- Web UI + CLI + Gateway: Multiple interaction modes (Lit 3.x UI, TUI, REST API)
Supported Providers
| Provider | Status | Auth Method |
|---|
| DeepSeek | ✅ | Browser login |
| Qwen (intl/cn) | ✅ | Browser login |
| Kimi | ✅ | Browser login |
| Claude Web | ✅ | Browser login |
| ChatGPT Web | ✅ | Browser login |
| Gemini Web | ✅ | Browser login |
| Grok Web | ✅ | Browser login |
| Doubao | ✅ | Browser login |
| GLM/GLM Intl | ✅ | Browser login |
| Xiaomi MiMo | ✅ | Browser login |
| Manus API | ✅ | API key (free) |
Installation
Prerequisites
node --version
pnpm --version
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt-get install -y nodejs
npm install -g pnpm
Clone and Build
git clone https://github.com/linuxhsj/openclaw-zero-token.git
cd openclaw-zero-token
pnpm install
pnpm build
pnpm ui:build
Configuration
Environment Setup
Create .env file:
PORT=3001
NODE_ENV=production
CHROME_DEBUG_PORT=9222
AGENT_WORKSPACE=/home/user/agent-workspace
LOG_LEVEL=info
First-Time Authentication Flow
OpenClaw uses a three-step process:
- Start debug Chrome → Opens browser on port 9222
- Login to web models → Manual browser login (scan QR / password)
- Run onboard wizard → Captures credentials automatically
./start-chrome-debug.sh
./onboard.sh webauth
The onboard.sh script uses Playwright CDP to intercept network requests and extract:
- Cookies
- Bearer tokens
- User-Agent headers
Starting the Gateway
./server.sh start
./server.sh stop
./server.sh restart
./server.sh status
pnpm start
Gateway runs on http://localhost:3001 with OpenAI-compatible endpoints.
Key Commands and Scripts
Core Scripts
| Script | Purpose |
|---|
./start-chrome-debug.sh | Launch Chrome on port 9222 for logins |
./onboard.sh webauth | Run auth wizard to capture credentials |
| `./server.sh [start | stop]` |
pnpm build | Build TypeScript backend |
pnpm ui:build | Build Lit 3.x frontend |
pnpm test | Run test suite |
pnpm Scripts (package.json)
pnpm build
pnpm ui:build
pnpm build:all
pnpm dev
pnpm start
pnpm test
pnpm lint
pnpm format
API Usage
OpenAI-Compatible Endpoints
OpenClaw exposes a standard OpenAI API format on port 3001:
curl http://localhost:3001/v1/models
curl http://localhost:3001/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-web/deepseek-chat",
"messages": [{"role": "user", "content": "Hello!"}]
}'
curl http://localhost:3001/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "qwen-web/qwen-turbo",
"messages": [{"role": "user", "content": "Count to 5"}],
"stream": true
}'
TypeScript Client Example
import OpenAI from 'openai';
const client = new OpenAI({
baseURL: 'http://localhost:3001/v1',
apiKey: 'not-needed',
});
async function chat() {
const response = await client.chat.completions.create({
model: 'deepseek-web/deepseek-chat',
messages: [
{ role: 'user', content: 'Explain TypeScript generics' }
],
});
console.log(response.choices[0].message.content);
}
chat();
Streaming Response
async function streamChat() {
const stream = await client.chat.completions.create({
model: 'kimi/moonshot-v1-8k',
messages: [{ role: 'user', content: 'Write a haiku' }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content || '');
}
}
Tool Calling (Web Models)
OpenClaw injects tool definitions into prompts for 11/13 web models. Tools are only injected when user message contains keywords like "search", "read", "execute".
Available Tools
| Tool | Function | Provider Support |
|---|
web_search | DuckDuckGo search | 11/13 models |
web_fetch | Fetch webpage content | 11/13 models |
exec | Execute shell command | 11/13 models |
read | Read file (workspace restricted) | 11/13 models |
write | Write file (workspace restricted) | 11/13 models |
message | Structured output | 11/13 models |
Tool Calling Example
const response = await client.chat.completions.create({
model: 'deepseek-web/deepseek-chat',
messages: [{
role: 'user',
content: 'Search for TypeScript 5.4 release notes and summarize'
}],
});
Agent File Access Configuration
Tools like read/write are restricted to the configured workspace:
AGENT_WORKSPACE=/home/user/projects/safe-zone
const badRead = await client.chat.completions.create({
model: 'kimi/moonshot-v1-32k',
messages: [{
role: 'user',
content: 'Read /etc/passwd'
}],
});
const goodRead = await client.chat.completions.create({
model: 'kimi/moonshot-v1-32k',
messages: [{
role: 'user',
content: 'Read project-notes.md'
}],
});
AskOnce: Multi-Model Queries
Query all configured providers simultaneously:
pnpm ask-once "What is the capital of France?"
import { askOnce } from './src/zero-token/ask-once';
const results = await askOnce({
query: 'Explain quantum entanglement in one sentence',
providers: ['deepseek-web', 'qwen-web', 'kimi', 'claude-web'],
});
results.forEach(({ provider, response, duration }) => {
console.log(`[${provider}] (${duration}ms): ${response}`);
});
Common Patterns
1. Multi-Provider Failover
const providers = [
'deepseek-web/deepseek-chat',
'qwen-web/qwen-turbo',
'kimi/moonshot-v1-8k',
];
async function chatWithFailover(message: string) {
for (const model of providers) {
try {
const response = await client.chat.completions.create({
model,
messages: [{ role: 'user', content: message }],
});
return response.choices[0].message.content;
} catch (error) {
console.warn(`${model} failed, trying next...`);
}
}
throw new Error('All providers failed');
}
2. Model Routing by Task
function selectModel(task: string): string {
if (task.includes('reasoning') || task.includes('logic')) {
return 'deepseek-web/deepseek-reasoner';
}
if (task.includes('code')) {
return 'qwen-web/qwen-plus';
}
return 'kimi/moonshot-v1-8k';
}
const model = selectModel('Write a sorting algorithm');
const response = await client.chat.completions.create({
model,
messages: [{ role: 'user', content: 'Implement quicksort in Python' }],
});
3. Workspace-Safe Agent
import * as path from 'path';
const WORKSPACE = process.env.AGENT_WORKSPACE || '/tmp/agent-workspace';
async function safeAgentTask(instruction: string) {
await fs.promises.mkdir(WORKSPACE, { recursive: true });
const response = await client.chat.completions.create({
model: 'kimi/moonshot-v1-32k',
messages: [{
role: 'system',
content: `You are a helpful agent. All file operations must be within ${WORKSPACE}.`
}, {
role: 'user',
content: instruction
}],
});
return response.choices[0].message.content;
}
await safeAgentTask('Write the current timestamp to notes.txt');
4. Re-authentication Helper
import { execSync } from 'child_process';
async function ensureAuth(provider: string) {
const authPath = `data/auth/${provider}.json`;
try {
const authData = await fs.promises.readFile(authPath, 'utf-8');
const parsed = JSON.parse(authData);
if (Date.now() > parsed.expiresAt) {
console.log(`Auth expired for ${provider}, re-running onboard...`);
execSync(`./onboard.sh webauth ${provider}`, { stdio: 'inherit' });
}
} catch (error) {
console.log(`No auth found for ${provider}, running onboard...`);
execSync(`./onboard.sh webauth ${provider}`, { stdio: 'inherit' });
}
}
await ensureAuth('deepseek-web');
Troubleshooting
Chrome Debug Port Issues
Symptom: onboard.sh fails with "Cannot connect to CDP"
pkill -f "chrome.*remote-debugging-port=9222"
./start-chrome-debug.sh
lsof -i :9222
Authentication Expired
Symptom: API calls return 401/403 after initial setup
./onboard.sh webauth
Stream Parsing Errors
Symptom: "Cannot parse SSE stream" for Doubao or Gemini
const response = await client.chat.completions.create({
model: 'doubao/doubao-pro',
messages: [{ role: 'user', content: 'Hello' }],
stream: false,
});
Tool Calling Not Triggering
Symptom: Model doesn't use tools despite keyword in message
const response = await client.chat.completions.create({
model: 'kimi/moonshot-v1-32k',
messages: [{
role: 'user',
content: 'SEARCH for TypeScript 5.4 release notes'
}],
});
Gateway Won't Start
lsof -i :3001
kill -9 $(lsof -t -i :3001)
tail -f logs/gateway.log
pnpm build
pnpm ui:build
Model Rate Limits
Symptom: Web model returns "Too many requests"
async function chatWithRetry(model: string, message: string, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
return await client.chat.completions.create({
model,
messages: [{ role: 'user', content: message }],
});
} catch (error: any) {
if (error.status === 429 && i < retries - 1) {
const delay = Math.pow(2, i) * 1000;
console.log(`Rate limited, waiting ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
}
Advanced Configuration
Custom Provider Setup
import { BaseWebProvider } from './base-web-provider';
export class CustomProvider extends BaseWebProvider {
constructor() {
super({
name: 'custom-web',
chatUrl: 'https://custom-ai.example.com/chat',
apiEndpoint: 'https://custom-ai.example.com/api/v1/chat',
});
}
async authenticate(page: Page): Promise<AuthData> {
const token = await page.evaluate(() => {
return localStorage.getItem('auth_token');
});
return {
token,
cookies: await page.context().cookies(),
userAgent: await page.evaluate(() => navigator.userAgent),
};
}
}
Environment Variables Reference
PORT=3001
NODE_ENV=production
LOG_LEVEL=info
CHROME_DEBUG_PORT=9222
HEADLESS=false
AGENT_WORKSPACE=/path/to/workspace
TOOL_TIMEOUT=30000
DEEPSEEK_CUSTOM_ENDPOINT=https://...
QWEN_API_VERSION=v1
File Structure
openclaw-zero-token/
├── src/
│ ├── zero-token/
│ │ ├── providers/ # Web model implementations
│ │ │ ├── deepseek-web.ts
│ │ │ ├── qwen-web.ts
│ │ │ ├── kimi.ts
│ │ │ └── ...
│ │ ├── tool-calling/ # Tool injection middleware
│ │ │ ├── tools.ts # Tool definitions
│ │ │ └── middleware.ts # Prompt injection logic
│ │ ├── ask-once/ # Multi-model query system
│ │ └── auth/ # Authentication capture
│ ├── gateway/ # OpenAI-compatible API gateway
│ └── ui/ # Lit 3.x web interface
├── data/
│ └── auth/ # Stored credentials (gitignored)
│ ├── deepseek-web.json
│ ├── qwen-web.json
│ └── ...
├── scripts/
│ ├── start-chrome-debug.sh # Chrome launcher
│ ├── onboard.sh # Auth wizard
│ └── server.sh # Gateway daemon manager
├── .env # Environment config
└── package.json
Security Notes
- Auth Data:
data/auth/*.json contains sensitive credentials — never commit
- Chrome Debug Port: Port 9222 allows full browser control — DO NOT expose externally
- Workspace Restriction: Agent file tools are sandboxed to
AGENT_WORKSPACE
- HTTPS Required: Use reverse proxy (nginx/Caddy) for production deployment
Example nginx config:
server {
listen 443 ssl;
server_name openclaw.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
}
}
References