Skip to main content

✨ An elegant async Python wrapper for Google Gemini web app

Project description

Gemini Banner

PyPI Downloads Dependencies License Code style

GitHub stars GitHub issues CI

Gemini Icon Gemini-API

A reverse-engineered asynchronous python wrapper for Google Gemini web app (formerly Bard).

Features

  • Persistent Cookies - Automatically refreshes cookies in background. Optimized for always-on services.
  • Image Generation - Natively supports generating and modifying images with natural language.
  • System Prompt - Supports customizing model's system prompt with Gemini Gems.
  • Extension Support - Supports generating contents with Gemini extensions on, like YouTube and Gmail.
  • Classified Outputs - Categorizes texts, thoughts, web images and AI generated images in the response.
  • Official Flavor - Provides a simple and elegant interface inspired by Google Generative AI's official API.
  • Asynchronous - Utilizes asyncio to run generating tasks and return outputs efficiently.

Table of Contents

Installation

[!NOTE]

This package requires Python 3.10 or higher.

Install/update the package with pip.

pip install -U gemini_webapi

Optionally, package offers a way to automatically import cookies from your local browser. To enable this feature, install browser-cookie3 as well. Supported platforms and browsers can be found here.

pip install -U browser-cookie3

Authentication

[!TIP]

If browser-cookie3 is installed, you can skip this step and go directly to usage section. Just make sure you have logged in to https://gemini.google.com in your browser.

  • Go to https://gemini.google.com and login with your Google account
  • Press F12 for web inspector, go to Network tab and refresh the page
  • Click any request and copy cookie values of __Secure-1PSID and __Secure-1PSIDTS

[!NOTE]

If your application is deployed in a containerized environment (e.g. Docker), you may want to persist the cookies with a volume to avoid re-authentication every time the container rebuilds.

Here's part of a sample docker-compose.yml file:

services:
    main:
        volumes:
            - ./gemini_cookies:/usr/local/lib/python3.12/site-packages/gemini_webapi/utils/temp

[!NOTE]

API's auto cookie refreshing feature doesn't require browser-cookie3, and by default is enabled. It allows you to keep the API service running without worrying about cookie expiration.

This feature may cause that you need to re-login to your Google account in the browser. This is an expected behavior and won't affect the API's functionality.

To avoid such result, it's recommended to get cookies from a separate browser session and close it as asap for best utilization (e.g. a fresh login in browser's private mode). More details can be found here.

Usage

Initialization

Import required packages and initialize a client with your cookies obtained from the previous step. After a successful initialization, the API will automatically refresh __Secure-1PSIDTS in background as long as the process is alive.

import asyncio
from gemini_webapi import GeminiClient

# Replace "COOKIE VALUE HERE" with your actual cookie values.
# Leave Secure_1PSIDTS empty if it's not available for your account.
Secure_1PSID = "COOKIE VALUE HERE"
Secure_1PSIDTS = "COOKIE VALUE HERE"

async def main():
    # If browser-cookie3 is installed, simply use `client = GeminiClient()`
    client = GeminiClient(Secure_1PSID, Secure_1PSIDTS, proxy=None)
    await client.init(timeout=30, auto_close=False, close_delay=300, auto_refresh=True)

asyncio.run(main())

[!TIP]

auto_close and close_delay are optional arguments for automatically closing the client after a certain period of inactivity. This feature is disabled by default. In an always-on service like chatbot, it's recommended to set auto_close to True combined with reasonable seconds of close_delay for better resource management.

Generate contents

Ask a single-turn question by calling GeminiClient.generate_content, which returns a gemini_webapi.ModelOutput object containing the generated text, images, thoughts, and conversation metadata.

async def main():
    response = await client.generate_content("Hello World!")
    print(response.text)

asyncio.run(main())

[!TIP]

Simply use print(response) to get the same output if you just want to see the response text

Generate contents with files

Gemini supports file input, including images and documents. Optionally, you can pass files as a list of paths in str or pathlib.Path to GeminiClient.generate_content together with text prompt.

async def main():
    response = await client.generate_content(
            "Introduce the contents of these two files. Is there any connection between them?",
            files=["assets/sample.pdf", Path("assets/banner.png")],
        )
    print(response.text)

asyncio.run(main())

Conversations across multiple turns

If you want to keep conversation continuous, please use GeminiClient.start_chat to create a gemini_webapi.ChatSession object and send messages through it. The conversation history will be automatically handled and get updated after each turn.

async def main():
    chat = client.start_chat()
    response1 = await chat.send_message(
        "Introduce the contents of these two files. Is there any connection between them?",
        files=["assets/sample.pdf", Path("assets/banner.png")],
    )
    print(response1.text)
    response2 = await chat.send_message(
        "Use image generation tool to modify the banner with another font and design."
    )
    print(response2.text, response2.images, sep="\n\n----------------------------------\n\n")

asyncio.run(main())

[!TIP]

Same as GeminiClient.generate_content, ChatSession.send_message also accepts image as an optional argument.

Continue previous conversations

To manually retrieve previous conversations, you can pass previous ChatSession's metadata to GeminiClient.start_chat when creating a new ChatSession. Alternatively, you can persist previous metadata to a file or db if you need to access them after the current Python process has exited.

async def main():
    # Start a new chat session
    chat = client.start_chat()
    response = await chat.send_message("Fine weather today")

    # Save chat's metadata
    previous_session = chat.metadata

    # Load the previous conversation
    previous_chat = client.start_chat(metadata=previous_session)
    response = await previous_chat.send_message("What was my previous message?")
    print(response)

asyncio.run(main())

Select language model

You can specify which language model to use by passing model argument to GeminiClient.generate_content or GeminiClient.start_chat. The default value is unspecified.

Currently available models (as of June 12, 2025):

  • unspecified - Default model
  • gemini-2.5-flash - Gemini 2.5 Flash
  • gemini-2.5-pro - Gemini 2.5 Pro (daily usage limit imposed)

Deprecated models (yet still working):

  • gemini-2.0-flash - Gemini 2.0 Flash
  • gemini-2.0-flash-thinking - Gemini 2.0 Flash Thinking
from gemini_webapi.constants import Model

async def main():
    response1 = await client.generate_content(
        "What's you language model version? Reply version number only.",
        model=Model.G_2_5_FLASH,
    )
    print(f"Model version ({Model.G_2_5_FLASH.model_name}): {response1.text}")

    chat = client.start_chat(model="gemini-2.5-pro")
    response2 = await chat.send_message("What's you language model version? Reply version number only.")
    print(f"Model version (gemini-2.5-pro): {response2.text}")

asyncio.run(main())

Apply system prompt with Gemini Gems

System prompt can be applied to conversations via Gemini Gems. To use a gem, you can pass gem argument to GeminiClient.generate_content or GeminiClient.start_chat. gem can be either a string of gem id or a gemini_webapi.Gem object. Only one gem can be applied to a single conversation.

async def main():
    # Fetch all gems for the current account, including both predefined and user-created ones
    await client.fetch_gems()

    # Once fetched, gems will be cached in `GeminiClient.gems`
    gems = client.gems

    # Get the gem you want to use
    system_gems = gems.filter(predefined=True)
    coding_partner = system_gems.get(id="coding-partner")

    response1 = await client.generate_content(
        "what's your system prompt?",
        model=Model.G_2_5_FLASH,
        gem=coding_partner,
    )
    print(response1.text)

    # Another example with a user-created custom gem
    # Gem ids are consistent strings. Store them somewhere to avoid fetching gems every time
    your_gem = gems.get(name="Your Gem Name")
    your_gem_id = your_gem.id
    chat = client.start_chat(gem=your_gem_id)
    response2 = await chat.send_message("what's your system prompt?")
    print(response2)

Retrieve model's thought process

When using models with thinking capabilities, the model's thought process will be populated in ModelOutput.thoughts.

async def main():
    response = await client.generate_content(
            "What's 1+1?", model="gemini-2.5-pro"
        )
    print(response.thoughts)
    print(response.text)

asyncio.run(main())

Retrieve images in response

Images in the API's output are stored as a list of gemini_webapi.Image objects. You can access the image title, URL, and description by calling Image.title, Image.url and Image.alt respectively.

async def main():
    response = await client.generate_content("Send me some pictures of cats")
    for image in response.images:
        print(image, "\n\n----------------------------------\n")

asyncio.run(main())

Generate images with Imagen4

You can ask Gemini to generate and modify images with Imagen4, Google's latest AI image generator, simply by natural language.

[!IMPORTANT]

Google has some limitations on the image generation feature in Gemini, so its availability could be different per region/account. Here's a summary copied from official documentation (as of March 19th, 2025):

This feature’s availability in any specific Gemini app is also limited to the supported languages and countries of that app.

For now, this feature isn’t available to users under 18.

To use this feature, you must be signed in to Gemini Apps.

You can save images returned from Gemini to local by calling Image.save(). Optionally, you can specify the file path and file name by passing path and filename arguments to the function and skip images with invalid file names by passing skip_invalid_filename=True. Works for both WebImage and GeneratedImage.

async def main():
    response = await client.generate_content("Generate some pictures of cats")
    for i, image in enumerate(response.images):
        await image.save(path="temp/", filename=f"cat_{i}.png", verbose=True)
        print(image, "\n\n----------------------------------\n")

asyncio.run(main())

[!NOTE]

by default, when asked to send images (like the previous example), Gemini will send images fetched from web instead of generating images with AI model, unless you specifically require to "generate" images in your prompt. In this package, web images and generated images are treated differently as WebImage and GeneratedImage, and will be automatically categorized in the output.

Generate contents with Gemini extensions

[!IMPORTANT]

To access Gemini extensions in API, you must activate them on the Gemini website first. Same as image generation, Google also has limitations on the availability of Gemini extensions. Here's a summary copied from official documentation (as of March 19th, 2025):

To connect apps to Gemini, you must have​​​​ Gemini Apps Activity on.

To use this feature, you must be signed in to Gemini Apps.

Important: If you’re under 18, Google Workspace and Maps apps currently only work with English prompts in Gemini.

After activating extensions for your account, you can access them in your prompts either by natural language or by starting your prompt with "@" followed by the extension keyword.

async def main():
    response1 = await client.generate_content("@Gmail What's the latest message in my mailbox?")
    print(response1, "\n\n----------------------------------\n")

    response2 = await client.generate_content("@Youtube What's the latest activity of Taylor Swift?")
    print(response2, "\n\n----------------------------------\n")

asyncio.run(main())

[!NOTE]

For the available regions limitation, it actually only requires your Google account's preferred language to be set to one of the three supported languages listed above. You can change your language settings here.

Check and switch to other reply candidates

A response from Gemini sometimes contains multiple reply candidates with different generated contents. You can check all candidates and choose one to continue the conversation. By default, the first candidate will be chosen.

async def main():
    # Start a conversation and list all reply candidates
    chat = client.start_chat()
    response = await chat.send_message("Recommend a science fiction book for me.")
    for candidate in response.candidates:
        print(candidate, "\n\n----------------------------------\n")

    if len(response.candidates) > 1:
        # Control the ongoing conversation flow by choosing candidate manually
        new_candidate = chat.choose_candidate(index=1)  # Choose the second candidate here
        followup_response = await chat.send_message("Tell me more about it.")  # Will generate contents based on the chosen candidate
        print(new_candidate, followup_response, sep="\n\n----------------------------------\n\n")
    else:
        print("Only one candidate available.")

asyncio.run(main())

Logging Configuration

This package uses loguru for logging, and exposes a function set_log_level to control log level. You can set log level to one of the following values: DEBUG, INFO, WARNING, ERROR and CRITICAL. The default value is INFO.

from gemini_webapi import set_log_level

set_log_level("DEBUG")

[!NOTE]

Calling set_log_level for the first time will globally remove all existing loguru handlers. You may want to configure logging directly with loguru to avoid this issue and have more advanced control over logging behaviors.

References

Google AI Studio

acheong08/Bard

Stargazers

Star History Chart

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gemini_webapi-1.14.2.tar.gz (253.7 kB view details)

Uploaded Source

Built Distribution

gemini_webapi-1.14.2-py3-none-any.whl (50.6 kB view details)

Uploaded Python 3

File details

Details for the file gemini_webapi-1.14.2.tar.gz.

File metadata

  • Download URL: gemini_webapi-1.14.2.tar.gz
  • Upload date:
  • Size: 253.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.8

File hashes

Hashes for gemini_webapi-1.14.2.tar.gz
Algorithm Hash digest
SHA256 f928a5a2a29c2b429cc8f2a4020acc46da7e2c3836e0566f522c8214288e3cb3
MD5 b7291f78ef3c3a55d4acfa5ce9a74f35
BLAKE2b-256 76fe3a871bb13a472cbb868b8d0d7ed590191e4552a94f806fcab37950e7b18c

See more details on using hashes here.

Provenance

The following attestation bundles were made for gemini_webapi-1.14.2.tar.gz:

Publisher: pypi-publish.yml on HanaokaYuzu/Gemini-API

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file gemini_webapi-1.14.2-py3-none-any.whl.

File metadata

  • Download URL: gemini_webapi-1.14.2-py3-none-any.whl
  • Upload date:
  • Size: 50.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.8

File hashes

Hashes for gemini_webapi-1.14.2-py3-none-any.whl
Algorithm Hash digest
SHA256 dabaf20f224f312a2a495125edbe60998323c18d43d25b10bfcae7d2e96aa29d
MD5 8ab2ddaaad6f89d782d8d30e50145795
BLAKE2b-256 91249d94ac20950bcc5fe5328f1fa5df3540b76932ba5759aed170e8bffd717c

See more details on using hashes here.

Provenance

The following attestation bundles were made for gemini_webapi-1.14.2-py3-none-any.whl:

Publisher: pypi-publish.yml on HanaokaYuzu/Gemini-API

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page