# Source: https://docs.claude.com/en/docs/build-with-claude/token-counting.md

# Token counting

Token counting enables you to determine the number of tokens in a message before sending it to Claude, helping you make informed decisions about your prompts and usage. With token counting, you can

* Proactively manage rate limits and costs
* Make smart model routing decisions
* Optimize prompts to be a specific length

***

## How to count message tokens

The [token counting](/en/api/messages-count-tokens) endpoint accepts the same structured list of inputs for creating a message, including support for system prompts, [tools](/en/docs/agents-and-tools/tool-use/overview), [images](/en/docs/build-with-claude/vision), and [PDFs](/en/docs/build-with-claude/pdf-support). The response contains the total number of input tokens.

<Note>
  The token count should be considered an **estimate**. In some cases, the actual number of input tokens used when creating a message may differ by a small amount.

  Token counts may include tokens added automatically by Anthropic for system optimizations. **You are not billed for system-added tokens**. Billing reflects only your content.
</Note>

### Supported models

All [active models](/en/docs/about-claude/models/overview) support token counting.

### Count tokens in basic messages

<CodeGroup>
  ```python Python theme={null}
  import anthropic

  client = anthropic.Anthropic()

  response = client.messages.count_tokens(
      model="claude-sonnet-4-5",
      system="You are a scientist",
      messages=[{
          "role": "user",
          "content": "Hello, Claude"
      }],
  )

  print(response.json())
  ```

  ```typescript TypeScript theme={null}
  import Anthropic from '@anthropic-ai/sdk';

  const client = new Anthropic();

  const response = await client.messages.countTokens({
    model: 'claude-sonnet-4-5',
    system: 'You are a scientist',
    messages: [{
      role: 'user',
      content: 'Hello, Claude'
    }]
  });

  console.log(response);
  ```

  ```bash Shell theme={null}
  curl https://api.anthropic.com/v1/messages/count_tokens \
      --header "x-api-key: $ANTHROPIC_API_KEY" \
      --header "content-type: application/json" \
      --header "anthropic-version: 2023-06-01" \
      --data '{
        "model": "claude-sonnet-4-5",
        "system": "You are a scientist",
        "messages": [{
          "role": "user",
          "content": "Hello, Claude"
        }]
      }'
  ```

  ```java Java theme={null}
  import com.anthropic.client.AnthropicClient;
  import com.anthropic.client.okhttp.AnthropicOkHttpClient;
  import com.anthropic.models.messages.MessageCountTokensParams;
  import com.anthropic.models.messages.MessageTokensCount;
  import com.anthropic.models.messages.Model;

  public class CountTokensExample {

      public static void main(String[] args) {
          AnthropicClient client = AnthropicOkHttpClient.fromEnv();

          MessageCountTokensParams params = MessageCountTokensParams.builder()
                  .model(Model.CLAUDE_SONNET_4_20250514)
                  .system("You are a scientist")
                  .addUserMessage("Hello, Claude")
                  .build();

          MessageTokensCount count = client.messages().countTokens(params);
          System.out.println(count);
      }
  }
  ```
</CodeGroup>

```JSON JSON theme={null}
{ "input_tokens": 14 }
```

### Count tokens in messages with tools

<Note>
  [Server tool](/en/docs/agents-and-tools/tool-use/overview#server-tools) token counts only apply to the first sampling call.
</Note>

<CodeGroup>
  ```python Python theme={null}
  import anthropic

  client = anthropic.Anthropic()

  response = client.messages.count_tokens(
      model="claude-sonnet-4-5",
      tools=[
          {
              "name": "get_weather",
              "description": "Get the current weather in a given location",
              "input_schema": {
                  "type": "object",
                  "properties": {
                      "location": {
                          "type": "string",
                          "description": "The city and state, e.g. San Francisco, CA",
                      }
                  },
                  "required": ["location"],
              },
          }
      ],
      messages=[{"role": "user", "content": "What's the weather like in San Francisco?"}]
  )

  print(response.json())
  ```

  ```typescript TypeScript theme={null}
  import Anthropic from '@anthropic-ai/sdk';

  const client = new Anthropic();

  const response = await client.messages.countTokens({
    model: 'claude-sonnet-4-5',
    tools: [
      {
        name: "get_weather",
        description: "Get the current weather in a given location",
        input_schema: {
          type: "object",
          properties: {
            location: {
              type: "string",
              description: "The city and state, e.g. San Francisco, CA",
            }
          },
          required: ["location"],
        }
      }
    ],
    messages: [{ role: "user", content: "What's the weather like in San Francisco?" }]
  });

  console.log(response);
  ```

  ```bash Shell theme={null}
  curl https://api.anthropic.com/v1/messages/count_tokens \
      --header "x-api-key: $ANTHROPIC_API_KEY" \
      --header "content-type: application/json" \
      --header "anthropic-version: 2023-06-01" \
      --data '{
        "model": "claude-sonnet-4-5",
        "tools": [
          {
            "name": "get_weather",
            "description": "Get the current weather in a given location",
            "input_schema": {
              "type": "object",
              "properties": {
                "location": {
                  "type": "string",
                  "description": "The city and state, e.g. San Francisco, CA"
                }
              },
              "required": ["location"]
            }
          }
        ],
        "messages": [
          {
            "role": "user",
            "content": "What'\''s the weather like in San Francisco?"
          }
        ]
      }'
  ```

  ```java Java theme={null}
  import java.util.List;
  import java.util.Map;

  import com.anthropic.client.AnthropicClient;
  import com.anthropic.client.okhttp.AnthropicOkHttpClient;
  import com.anthropic.core.JsonValue;
  import com.anthropic.models.messages.MessageCountTokensParams;
  import com.anthropic.models.messages.MessageTokensCount;
  import com.anthropic.models.messages.Model;
  import com.anthropic.models.messages.Tool;
  import com.anthropic.models.messages.Tool.InputSchema;

  public class CountTokensWithToolsExample {

      public static void main(String[] args) {
          AnthropicClient client = AnthropicOkHttpClient.fromEnv();

          InputSchema schema = InputSchema.builder()
                  .properties(JsonValue.from(Map.of(
                          "location", Map.of(
                                  "type", "string",
                                  "description", "The city and state, e.g. San Francisco, CA"
                          )
                  )))
                  .putAdditionalProperty("required", JsonValue.from(List.of("location")))
                  .build();

          MessageCountTokensParams params = MessageCountTokensParams.builder()
                  .model(Model.CLAUDE_SONNET_4_20250514)
                  .addTool(Tool.builder()
                          .name("get_weather")
                          .description("Get the current weather in a given location")
                          .inputSchema(schema)
                          .build())
                  .addUserMessage("What's the weather like in San Francisco?")
                  .build();

          MessageTokensCount count = client.messages().countTokens(params);
          System.out.println(count);
      }
  }
  ```
</CodeGroup>

```JSON JSON theme={null}
{ "input_tokens": 403 }
```

### Count tokens in messages with images

<CodeGroup>
  ```bash Shell theme={null}
  #!/bin/sh

  IMAGE_URL="https://upload.wikimedia.org/wikipedia/commons/a/a7/Camponotus_flavomarginatus_ant.jpg"
  IMAGE_MEDIA_TYPE="image/jpeg"
  IMAGE_BASE64=$(curl "$IMAGE_URL" | base64)

  curl https://api.anthropic.com/v1/messages/count_tokens \
       --header "x-api-key: $ANTHROPIC_API_KEY" \
       --header "anthropic-version: 2023-06-01" \
       --header "content-type: application/json" \
       --data \
  '{
      "model": "claude-sonnet-4-5",
      "messages": [
          {"role": "user", "content": [
              {"type": "image", "source": {
                  "type": "base64",
                  "media_type": "'$IMAGE_MEDIA_TYPE'",
                  "data": "'$IMAGE_BASE64'"
              }},
              {"type": "text", "text": "Describe this image"}
          ]}
      ]
  }'
  ```

  ```Python Python theme={null}
  import anthropic
  import base64
  import httpx

  image_url = "https://upload.wikimedia.org/wikipedia/commons/a/a7/Camponotus_flavomarginatus_ant.jpg"
  image_media_type = "image/jpeg"
  image_data = base64.standard_b64encode(httpx.get(image_url).content).decode("utf-8")

  client = anthropic.Anthropic()

  response = client.messages.count_tokens(
      model="claude-sonnet-4-5",
      messages=[
          {
              "role": "user",
              "content": [
                  {
                      "type": "image",
                      "source": {
                          "type": "base64",
                          "media_type": image_media_type,
                          "data": image_data,
                      },
                  },
                  {
                      "type": "text",
                      "text": "Describe this image"
                  }
              ],
          }
      ],
  )
  print(response.json())
  ```

  ```Typescript TypeScript theme={null}
  import Anthropic from '@anthropic-ai/sdk';

  const anthropic = new Anthropic();

  const image_url = "https://upload.wikimedia.org/wikipedia/commons/a/a7/Camponotus_flavomarginatus_ant.jpg"
  const image_media_type = "image/jpeg"
  const image_array_buffer = await ((await fetch(image_url)).arrayBuffer());
  const image_data = Buffer.from(image_array_buffer).toString('base64');

  const response = await anthropic.messages.countTokens({
    model: 'claude-sonnet-4-5',
    messages: [
      {
        "role": "user",
        "content": [
          {
            "type": "image",
            "source": {
              "type": "base64",
              "media_type": image_media_type,
              "data": image_data,
            },
          }
        ],
      },
      {
        "type": "text",
        "text": "Describe this image"
      }
    ]
  });
  console.log(response);
  ```

  ```java Java theme={null}
  import java.util.Base64;
  import java.util.List;

  import com.anthropic.client.AnthropicClient;
  import com.anthropic.client.okhttp.AnthropicOkHttpClient;
  import com.anthropic.models.messages.Base64ImageSource;
  import com.anthropic.models.messages.ContentBlockParam;
  import com.anthropic.models.messages.ImageBlockParam;
  import com.anthropic.models.messages.MessageCountTokensParams;
  import com.anthropic.models.messages.MessageTokensCount;
  import com.anthropic.models.messages.Model;
  import com.anthropic.models.messages.TextBlockParam;

  import java.net.URI;
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;

  public class CountTokensImageExample {

      public static void main(String[] args) throws Exception {
          AnthropicClient client = AnthropicOkHttpClient.fromEnv();

          String imageUrl = "https://upload.wikimedia.org/wikipedia/commons/a/a7/Camponotus_flavomarginatus_ant.jpg";
          String imageMediaType = "image/jpeg";

          HttpClient httpClient = HttpClient.newHttpClient();
          HttpRequest request = HttpRequest.newBuilder()
                  .uri(URI.create(imageUrl))
                  .build();
          byte[] imageBytes = httpClient.send(request, HttpResponse.BodyHandlers.ofByteArray()).body();
          String imageBase64 = Base64.getEncoder().encodeToString(imageBytes);

          ContentBlockParam imageBlock = ContentBlockParam.ofImage(
                  ImageBlockParam.builder()
                          .source(Base64ImageSource.builder()
                                  .mediaType(Base64ImageSource.MediaType.IMAGE_JPEG)
                                  .data(imageBase64)
                                  .build())
                          .build());

          ContentBlockParam textBlock = ContentBlockParam.ofText(
                  TextBlockParam.builder()
                          .text("Describe this image")
                          .build());

          MessageCountTokensParams params = MessageCountTokensParams.builder()
                  .model(Model.CLAUDE_SONNET_4_20250514)
                  .addUserMessageOfBlockParams(List.of(imageBlock, textBlock))
                  .build();

          MessageTokensCount count = client.messages().countTokens(params);
          System.out.println(count);
      }
  }
  ```
</CodeGroup>

```JSON JSON theme={null}
{ "input_tokens": 1551 }
```

### Count tokens in messages with extended thinking

<Note>
  See [here](/en/docs/build-with-claude/extended-thinking#how-context-window-is-calculated-with-extended-thinking) for more details about how the context window is calculated with extended thinking

  * Thinking blocks from **previous** assistant turns are ignored and **do not** count toward your input tokens
  * **Current** assistant turn thinking **does** count toward your input tokens
</Note>

<CodeGroup>
  ```bash Shell theme={null}
  curl https://api.anthropic.com/v1/messages/count_tokens \
      --header "x-api-key: $ANTHROPIC_API_KEY" \
      --header "content-type: application/json" \
      --header "anthropic-version: 2023-06-01" \
      --data '{
        "model": "claude-sonnet-4-5",
        "thinking": {
          "type": "enabled",
          "budget_tokens": 16000
        },
        "messages": [
          {
            "role": "user",
            "content": "Are there an infinite number of prime numbers such that n mod 4 == 3?"
          },
          {
            "role": "assistant",
            "content": [
              {
                "type": "thinking",
                "thinking": "This is a nice number theory question. Lets think about it step by step...",
                "signature": "EuYBCkQYAiJAgCs1le6/Pol5Z4/JMomVOouGrWdhYNsH3ukzUECbB6iWrSQtsQuRHJID6lWV..."
              },
              {
                "type": "text",
                "text": "Yes, there are infinitely many prime numbers p such that p mod 4 = 3..."
              }
            ]
          },
          {
            "role": "user",
            "content": "Can you write a formal proof?"
          }
        ]
      }'
  ```

  ```Python Python theme={null}
  import anthropic

  client = anthropic.Anthropic()

  response = client.messages.count_tokens(
      model="claude-sonnet-4-5",
      thinking={
          "type": "enabled",
          "budget_tokens": 16000
      },
      messages=[
          {
              "role": "user",
              "content": "Are there an infinite number of prime numbers such that n mod 4 == 3?"
          },
          {
              "role": "assistant",
              "content": [
                  {
                      "type": "thinking",
                      "thinking": "This is a nice number theory question. Let's think about it step by step...",
                      "signature": "EuYBCkQYAiJAgCs1le6/Pol5Z4/JMomVOouGrWdhYNsH3ukzUECbB6iWrSQtsQuRHJID6lWV..."
                  },
                  {
                    "type": "text",
                    "text": "Yes, there are infinitely many prime numbers p such that p mod 4 = 3..."
                  }
              ]
          },
          {
              "role": "user",
              "content": "Can you write a formal proof?"
          }
      ]
  )

  print(response.json())
  ```

  ```typescript TypeScript theme={null}
  import Anthropic from '@anthropic-ai/sdk';

  const client = new Anthropic();

  const response = await client.messages.countTokens({
    model: 'claude-sonnet-4-5',
    thinking: {
      'type': 'enabled',
      'budget_tokens': 16000
    },
    messages: [
      {
        'role': 'user',
        'content': 'Are there an infinite number of prime numbers such that n mod 4 == 3?'
      },
      {
        'role': 'assistant',
        'content': [
          {
            'type': 'thinking',
            'thinking': "This is a nice number theory question. Let's think about it step by step...",
            'signature': 'EuYBCkQYAiJAgCs1le6/Pol5Z4/JMomVOouGrWdhYNsH3ukzUECbB6iWrSQtsQuRHJID6lWV...'
          },
          {
            'type': 'text',
            'text': 'Yes, there are infinitely many prime numbers p such that p mod 4 = 3...',
          }
        ]
      },
      {
        'role': 'user',
        'content': 'Can you write a formal proof?'
      }
    ]
  });

  console.log(response);
  ```

  ```java Java theme={null}
  import java.util.List;

  import com.anthropic.client.AnthropicClient;
  import com.anthropic.client.okhttp.AnthropicOkHttpClient;
  import com.anthropic.models.messages.ContentBlockParam;
  import com.anthropic.models.messages.MessageCountTokensParams;
  import com.anthropic.models.messages.MessageTokensCount;
  import com.anthropic.models.messages.Model;
  import com.anthropic.models.messages.TextBlockParam;
  import com.anthropic.models.messages.ThinkingBlockParam;

  public class CountTokensThinkingExample {

      public static void main(String[] args) {
          AnthropicClient client = AnthropicOkHttpClient.fromEnv();

          List<ContentBlockParam> assistantBlocks = List.of(
                  ContentBlockParam.ofThinking(ThinkingBlockParam.builder()
                          .thinking("This is a nice number theory question. Let's think about it step by step...")
                          .signature("EuYBCkQYAiJAgCs1le6/Pol5Z4/JMomVOouGrWdhYNsH3ukzUECbB6iWrSQtsQuRHJID6lWV...")
                          .build()),
                  ContentBlockParam.ofText(TextBlockParam.builder()
                          .text("Yes, there are infinitely many prime numbers p such that p mod 4 = 3...")
                          .build())
          );

          MessageCountTokensParams params = MessageCountTokensParams.builder()
                  .model(Model.CLAUDE_SONNET_4_20250514)
                  .enabledThinking(16000)
                  .addUserMessage("Are there an infinite number of prime numbers such that n mod 4 == 3?")
                  .addAssistantMessageOfBlockParams(assistantBlocks)
                  .addUserMessage("Can you write a formal proof?")
                  .build();

          MessageTokensCount count = client.messages().countTokens(params);
          System.out.println(count);
      }
  }
  ```
</CodeGroup>

```JSON JSON theme={null}
{ "input_tokens": 88 }
```

### Count tokens in messages with PDFs

<Note>
  Token counting supports PDFs with the same [limitations](/en/docs/build-with-claude/pdf-support#pdf-support-limitations) as the Messages API.
</Note>

<CodeGroup>
  ```bash Shell theme={null}
  curl https://api.anthropic.com/v1/messages/count_tokens \
      --header "x-api-key: $ANTHROPIC_API_KEY" \
      --header "content-type: application/json" \
      --header "anthropic-version: 2023-06-01" \
      --data '{
        "model": "claude-sonnet-4-5",
        "messages": [{
          "role": "user",
          "content": [
            {
              "type": "document",
              "source": {
                "type": "base64",
                "media_type": "application/pdf",
                "data": "'$(base64 -i document.pdf)'"
              }
            },
            {
              "type": "text",
              "text": "Please summarize this document."
            }
          ]
        }]
      }'
  ```

  ```Python Python theme={null}
  import base64
  import anthropic

  client = anthropic.Anthropic()

  with open("document.pdf", "rb") as pdf_file:
      pdf_base64 = base64.standard_b64encode(pdf_file.read()).decode("utf-8")

  response = client.messages.count_tokens(
      model="claude-sonnet-4-5",
      messages=[{
          "role": "user",
          "content": [
              {
                  "type": "document",
                  "source": {
                      "type": "base64",
                      "media_type": "application/pdf",
                      "data": pdf_base64
                  }
              },
              {
                  "type": "text",
                  "text": "Please summarize this document."
              }
          ]
      }]
  )

  print(response.json())
  ```

  ```Typescript TypeScript theme={null}
  import Anthropic from '@anthropic-ai/sdk';
  import { readFileSync } from 'fs';

  const client = new Anthropic();

  const pdfBase64 = readFileSync('document.pdf', { encoding: 'base64' });

  const response = await client.messages.countTokens({
    model: 'claude-sonnet-4-5',
    messages: [{
      role: 'user',
      content: [
        {
          type: 'document',
          source: {
            type: 'base64',
            media_type: 'application/pdf',
            data: pdfBase64
          }
        },
        {
          type: 'text',
          text: 'Please summarize this document.'
        }
      ]
    }]
  });

  console.log(response);
  ```

  ```java Java theme={null}
  import java.nio.file.Files;
  import java.nio.file.Path;
  import java.util.Base64;
  import java.util.List;

  import com.anthropic.client.AnthropicClient;
  import com.anthropic.client.okhttp.AnthropicOkHttpClient;
  import com.anthropic.models.messages.Base64PdfSource;
  import com.anthropic.models.messages.ContentBlockParam;
  import com.anthropic.models.messages.DocumentBlockParam;
  import com.anthropic.models.messages.MessageCountTokensParams;
  import com.anthropic.models.messages.MessageTokensCount;
  import com.anthropic.models.messages.Model;
  import com.anthropic.models.messages.TextBlockParam;

  public class CountTokensPdfExample {

      public static void main(String[] args) throws Exception {
          AnthropicClient client = AnthropicOkHttpClient.fromEnv();

          byte[] fileBytes = Files.readAllBytes(Path.of("document.pdf"));
          String pdfBase64 = Base64.getEncoder().encodeToString(fileBytes);

          ContentBlockParam documentBlock = ContentBlockParam.ofDocument(
                  DocumentBlockParam.builder()
                          .source(Base64PdfSource.builder()
                                  .mediaType(Base64PdfSource.MediaType.APPLICATION_PDF)
                                  .data(pdfBase64)
                                  .build())
                          .build());

          ContentBlockParam textBlock = ContentBlockParam.ofText(
                  TextBlockParam.builder()
                          .text("Please summarize this document.")
                          .build());

          MessageCountTokensParams params = MessageCountTokensParams.builder()
                  .model(Model.CLAUDE_SONNET_4_20250514)
                  .addUserMessageOfBlockParams(List.of(documentBlock, textBlock))
                  .build();

          MessageTokensCount count = client.messages().countTokens(params);
          System.out.println(count);
      }
  }
  ```
</CodeGroup>

```JSON JSON theme={null}
{ "input_tokens": 2188 }
```

***

## Pricing and rate limits

Token counting is **free to use** but subject to requests per minute rate limits based on your [usage tier](/en/api/rate-limits#rate-limits). If you need higher limits, contact sales through the [Claude Console](https://console.anthropic.com/settings/limits).

| Usage tier | Requests per minute (RPM) |
| ---------- | ------------------------- |
| 1          | 100                       |
| 2          | 2,000                     |
| 3          | 4,000                     |
| 4          | 8,000                     |

<Note>
  Token counting and message creation have separate and independent rate limits -- usage of one does not count against the limits of the other.
</Note>

***

## FAQ

<AccordionGroup>
  <Accordion title="Does token counting use prompt caching?">
    No, token counting provides an estimate without using caching logic. While you may provide `cache_control` blocks in your token counting request, prompt caching only occurs during actual message creation.
  </Accordion>
</AccordionGroup>