gemini-reverse
v1.0.2
Published
Unofficial Node.js client for gemini.google.com — inspired by Gemini-API (Python). Supports streaming, chat sessions, gems, file uploads, and TypeScript.
Maintainers
Readme

Gemini-Reverse
An unofficial Node.js client for gemini.google.com, inspired by Gemini-API — a Python reverse engineering project by @HanaokaYuzu.
This package ports the core concepts and functionality of the original Python library to Node.js, with full CommonJS and TypeScript support.
Features
- Send messages and receive responses from Gemini
- Streaming support with text deltas
- Multi-turn chat sessions with conversation history
- File and image upload support
- Gem (system prompt) management — create, update, delete, fetch
- Auto cookie refresh to keep sessions alive
- TypeScript type declarations included
- Proxy support
Installation
npm install gemini-reverseAuthentication
This package uses browser cookies to authenticate with Gemini. You need to obtain your __Secure-1PSID cookie from your browser after logging in to gemini.google.com.
Steps:
- Open gemini.google.com in your browser and log in
- Open DevTools → Application → Cookies →
https://gemini.google.com - Copy the value of
__Secure-1PSID(and optionally__Secure-1PSIDTS)
__Secure-1PSIDTSis optional — the client will attempt to refresh and cache it automatically after the first successful init.
Quick Start
const { GeminiClient } = require('gemini-core');
const client = new GeminiClient({
secure_1psid: 'YOUR_SECURE_1PSID',
});
await client.init();
const chat = client.startChat();
const response = await chat.sendMessage({ prompt: 'Hello, Gemini!' });
console.log(response.text);Usage
Initialize Client
const client = new GeminiClient({
secure_1psid: 'YOUR_SECURE_1PSID',
secure_1psidts: 'YOUR_SECURE_1PSIDTS', // optional
proxy: 'http://host:port', // optional
});
await client.init({
timeout: 300000, // request timeout in ms, default 300000
autoClose: false, // auto close client after inactivity
closeDelay: 300000, // inactivity delay before closing in ms
autoRefresh: true, // auto refresh cookies in background
refreshInterval: 540000 // cookie refresh interval in ms
});Generate Content (single turn)
const response = await client.generateContent({ prompt: 'What is the capital of France?' });
console.log(response.text);Streaming
for await (const chunk of client.generateContentStream({ prompt: 'Tell me a long story.' })) {
process.stdout.write(chunk.text_delta);
}Chat Session
const chat = client.startChat({ model: 'gemini-3.1-pro' });
const res1 = await chat.sendMessage({ prompt: 'My name is Alice.' });
console.log(res1.text);
const res2 = await chat.sendMessage({ prompt: 'What is my name?' });
console.log(res2.text); // remembers contextStreaming in Chat
const chat = client.startChat({ model: 'gemini-3.0-flash' });
for await (const chunk of chat.sendMessageStream({ prompt: 'Explain quantum computing.' })) {
process.stdout.write(chunk.text_delta);
}Temporary Chat (no history saved)
const chat = client.startChat();
const response = await chat.sendMessage({ prompt: 'This will not appear in history.', temporary: true });Send with Files
const chat = client.startChat();
const response = await chat.sendMessage({
prompt: 'Describe this image.',
files: ['./photo.jpg'],
});
console.log(response.text);Multiple Candidates
const chat = client.startChat();
const response = await chat.sendMessage({ prompt: 'Give me a poem.' });
// list all candidates
response.candidates.forEach((c, i) => console.log(`[${i}] ${c.text}`));
// choose a specific candidate to continue the conversation
chat.chooseCandidate(1);Models
// use model name string
const chat = client.startChat({ model: 'gemini-3.1-pro' });
// or use the Model constant
const { Model } = require('gemini-api');
const chat = client.startChat({ model: Model.G_3_0_FLASH });
// or use a custom model dict
const chat = client.startChat({
model: {
model_name: 'my-model',
model_header: { 'x-goog-ext-525001261-jspb': '...' },
},
});Available models:
| String | Constant |
|---|---|
| gemini-3.1-pro | Model.G_3_1_PRO |
| gemini-3.0-flash | Model.G_3_0_FLASH |
| gemini-3.0-flash-thinking | Model.G_3_0_FLASH_THINKING |
| unspecified (default) | Model.UNSPECIFIED |
Images
Responses may include web images or AI-generated images.
const response = await chat.sendMessage({ prompt: 'Send me an image of a cat.' });
for (const img of response.images) {
console.log(img.url, img.title, img.alt);
await img.save({ path: './downloads', verbose: true });
}Read Chat History
const turns = await client.readChat('c_YOUR_CHAT_ID');
for (const turn of turns) {
console.log('User:', turn.user_prompt);
console.log('Gemini:', turn.assistant_response);
}Delete Chat
await client.deleteChat('c_YOUR_CHAT_ID');Gems
// fetch all gems
const gems = await client.fetchGems();
// get by name
const gem = gems.get({ name: 'Coding partner' });
// filter user-created gems
const myGems = gems.filter({ predefined: false });
// use a gem in chat
const chat = client.startChat({ gem: gem });
// create a gem
const newGem = await client.createGem({
name: 'My Assistant',
prompt: 'You are a helpful assistant that speaks formally.',
description: 'Formal assistant gem',
});
// update a gem
await client.updateGem({
gem: newGem,
name: 'My Assistant v2',
prompt: 'You are a helpful assistant that speaks casually.',
});
// delete a gem
await client.deleteGem(newGem);Close Client
await client.close();TypeScript
This package includes full TypeScript declarations out of the box.
import { GeminiClient, ChatSession, ModelOutput, ConversationTurn, Gem, Model } from 'gemini-api';
const client = new GeminiClient({ secure_1psid: '...' });
await client.init();
const chat: ChatSession = client.startChat({ model: 'gemini-3.1-pro' });
const response: ModelOutput = await chat.sendMessage({ prompt: 'Hello!' });
console.log(response.text);Project Structure
gemini-api/
├── index.js # entry point
├── index.d.ts # TypeScript declarations
├── client.js # GeminiClient + ChatSession
├── constants.js # Endpoint, GRPC, Headers, Model, ErrorCode
├── exceptions.js # custom error classes
├── types/
│ ├── candidate.js
│ ├── conversation.js
│ ├── gem.js
│ ├── grpc.js
│ ├── image.js
│ └── modeloutput.js
├── utils/
│ ├── accessToken.js
│ ├── parsing.js
│ ├── rotate.js
│ └── upload.js
└── components/
├── chatMixin.js
└── gemMixin.jsError Handling
const {
AuthError,
APIError,
GeminiError,
TimeoutError,
UsageLimitExceeded,
ModelInvalid,
TemporarilyBlocked,
} = require('gemini-api');
try {
const response = await chat.sendMessage({ prompt: 'Hello!' });
} catch (e) {
if (e instanceof AuthError) {
console.error('Cookie expired or invalid.');
} else if (e instanceof UsageLimitExceeded) {
console.error('Usage limit reached. Try again later or switch models.');
} else if (e instanceof TemporarilyBlocked) {
console.error('IP temporarily blocked. Try using a proxy.');
} else if (e instanceof TimeoutError) {
console.error('Request timed out.');
} else if (e instanceof ModelInvalid) {
console.error('Invalid or unavailable model.');
} else if (e instanceof APIError) {
console.error('API error:', e.message);
}
}Credits
Inspired by Gemini-API by @HanaokaYuzu — an unofficial Python client for Gemini through reverse engineering.
Disclaimer
This is an unofficial package and is not affiliated with or endorsed by Google. Use at your own risk. Cookie-based authentication may break if Google changes its internal API.
License
MIT
