Skip to main content
Lesson 10 of 12 · Grok Vision: Understanding Images

Optimize image tokens

Lesson 10 of 12 Updated July 30, 2026 Beginner
On this page
  1. Control your costs in production
  2. Strategy 1: Choose the right level of detail
  3. Strategy 2: Resize before sending
  4. Strategy 3: Two-pass pipeline
  5. Strategy 4: Caching
  6. Monitor and alert
  7. Key takeaways

Control your costs in production

In production, image tokens can make up a significant portion of your API bill. A single image in high mode consumes up to 1,792 tokens—equivalent to several paragraphs of text. Multiply that by hundreds or thousands of daily requests, and optimization becomes a necessity.

Strategy 1: Choose the right level of detail

The detail parameter is your primary optimization lever. The most common mistake is using high by default when low or auto suffice in most cases.

Decision matrix

Task Recommended detail Estimated tokens
Image classification low ~256
General description auto ~512-768
Alt text / accessibility low ~256
Content moderation auto ~512-768
OCR / text extraction high ~1024-1792
Chart analysis high ~1024-1792
Defect detection high ~1024-1792

Strategy 2: Resize before sending

High-resolution images (4K, 8K) are rarely necessary for AI analysis. Consistently resizing your images before sending them reduces tokens without perceptible impact on analysis quality.

from PIL import Image
import io
import base64

class OptimiseurImage:
    TAILLES_PAR_TACHE = {
        "classification": (512, 512),
        "description": (1024, 1024),
        "ocr": (2048, 2048),
        "comparison": (800, 800),
    }

    @staticmethod
    def optimiser(chemin, tache="description", qualite=85):
        taille_max = OptimiseurImage.TAILLES_PAR_TACHE.get(
            tache, (1024, 1024)
        )

        img = Image.open(chemin)

        # Do not enlarge small images
        if img.width <= taille_max[0] and img.height <= taille_max[1]:
            pass
        else:
            img.thumbnail(taille_max)

        # Convert to JPEG to reduce size
        if img.mode in ("RGBA", "P"):
            img = img.convert("RGB")

        buffer = io.BytesIO()
        img.save(buffer, "JPEG", quality=qualite)
        buffer.seek(0)

        encoded = base64.standard_b64encode(buffer.read()).decode()
        return f"data:image/jpeg;base64,{encoded}"

Strategy 3: Two-pass pipeline

For high volumes, use a two-pass pipeline—a fast first pass in low to sort, then a second pass in high only for images that require it:

def pipeline_deux_passes(images):
    # Pass 1: fast classification (low)
    classifications = []
    for img in images:
        response = client.responses.create(
            model="grok-4.5",
            input=[
                {"type": "input_image", "image_url": img, "detail": "low"},
                {"type": "input_text", "text": "Classify: document, photo, chart, other. One word."}
            ],
            store=False
        )
        classifications.append({
            "url": img,
            "type": response.output_text.strip().lower()
        })

    # Pass 2: detailed analysis (high) only if necessary
    resultats = []
    for item in classifications:
        if item["type"] in ("document", "chart"):
            detail = "high"
        else:
            detail = "auto"

        response = client.responses.create(
            model="grok-4.5",
            input=[
                {"type": "input_image", "image_url": item["url"], "detail": detail},
                {"type": "input_text", "text": "Detailed analysis of this image."}
            ],
            store=False
        )
        resultats.append(response.output_text)

    return resultats

Strategy 4: Caching

If you analyze the same images multiple times (tests, development, demo), cache the results:

import hashlib
import json

cache = {}

def vision_avec_cache(image_url, prompt, detail="auto"):
    # Create a unique key
    cle = hashlib.sha256(
        f"{image_url}:{prompt}:{detail}".encode()
    ).hexdigest()

    if cle in cache:
        return cache[cle]

    response = client.responses.create(
        model="grok-4.5",
        input=[
            {"type": "input_image", "image_url": image_url, "detail": detail},
            {"type": "input_text", "text": prompt}
        ],
        store=False
    )

    cache[cle] = response.output_text
    return response.output_text

Monitor and alert

Set up cost tracking to detect overruns:

def monitorer_tokens(response, seuil_alerte=5000):
    usage = response.usage
    image_tokens = usage.prompt_tokens_details.image_tokens

    if image_tokens > seuil_alerte:
        print(f"ALERT: {image_tokens} image tokens (threshold: {seuil_alerte})")

    return {
        "image_tokens": image_tokens,
        "text_tokens": usage.prompt_tokens_details.text_tokens,
        "total": usage.total_tokens
    }

Key takeaways

  • Choose the detail level suited to the task—low when sufficient
  • Resize images before sending to reduce consumption
  • Use a two-pass pipeline for high volumes
  • Cache results to avoid redundant calls
  • Monitor image tokens in production to anticipate costs