SPB Git

Repository Public

tokens.md 24.1 KB 720 lines markdown

1Gemini and other generative AI models process input and output at a granularity2called a *token*.34**For Gemini models, a token is equivalent to about 4 characters.5100 tokens is equal to about 60-80 English words.**67## About tokens89Tokens can be single characters like `z` or whole words like `cat`. Long words10are broken up into several tokens. The set of all tokens used by the model is11called the vocabulary, and the process of splitting text into tokens is called12*tokenization*.1314When billing is enabled, the [cost of a call to the Gemini API](https://ai.google.dev/pricing) is15determined in part by the number of input and output tokens, so knowing how to16count tokens can be helpful.1718You can try out counting tokens in our Colab.1920|---|---|---|21| [![](https://ai.google.dev/static/site-assets/images/docs/notebook-site-button.png)View on ai.google.dev](https://ai.google.dev/gemini-api/docs/tokens) | [![](https://www.tensorflow.org/images/colab_logo_32px.png)Try a Colab notebook](https://colab.research.google.com/github/google-gemini/cookbook/blob/main/quickstarts/Counting_Tokens.ipynb) | [![](https://www.tensorflow.org/images/GitHub-Mark-32px.png)View notebook on GitHub](https://colab.research.google.com/github/google-gemini/cookbook/blob/main/quickstarts/Counting_Tokens.ipynb) |2223## Count tokens2425All input to and output from the Gemini API is tokenized, including text, image26files, and other non-text modalities.2728You can count tokens in the following ways:2930- **Call [`count_tokens`](https://ai.google.dev/api/rest/v1/models/countTokens) with the input31  of the request.**   32  This returns the total number of tokens in *the33  input only*. You can make this call before sending the input to the34  model to check the size of your requests.3536- **Use the `usage_metadata` attribute on the `response` object after37  calling `generate_content`.**   38  This returns the total number of39  tokens in *both the input and the output* : `total_token_count`.  40  It41  also returns the token counts of the input and output separately:42  `prompt_token_count` (input tokens) and `candidates_token_count`43  (output tokens).4445  If you are using a [thinking46  model](https://ai.google.dev/gemini-api/docs/thinking), the tokens used during the thinking47  process are returned in `thoughts_token_count`. And if you are using48  [Context caching](https://ai.google.dev/gemini-api/docs/caching), the cached token49  count will be in `cached_content_token_count`.5051### Count text tokens5253If you call `count_tokens` with a text-only input, it returns the token count of54the text in *the input only* (`total_tokens`). You can make this call before55calling `generate_content` to check the size of your requests.5657Another option is calling `generate_content` and then using the `usage_metadata`58attribute on the `response` object to get the following:5960- The separate token counts of the input (`prompt_token_count`), the cached content (`cached_content_token_count`) and the output (`candidates_token_count`)61- The token count for the thinking process (`thoughts_token_count`)62- The total number of tokens in *both the input and the output*63  (`total_token_count`)6465### Python6667    from google import genai6869    client = genai.Client()70    prompt = "The quick brown fox jumps over the lazy dog."7172    total_tokens = client.models.count_tokens(73        model="gemini-3.8-flash", contents=prompt74    )75    print("total_tokens: ", total_tokens)7677    response = client.models.generate_content(78        model="gemini-3.8-flash", contents=prompt79    )8081    print(response.usage_metadata)8283### JavaScript8485    import { GoogleGenAI } from '@google/genai';8687    const ai = new GoogleGenAI({});88    const prompt = "The quick brown fox jumps over the lazy dog.";8990    async function main() {91      const countTokensResponse = await ai.models.countTokens({92        model: "gemini-3.8-flash",93        contents: prompt,94      });95      console.log(countTokensResponse.totalTokens);9697      const generateResponse = await ai.models.generateContent({98        model: "gemini-3.8-flash",99        contents: prompt,100      });101      console.log(generateResponse.usageMetadata);102    }103104    await main();105106### Go107108    ctx := context.Background()109    client, err := genai.NewClient(ctx, nil)110111    // Convert prompt to a slice of *genai.Content using the helper.112    contents := []*genai.Content{113      genai.NewContentFromText(prompt, genai.RoleUser),114    }115    countResp, err := client.Models.CountTokens(ctx, "gemini-3.8-flash", contents, nil)116    if err != nil {117      return err118    }119    fmt.Println("total_tokens:", countResp.TotalTokens)120121    response, err := client.Models.GenerateContent(ctx, "gemini-3.8-flash", contents, nil)122    if err != nil {123      log.Fatal(err)124    }125    usageMetadata, err := json.MarshalIndent(response.UsageMetadata, "", "  ")126    if err != nil {127      log.Fatal(err)128    }129    fmt.Println(string(usageMetadata))130        ```131132### Count multi-turn (chat) tokens133134If you call `count_tokens` with the chat history, it returns the total token135count of the text from each role in the chat (`total_tokens`).136137Another option is calling `send_message` and then using the `usage_metadata`138attribute on the `response` object to get the following:139140- The separate token counts of the input (`prompt_token_count`), the cached content (`cached_content_token_count`) and the output (`candidates_token_count`)141- The token count for the thinking process (`thoughts_token_count`)142- The total number of tokens in *both the input and the output* (`total_token_count`)143144To understand how big your next conversational turn will be, you need to append145it to the history when you call `count_tokens`.146147### Python148149    from google import genai150    from google.genai import types151152    client = genai.Client()153154    chat = client.chats.create(155        model="gemini-3.8-flash",156        history=[157            types.Content(158                role="user", parts=[types.Part(text="Hi my name is Bob")]159            ),160            types.Content(role="model", parts=[types.Part(text="Hi Bob!")]),161        ],162    )163164    print(165        client.models.count_tokens(166            model="gemini-3.8-flash", contents=chat.get_history()167        )168    )169170    response = chat.send_message(171        message="In one sentence, explain how a computer works to a young child."172    )173    print(response.usage_metadata)174175    extra = types.UserContent(176        parts=[177            types.Part(178                text="What is the meaning of life?",179            )180        ]181    )182    history = [*chat.get_history(), extra]183    print(client.models.count_tokens(model="gemini-3.8-flash", contents=history))184185### JavaScript186187    import { GoogleGenAI } from '@google/genai';188189    const ai = new GoogleGenAI({});190191    async function main() {192      const history = [193        { role: "user", parts: [{ text: "Hi my name is Bob" }] },194        { role: "model", parts: [{ text: "Hi Bob!" }] },195      ];196      const chat = ai.chats.create({197        model: "gemini-3.8-flash",198        history: history,199      });200201      const countTokensResponse = await ai.models.countTokens({202        model: "gemini-3.8-flash",203        contents: chat.getHistory(),204      });205      console.log(countTokensResponse.totalTokens);206207      const chatResponse = await chat.sendMessage({208        message: "In one sentence, explain how a computer works to a young child.",209      });210      console.log(chatResponse.usageMetadata);211212      const extraMessage = {213        role: "user",214        parts: [{ text: "What is the meaning of life?" }],215      };216      const combinedHistory = [...chat.getHistory(), extraMessage];217      const combinedCountTokensResponse = await ai.models.countTokens({218        model: "gemini-3.8-flash",219        contents: combinedHistory,220      });221      console.log(222        "Combined history token count:",223        combinedCountTokensResponse.totalTokens,224      );225    }226227    await main();228229### Go230231    ctx := context.Background()232    client, err := genai.NewClient(ctx, nil)233234    history := []*genai.Content{235      {Role: genai.RoleUser, Parts: []*genai.Part({Text: "Hi my name is Bob"})},236      {Role: genai.RoleModel, Parts: []*genai.Part({Text: "Hi Bob!"})},237    }238    chat, err := client.Chats.Create(ctx, "gemini-3.8-flash", nil, history)239    if err != nil {240      log.Fatal(err)241    }242243    firstTokenResp, err := client.Models.CountTokens(ctx, "gemini-3.8-flash", chat.History(false), nil)244    if err != nil {245      log.Fatal(err)246    }247    fmt.Println(firstTokenResp.TotalTokens)248249    resp, err := chat.SendMessage(ctx, genai.NewPartFromText("In one sentence, explain how a computer works to a young child."))250    if err != nil {251      log.Fatal(err)252    }253    fmt.Printf("%#v\n", resp.UsageMetadata)254255    extra := genai.NewContentFromText("What is the meaning of life?", genai.RoleUser)256    hist := chat.History(false)257    hist = append(hist, extra)258259    secondTokenResp, err := client.Models.CountTokens(ctx, "gemini-3.8-flash", hist, nil)260    if err != nil {261      log.Fatal(err)262    }263    fmt.Println(secondTokenResp.TotalTokens)264265### Count multimodal tokens266267All input to the Gemini API is tokenized, including text, image files, and other268non-text modalities. Note the following high-level key points about tokenization269of multimodal input during processing by the Gemini API:270271- Image inputs with both dimensions \<=384 pixels are counted as272  258 tokens. Images larger in one or both dimensions are cropped and scaled as273  needed into tiles of 768x768 pixels, each counted as 258 tokens.274275- Video and audio files are converted to tokens at the following fixed rates:276  video at 263 tokens per second and audio at 32 tokens per second. This rate277  applies to static processing (default). For agentic processing, token usage278  varies. See [Video token usage by processing mode](https://ai.google.dev/gemini-api/docs/generate-content/tokens#video-token-usage).279280#### Media resolutions281282[Gemini 3 models](https://ai.google.dev/gemini-api/docs/models#gemini-3) introduce granular control over283multimodal vision processing with the `media_resolution` parameter. The284`media_resolution` parameter determines the285**maximum number of tokens allocated per input image or video frame.**286Higher resolutions improve the model's ability to287read fine text or identify small details, but increase token usage and latency.288289For more details about the parameter and how it can impact token calculations,290see the [media resolution](https://ai.google.dev/gemini-api/docs/generate-content/media-resolution) guide.291292#### Image files293294If you call `count_tokens` with a text-and-image input, it returns the combined295token count of the text and the image in *the input only* (`total_tokens`). You296can make this call before calling `generate_content` to check the size of your297requests. You can also optionally call `count_tokens` on the text and the file298separately.299300Another option is calling `generate_content` and then using the `usage_metadata`301attribute on the `response` object to get the following:302303- The separate token counts of the input (`prompt_token_count`), the cached content (`cached_content_token_count`) and the output (`candidates_token_count`)304- The token count for the thinking process (`thoughts_token_count`)305- The total number of tokens in *both the input and the output* (`total_token_count`)306307Example that uses an uploaded image from the File API:308309### Python310311    from google import genai312313    client = genai.Client()314    prompt = "Tell me about this image"315    your_image_file = client.files.upload(file=media / "organ.jpg")316317    print(318        client.models.count_tokens(319            model="gemini-3.8-flash", contents=[prompt, your_image_file]320        )321    )322323    response = client.models.generate_content(324        model="gemini-3.8-flash", contents=[prompt, your_image_file]325    )326    print(response.usage_metadata)327328### JavaScript329330    import { GoogleGenAI } from '@google/genai';331332    const ai = new GoogleGenAI({});333    const prompt = "Tell me about this image";334335    async function main() {336      const organ = await ai.files.upload({337        file: path.join(media, "organ.jpg"),338        config: { mimeType: "image/jpeg" },339      });340341      const countTokensResponse = await ai.models.countTokens({342        model: "gemini-3.8-flash",343        contents: createUserContent([344          prompt,345          createPartFromUri(organ.uri, organ.mimeType),346        ]),347      });348      console.log(countTokensResponse.totalTokens);349350      const generateResponse = await ai.models.generateContent({351        model: "gemini-3.8-flash",352        contents: createUserContent([353          prompt,354          createPartFromUri(organ.uri, organ.mimeType),355        ]),356      });357      console.log(generateResponse.usageMetadata);358    }359360    await main();361362### Go363364    ctx := context.Background()365    client, err := genai.NewClient(ctx, nil)366367    file, err := client.Files.UploadFromPath(368      ctx, 369      filepath.Join(getMedia(), "organ.jpg"), 370      &genai.UploadFileConfig{371        MIMEType : "image/jpeg",372      },373    )374    if err != nil {375      log.Fatal(err)376    }377    parts := []*genai.Part{378      genai.NewPartFromText("Tell me about this image"),379      genai.NewPartFromURI(file.URI, file.MIMEType),380    }381    contents := []*genai.Content{382      genai.NewContentFromParts(parts, genai.RoleUser),383    }384385    tokenResp, err := client.Models.CountTokens(ctx, "gemini-3.8-flash", contents, nil)386    if err != nil {387      log.Fatal(err)388    }389    fmt.Println("Multimodal image token count:", tokenResp.TotalTokens)390391    response, err := client.Models.GenerateContent(ctx, "gemini-3.8-flash", contents, nil)392    if err != nil {393      log.Fatal(err)394    }395    usageMetadata, err := json.MarshalIndent(response.UsageMetadata, "", "  ")396    if err != nil {397      log.Fatal(err)398    }399    fmt.Println(string(usageMetadata))400401Example that provides the image as inline data:402403### Python404405    from google import genai406    import PIL.Image407408    client = genai.Client()409    prompt = "Tell me about this image"410    your_image_file = PIL.Image.open(media / "organ.jpg")411412    print(413        client.models.count_tokens(414            model="gemini-3.8-flash", contents=[prompt, your_image_file]415        )416    )417418    response = client.models.generate_content(419        model="gemini-3.8-flash", contents=[prompt, your_image_file]420    )421    print(response.usage_metadata)422423### JavaScript424425    import { GoogleGenAI } from '@google/genai';426427    const ai = new GoogleGenAI({});428    const prompt = "Tell me about this image";429    const imageBuffer = fs.readFileSync(path.join(media, "organ.jpg"));430431    const imageBase64 = imageBuffer.toString("base64");432433    const contents = createUserContent([434      prompt,435      createPartFromBase64(imageBase64, "image/jpeg"),436    ]);437438    async function main() {439      const countTokensResponse = await ai.models.countTokens({440        model: "gemini-3.8-flash",441        contents: contents,442      });443      console.log(countTokensResponse.totalTokens);444445      const generateResponse = await ai.models.generateContent({446        model: "gemini-3.8-flash",447        contents: contents,448      });449      console.log(generateResponse.usageMetadata);450    }451452    await main();453454### Go455456    ctx := context.Background()457    client, err := genai.NewClient(ctx, nil)458459    imageBytes, err := os.ReadFile("organ.jpg")460    if err != nil {461        log.Fatalf("Failed to read image file: %v", err)462    }463    parts := []*genai.Part{464      genai.NewPartFromText("Tell me about this image"),465      {466            InlineData: &genai.Blob{467                  MIMEType: "image/jpeg",468                  Data:     imageBytes,469            },470      },471    }472    contents := []*genai.Content{473      genai.NewContentFromParts(parts, genai.RoleUser),474    }475476    tokenResp, err := client.Models.CountTokens(ctx, "gemini-3.8-flash", contents, nil)477    if err != nil {478      log.Fatal(err)479    }480    fmt.Println("Multimodal image token count:", tokenResp.TotalTokens)481482    response, err := client.Models.GenerateContent(ctx, "gemini-3.8-flash", contents, nil)483    if err != nil {484      log.Fatal(err)485    }486    usageMetadata, err := json.MarshalIndent(response.UsageMetadata, "", "  ")487    if err != nil {488      log.Fatal(err)489    }490    fmt.Println(string(usageMetadata))491492#### Video or audio files493494Audio and video are each converted to tokens at the following fixed rates:495496- Video: 263 tokens per second497- Audio: 32 tokens per second498499If you call `count_tokens` with a text-and-video/audio input, it returns the500combined token count of the text and the video/audio file in *the input only*501(`total_tokens`). You can make this call before calling `generate_content` to502check the size of your requests. You can also optionally call `count_tokens` on503the text and the file separately.504505Another option is calling `generate_content` and then using the `usage_metadata`506attribute on the `response` object to get the following:507508- The separate token counts of the input (`prompt_token_count`), the cached content (`cached_content_token_count`) and the output (`candidates_token_count`)509- The token count for the thinking process (`thoughts_token_count`)510- The total number of tokens in *both the input and the output*511  (`total_token_count`).512513### Python514515    from google import genai516    import time517518    client = genai.Client()519    prompt = "Tell me about this video"520    your_file = client.files.upload(file=media / "Big_Buck_Bunny.mp4")521522    while not your_file.state or your_file.state.name != "ACTIVE":523        print("Processing video...")524        print("File state:", your_file.state)525        time.sleep(5)526        your_file = client.files.get(name=your_file.name)527528    print(529        client.models.count_tokens(530            model="gemini-3.8-flash", contents=[prompt, your_file]531        )532    )533534    response = client.models.generate_content(535        model="gemini-3.8-flash", contents=[prompt, your_file]536    )537    print(response.usage_metadata)538539### JavaScript540541    import { GoogleGenAI } from '@google/genai';542543    const ai = new GoogleGenAI({});544    const prompt = "Tell me about this video";545546    async function main() {547      let videoFile = await ai.files.upload({548        file: path.join(media, "Big_Buck_Bunny.mp4"),549        config: { mimeType: "video/mp4" },550      });551552      while (!videoFile.state || videoFile.state.toString() !== "ACTIVE") {553        console.log("Processing video...");554        console.log("File state: ", videoFile.state);555        await sleep(5000);556        videoFile = await ai.files.get({ name: videoFile.name });557      }558559      const countTokensResponse = await ai.models.countTokens({560        model: "gemini-3.8-flash",561        contents: createUserContent([562          prompt,563          createPartFromUri(videoFile.uri, videoFile.mimeType),564        ]),565      });566      console.log(countTokensResponse.totalTokens);567568      const generateResponse = await ai.models.generateContent({569        model: "gemini-3.8-flash",570        contents: createUserContent([571          prompt,572          createPartFromUri(videoFile.uri, videoFile.mimeType),573        ]),574      });575      console.log(generateResponse.usageMetadata);576    }577578    await main();579580### Go581582    ctx := context.Background()583    client, err := genai.NewClient(ctx, nil)584585    file, err := client.Files.UploadFromPath(586      ctx,587      filepath.Join(getMedia(), "Big_Buck_Bunny.mp4"),588      &genai.UploadFileConfig{589        MIMEType : "video/mp4",590      },591    )592    if err != nil {593      log.Fatal(err)594    }595596    for file.State == genai.FileStateUnspecified || file.State != genai.FileStateActive {597      fmt.Println("Processing video...")598      fmt.Println("File state:", file.State)599      time.Sleep(5 * time.Second)600601      file, err = client.Files.Get(ctx, file.Name, nil)602      if err != nil {603        log.Fatal(err)604      }605    }606607    parts := []*genai.Part{608      genai.NewPartFromText("Tell me about this video"),609      genai.NewPartFromURI(file.URI, file.MIMEType),610    }611    contents := []*genai.Content{612      genai.NewContentFromParts(parts, genai.RoleUser),613    }614615    tokenResp, err := client.Models.CountTokens(ctx, "gemini-3.8-flash", contents, nil)616    if err != nil {617      log.Fatal(err)618    }619    fmt.Println("Multimodal video/audio token count:", tokenResp.TotalTokens)620    response, err := client.Models.GenerateContent(ctx, "gemini-3.8-flash", contents, nil)621    if err != nil {622      log.Fatal(err)623    }624    usageMetadata, err := json.MarshalIndent(response.UsageMetadata, "", "  ")625    if err != nil {626      log.Fatal(err)627    }628    fmt.Println(string(usageMetadata))629630#### Video token usage by processing mode631632Token usage for video depends on the processing mode:633634| **Processing mode** | **Token calculation** | **Typical usage** |635|---|---|---|636| **Static** (default) | \~100 tokens/second by default (low resolution) or \~300 tokens/second (high resolution). All frames sampled at 1 FPS. | Predictable, proportional to video duration. |637| **Agentic** | Varies by content complexity. The model loads only the transcript and/or frames and/or audio needed to answer the prompt. | Up to 88% fewer tokens for long-form content. |638639With agentic processing, a 1-hour lecture that would use \~1.08M tokens in static mode might use \~108K tokens, depending on the prompt and content.640641To check actual token usage for a request, use the `usage_metadata` field in the response. In `UsageMetadata`, agentic video tokens are reported across the following fields:642643- **Initial prompt** (video reference + user prompt): `prompt_token_count`644- **Navigation thinking** : `thoughts_token_count`645- **Transcript, frames, and audio loaded on demand** : `tool_use_prompt_token_count`646- **Final answer** : `candidates_token_count`647648### Count thought tokens649650> [!NOTE]651> **Note:** The API provides **summaries** in both the [free and paid tiers](https://ai.google.dev/gemini-api/docs/pricing). **Thought signatures** increase the input token count (and your cost) when you send them back in subsequent conversational turns.652653When you turn on thinking, response pricing is the sum of output tokens and thinking tokens. You can retrieve the total number of generated thinking tokens from the `thoughtsTokenCount` field (or SDK equivalent).654655### Python656657    # ...658    print("Thoughts tokens:", response.usage_metadata.thoughts_token_count)659    print("Output tokens:", response.usage_metadata.candidates_token_count)660661### JavaScript662663    // ...664    console.log(`Thoughts tokens: ${response.usageMetadata.thoughtsTokenCount}`);665    console.log(`Output tokens: ${response.usageMetadata.candidatesTokenCount}`);666667### Go668669    // ...670    fmt.Println("Thoughts tokens:", response.UsageMetadata.ThoughtsTokenCount)671    fmt.Println("Output tokens:", response.UsageMetadata.CandidatesTokenCount)672673Thinking models generate full thoughts to improve the quality of the final response, and then output [summaries](https://ai.google.dev/gemini-api/docs/thinking#summaries) to provide insight into the thought process. So, the API bases pricing on the full thought tokens the model generates to create a summary, even though the API only outputs the summary.674675You can learn more about how to configure thinking in the [Gemini thinking](https://ai.google.dev/gemini-api/docs/thinking) guide.676677## Context windows678679The models available through the Gemini API have context windows that are680measured in tokens. The context window defines how much input you can provide681and how much output the model can generate. You can determine the size of the682context window by calling the [`models.get` endpoint](https://ai.google.dev/api/rest/v1/models/get)683or by looking in the [models documentation](https://ai.google.dev/gemini-api/docs/models).684685### Python686687    from google import genai688689    client = genai.Client()690    model_info = client.models.get(model="gemini-3.8-flash")691    print(f"{model_info.input_token_limit=}")692    print(f"{model_info.output_token_limit=}")693694### JavaScript695696    import { GoogleGenAI } from '@google/genai';697698    const ai = new GoogleGenAI({});699700    async function main() {701      const modelInfo = await ai.models.get({model: 'gemini-3.8-flash'});702      console.log(modelInfo.inputTokenLimit);703      console.log(modelInfo.outputTokenLimit);704    }705706    await main();707708### Go709710    ctx := context.Background()711    client, err := genai.NewClient(ctx, nil)712    if err != nil {713      log.Fatal(err)714    }715    modelInfo, err := client.ModelInfo(ctx, "models/gemini-3.8-flash")716    if err != nil {717      log.Fatal(err)718    }719    fmt.Println("input token limit:", modelInfo.InputTokenLimit)720    fmt.Println("output token limit:", modelInfo.OutputTokenLimit)
Files main
Menu

Theme