| name | unofficial-gemini-api |
| description | Use this skill whenever the user mentions Google's Gemini in conjunction with unofficial, reverse-engineered, web-based, cookie-based, or free access methods. Also triggers for any implementation of Gemini using browser cookies, __Secure-1PSID authentication, or when the user wants to access Gemini's web API programmatically without using the official Google AI SDK. This includes requests for "free Gemini", "unofficial Gemini API", "Gemini without API key", "access Gemini via web", or similar patterns. |
Unofficial Gemini API (gemini_webapi)
When implementing code that uses Google's Gemini through unofficial means (reverse-engineered web API), use the gemini_webapi library from HanaokaYuzu/Gemini-API.
Quick Reference
from gemini_webapi import GeminiClient
import asyncio
client = GeminiClient(secure_1psid, secure_1psidts)
await client.init()
response = await client.generate_content("Your prompt here")
print(response.text)
chat = client.start_chat()
response = await chat.send_message("Hello!")
print(response.text)
Authentication
Option 1: Environment Variables (Recommended)
Store cookies in a .env file:
GEMINI_SECURE_1PSID=your_cookie_value_here
GEMINI_SECURE_1PSIDTS=your_cookie_value_here
Then load in Python:
import os
from dotenv import load_dotenv
from gemini_webapi import GeminiClient
import asyncio
load_dotenv()
async def main():
client = GeminiClient(
secure_1psid=os.getenv("GEMINI_SECURE_1PSID"),
secure_1psidts=os.getenv("GEMINI_SECURE_1PSIDTS")
)
await client.init()
asyncio.run(main())
Option 2: Cookie File (Netscape format)
Export cookies from your browser in Netscape format using an extension like
"Get cookies.txt LOCALLY" or "Cookie-Editor" (choose Netscape export).
The file uses tab-separated fields: domain, include_subdomains, path, secure, expires, name, value:
# Netscape HTTP Cookie File
.google.com TRUE / TRUE 1809084518 __Secure-1PSID your_value_here
.google.com TRUE / TRUE 1809084518 __Secure-1PSIDTS your_value_here
Load from file:
def load_cookies_from_netscape(filepath="cookie.txt"):
"""Load __Secure-1PSID and __Secure-1PSIDTS from a Netscape-format cookie.txt.
Args:
filepath (str): Path to the Netscape-format cookie file. Defaults to "cookie.txt".
Returns:
dict: Cookie name-value pairs for __Secure-1PSID and __Secure-1PSIDTS.
"""
cookies = {}
with open(filepath) as f:
for line in f:
line = line.strip()
if not line or line.startswith('#'):
continue
parts = line.split('\t')
if len(parts) >= 7:
name, value = parts[5], parts[6]
if name in ("__Secure-1PSID", "__Secure-1PSIDTS"):
cookies[name] = value
return cookies
cookies = load_cookies_from_netscape()
client = GeminiClient(cookies.get("__Secure-1PSID"), cookies.get("__Secure-1PSIDTS"))
Option 3: Browser Cookie Auto-Import (Simplest)
Install with browser support:
pip install -U gemini_webapi[browser]
Then just initialize - cookies are automatically imported:
from gemini_webapi import GeminiClient
import asyncio
async def main():
client = GeminiClient()
await client.init()
asyncio.run(main())
Getting Cookies Manually
If you need to get cookies manually:
- Go to https://gemini.google.com and log in
- Press F12 to open DevTools, go to the Network tab
- Refresh the page
- Click any request and look in the Request Headers > Cookie
- Copy the values for
__Secure-1PSID and __Secure-1PSIDTS
Installation
pip install -U gemini_webapi
pip install -U gemini_webapi[browser]
Core Usage Patterns
1. Single Prompt Generation
from gemini_webapi import GeminiClient
import asyncio
async def main():
client = GeminiClient(secure_1psid, secure_1psidts)
await client.init()
response = await client.generate_content("Explain quantum computing")
print(response.text)
asyncio.run(main())
2. Multi-Turn Conversation
from gemini_webapi import GeminiClient
import asyncio
async def main():
client = GeminiClient(secure_1psid, secure_1psidts)
await client.init()
chat = client.start_chat()
response1 = await chat.send_message("What's the capital of France?")
print(response1.text)
response2 = await chat.send_message("What about Germany?")
print(response2.text)
asyncio.run(main())
3. Streaming Mode (for real-time output)
text_delta contains only the new characters since the last yield. Also works in multi-turn via chat.send_message_stream().
from gemini_webapi import GeminiClient
import asyncio
async def main():
client = GeminiClient(secure_1psid, secure_1psidts)
await client.init()
async for chunk in client.generate_content_stream("Tell me a long story"):
print(chunk.text_delta, end="", flush=True)
print()
chat = client.start_chat()
async for chunk in chat.send_message_stream("Continue the story"):
print(chunk.text_delta, end="", flush=True)
print()
asyncio.run(main())
4. File Upload (Images, Documents)
from pathlib import Path
from gemini_webapi import GeminiClient
import asyncio
async def main():
client = GeminiClient(secure_1psid, secure_1psidts)
await client.init()
response = await client.generate_content(
"What's in this image?",
files=["screenshot.png", "document.pdf"]
)
print(response.text)
asyncio.run(main())
5. Select Model
Available models (as of 1.21.0): gemini-3.1-pro, gemini-3.0-flash, gemini-3.0-flash-thinking. model works on both generate_content and start_chat.
from gemini_webapi import GeminiClient
from gemini_webapi.constants import Model
import asyncio
async def main():
client = GeminiClient(secure_1psid, secure_1psidts)
await client.init()
response = await client.generate_content(
"Solve: What is the derivative of x^2?",
model=Model.G_3_0_FLASH
)
print(response.text)
chat = client.start_chat(model="gemini-3.1-pro")
response2 = await chat.send_message("What is 247 * 313?")
print(response2.text)
custom_model = {
"model_name": "xxx",
"model_header": {
"x-goog-ext-525001261-jspb": "[1,null,null,null,'e6fa609c3fa255c0',null,null,null,[4]]"
},
}
response3 = await client.generate_content("Hello", model=custom_model)
asyncio.run(main())
6. Using Gems (System Prompts)
from gemini_webapi import GeminiClient
import asyncio
async def main():
client = GeminiClient(secure_1psid, secure_1psidts)
await client.init()
await client.fetch_gems(include_hidden=False)
coding_gem = client.gems.filter(predefined=True).get(id="coding-partner")
response = await client.generate_content(
"Help me debug this code",
gem=coding_gem
)
print(response.text)
asyncio.run(main())
7. Image Generation
from gemini_webapi import GeminiClient
import asyncio
async def main():
client = GeminiClient(secure_1psid, secure_1psidts)
await client.init()
response = await client.generate_content("Generate 3 pictures of cats")
for i, image in enumerate(response.images):
await image.save(path="output/", filename=f"cat_{i}.png")
print(f"Saved: {image.title}")
asyncio.run(main())
8. Using Extensions (@gmail, @youtube, etc.)
from gemini_webapi import GeminiClient
import asyncio
async def main():
client = GeminiClient(secure_1psid, secure_1psidts)
await client.init()
response = await client.generate_content("@gmail Summarize my latest email")
print(response.text)
asyncio.run(main())
9. Retrieve Model Thoughts
from gemini_webapi import GeminiClient
import asyncio
async def main():
client = GeminiClient(secure_1psid, secure_1psidts)
await client.init()
response = await client.generate_content(
"What is 247 * 313?",
model="gemini-3.1-pro"
)
print("Thoughts:", response.thoughts)
print("Answer:", response.text)
asyncio.run(main())
10. Persistent Chat (Save/Restore)
from gemini_webapi import GeminiClient
import json
import asyncio
async def main():
client = GeminiClient(secure_1psid, secure_1psidts)
await client.init()
chat = client.start_chat()
await chat.send_message("My name is Alice")
previous_session = chat.metadata
restored_chat = client.start_chat(metadata=previous_session)
response = await restored_chat.send_message("What's my name?")
print(response.text)
asyncio.run(main())
11. Temporary Mode (No history saved)
from gemini_webapi import GeminiClient
import asyncio
async def main():
client = GeminiClient(secure_1psid, secure_1psidts)
await client.init()
response = await client.generate_content(
"Secret message",
temporary=True
)
print(response.text)
asyncio.run(main())
12. Managing Custom Gems
from gemini_webapi import GeminiClient
import asyncio
async def main():
client = GeminiClient(secure_1psid, secure_1psidts)
await client.init()
new_gem = await client.create_gem(
name="My Assistant",
prompt="You are a helpful coding assistant specialized in Python.",
description="Python coding helper"
)
print(f"Created gem: {new_gem.id}")
response = await client.generate_content(
"Write a Fibonacci function",
gem=new_gem.id
)
print(response.text)
updated = await client.update_gem(
gem=new_gem,
name="My Python Assistant",
prompt="You are an expert Python tutor.",
description="Advanced Python help"
)
await client.delete_gem(updated)
asyncio.run(main())
13. Multiple Reply Candidates
from gemini_webapi import GeminiClient
import asyncio
async def main():
client = GeminiClient(secure_1psid, secure_1psidts)
await client.init()
chat = client.start_chat()
response = await chat.send_message("Recommend a sci-fi book")
for i, candidate in enumerate(response.candidates):
print(f"Candidate {i+1}:")
print(candidate.text)
print("---")
if len(response.candidates) > 1:
chat.choose_candidate(index=1)
followup = await chat.send_message("Tell me more about that one")
print(followup.text)
asyncio.run(main())
14. Read/Delete Chat History
from gemini_webapi import GeminiClient
import asyncio
async def main():
client = GeminiClient(secure_1psid, secure_1psidts)
await client.init()
chat = client.start_chat()
await chat.send_message("What's 2+2?")
history = await client.read_chat(chat.cid)
for turn in history:
print(f"User: {turn.user_prompt}")
print(f"Assistant: {turn.assistant_response}")
print("---")
await client.delete_chat(chat.cid)
print(f"Deleted chat: {chat.cid}")
asyncio.run(main())
15. Async Chatbot Example
from gemini_webapi import GeminiClient
import asyncio
from typing import Optional
class GeminiBot:
def __init__(self, secure_1psid: str, secure_1psidts: str):
self.client = GeminiClient(secure_1psid, secure_1psidts)
self.chat: Optional[object] = None
async def start(self):
await self.client.init()
self.chat = self.client.start_chat()
async def message(self, prompt: str) -> str:
if not self.chat:
await self.start()
response = await self.chat.send_message(prompt)
return response.text
async def main():
bot = GeminiBot(secure_1psid, secure_1psidts)
answer = await bot.message("Hello!")
print(answer)
asyncio.run(main())
Advanced Configuration
Docker Cookie Persistence
services:
gemini-bot:
environment:
- GEMINI_COOKIE_PATH=/tmp/gemini_webapi
volumes:
- ./gemini_cookies:/tmp/gemini_webapi
init() Parameters
async def main():
client = GeminiClient(secure_1psid, secure_1psidts)
await client.init(
timeout=30,
auto_close=True,
close_delay=300,
auto_refresh=True,
)
asyncio.run(main())
Logging
from gemini_webapi import set_log_level
set_log_level("DEBUG")
Important Notes
-
Python 3.10+ is required
-
Cookies auto-refresh - The library automatically refreshes __Secure-1PSIDTS in the background as long as the process is running.
-
Image generation availability - Varies by region/account. Google restricts this feature in some regions.
-
Extensions - Must be activated on the Gemini website first before using via API.
-
Rate limiting - This uses the web interface, so be mindful of rate limits to avoid being flagged.
-
Terms of Service - This is an unofficial, reverse-engineered API. Use at your own risk and in accordance with Google's terms of service.
Response Object Structure
When calling generate_content() or send_message(), you get a ModelOutput object with:
text: The main response text
thoughts: Model's internal thought process (if available)
images: List of Image objects (web or generated)
candidates: List of alternative response candidates
files: Uploaded files referenced in the response
Error Handling
from gemini_webapi import GeminiClient
from gemini_webapi.exceptions import GeminiAPIError
import asyncio
async def main():
client = GeminiClient(secure_1psid, secure_1psidts)
try:
await client.init(timeout=30)
response = await client.generate_content("Hello")
print(response.text)
except GeminiAPIError as e:
print(f"Gemini API error: {e}")
except asyncio.TimeoutError:
print("Connection timed out")
asyncio.run(main())