CloudBrum
CloudBrum · Cloud decision-support platform
Google Cloud AI and machine learning

Cloud Vision API (Vision AI)Last reviewedReading time~12 minLevelBeginner to advanced

Google Cloud · AI and machine learning · Image analysis API

The Cloud Vision API is Google’s pre-trained image analyser: you POST a picture, or a gs:// address, name the features you want, and get labels, objects, text, SafeSearch ratings and more back as JSON. It bills one unit for every feature on every image, and the first 1,000 units of each feature each month cost nothing. It reads pictures well and can detect faces, but it does not identify who anyone is. For a written description of a picture, or an answer to a question about it, Google points you to Gemini instead.

On this page (17 sections)

    Mind map: Cloud Vision API at a glance

    Cloud Vision API mind map Cloud Vision API at a glance: Understand: Labels, Objects, Image properties; Read: Text detection, Document text, Handwriting; Safety: SafeSearch, Likelihood levels, Review queue; Places and brands: Landmarks, Logos, Web detection; People: Face detection, No identification, Crop hints; Batch work: 16 images a call, PDF and TIFF jobs, JSON in Cloud Storage; Security: Service accounts, Bucket permissions, Restricted API keys; Pricing: Per feature unit, 1,000 free a month, Volume tiers. Cloud Vision API at a glance Image analysis on Google Cloud: the main building blocks and decisions CloudBrum Cloud decision-support platform CloudBrum Labels Objects Image properties Understand Text detection Document text Handwriting Read SafeSearch Likelihood levels Review queue Safety Landmarks Logos Web detection Places and brands Face detection No identification Crop hints People 16 images a call PDF and TIFF jobs JSON in Cloud Storage Batch work Service accounts Bucket permissions Restricted API keys Security Per feature unit 1,000 free a month Volume tiers Pricing Vision API17-point analysis CloudBrum· 17-point cloud service analysis cloudbrum.com
    CloudBrum Vision API at a glance · 17-point analysis Understand Labels Objects Image properties Read Text detection Document text Handwriting Safety SafeSearch Likelihood levels Review queue Places and brands Landmarks Logos Web detection People Face detection No identification Crop hints Batch work 16 images a call PDF and TIFF jobs JSON in Cloud Storage Security Service accounts Bucket permissions Restricted API keys Pricing Per feature unit 1,000 free a month Volume tiers CloudBrum · cloudbrum.com

    Free to share. The downloaded image includes the CloudBrum link.

    Key features (summary)

    • Label detectionBroad categories for the whole picture, such as "Street", "Bicycle" or "Wedding", each with a score between 0 and 1. A starting point for search and tagging.
    • Object localizationFinds individual objects and gives each a name, a score and a normalised bounding box, so you can draw it or crop to it.
    • Text and document text detectionTEXT_DETECTION reads sparse text such as signs and labels. DOCUMENT_TEXT_DETECTION is built for dense pages and handwriting and returns pages, blocks, paragraphs, words and symbols.
    • SafeSearchRates a picture for adult, violent, racy, medical and spoof content on a five-step scale from VERY_UNLIKELY to VERY_LIKELY. You choose where the lines go.
    • Landmarks, logos and web detectionNames well-known places and brands, and finds the same or similar pictures on the web with the pages that use them. Useful for rights checks and reverse image search.
    • Face detectionLocates faces and returns landmarks, angles and likelihoods for expressions and headwear. It does not say whose face it is, and there is no face collection.
    • Image properties and crop hintsDominant colours for design and filtering, and suggested crops for the aspect ratios you give.
    • Batch and asynchronous jobsUp to 16 images go in one request. PDFs, TIFFs and big image sets are processed as offline jobs that write JSON files to a Cloud Storage bucket.

    Basic concepts

    images:annotate
    The main REST method. A request holds up to 16 image requests, each with an image and a list of features.
    Feature
    One kind of analysis, such as LABEL_DETECTION. You can list several for one image, and each is billed.
    Unit
    The billing count. One feature applied to one image is one unit. Two features on one picture are two.
    Image source
    Either the bytes of the picture (base64 in JSON) or a gs:// or public URL for the API to fetch.
    Likelihood
    SafeSearch and face answers come as UNKNOWN, VERY_UNLIKELY, UNLIKELY, POSSIBLE, LIKELY or VERY_LIKELY, not as a number.
    Normalised vertices
    Bounding boxes given as fractions of the width and height, so they are independent of the resolution.
    TEXT_DETECTION
    OCR tuned for a little text inside a bigger scene.
    DOCUMENT_TEXT_DETECTION
    OCR tuned for dense text and handwriting, with the page structure kept.
    Web detection
    A feature that finds web entities, matching pages and visually similar images for a picture.
    Product Search
    A separate part of the API that matches a photo against a catalogue of reference images you upload.
    Asynchronous batch
    Offline jobs (files:asyncBatchAnnotate for PDF and TIFF files of up to 2,000 pages) that read from and write to Cloud Storage and return an operation to poll. API keys are not accepted for this method, so use a service account.
    Application Default Credentials
    The way Google client libraries find credentials: the attached service account on Google Cloud, or your gcloud login on a laptop.
    Service account
    A non-human identity the application runs as. It needs read access to the bucket and the right to use the project’s APIs.
    API key
    A simple credential that can be restricted to the Vision API. Convenient, but a service account is the safer default.
    Document AI
    Google’s service for forms, invoices and other structured documents. Use it where OCR is only the first step.

    How to create & configure it

    Enable the Vision API and screen pictures in a bucket with the gcloud CLI

    1. Decide what you want backLabels, text, a safety rating, or a sentence? The first three are Vision. A sentence or an answer about the picture is a job for Gemini, and a structured invoice is a job for Document AI.
    2. Create a project and set a budgetUse a project of its own so usage and cost are easy to read. Add a budget alert before the first call, because every feature on every image is billed after the free units.
    3. Enable the APIRun gcloud services enable vision.googleapis.com. You need the Service Usage Admin role or an owner of the project to do it.
    4. Create a service account for the applicationGive it read access to the one bucket that holds the pictures. Don’t download a key file. On Cloud Run, Cloud Functions or GKE, attach the service account and let Application Default Credentials find it.
    5. Try each feature from the command linegcloud ml vision detect-labels, detect-text, detect-safe-search and the others take a local file or a gs:// address. Run them on your own pictures.
    6. Pick thresholds from a sampleDecide which SafeSearch levels reject, which go to a person and which pass. Choose a minimum label score. Note the date, since models change.
    7. Batch and count unitsSend up to 16 images per call and compute the units before a big run: images times features.
    8. Run PDFs and TIFFs as jobsUse the asynchronous batch method with an output bucket, then read the JSON files. Poll the operation instead of holding a connection.
    9. Watch quota, errors and spendLook at the API dashboard for the request rate and errors, keep an alert on the budget, and re-run your sample every few months.

    Tip: a response can hold a good answer for one image and an error for another in the same batch. Check each response’s error field instead of only the HTTP status, or a single corrupt file will quietly hide the rest. See the code references for the same setup as Terraform.

    Common issues after configuration

    SymptomLikely causeWhat to check / fix
    403: Cloud Vision API has not been used in project before or it is disabledThe API is not enabled in the project the call is billed toRun gcloud services enable vision.googleapis.com in that project and wait a minute for it to propagate.
    403 or an empty answer for a gs:// imageThe caller can’t read the object, or the object is in a bucket with public access prevented and no IAM grantGive the caller’s service account roles/storage.objectViewer on the bucket and test with gcloud storage cat.
    400: Bad image dataThe bytes are not a valid image, the base64 is wrong, or the file is over the size limitCheck the file opens locally, send raw base64 without a data: prefix and keep each image under the documented limit.
    429: Quota exceeded for quota metricThe per-minute request quota for the project was reachedRetry with exponential backoff, spread work out, batch up to 16 images and ask for more quota in the console with real numbers.
    One image in a batch fails and the rest workA response has its own error object while the HTTP status is 200Loop over responses, read error on each, and retry only the failed ones.
    Text comes back as a single block or in odd orderTEXT_DETECTION was used for a dense pageUse DOCUMENT_TEXT_DETECTION for pages and handwriting, and read the structure from fullTextAnnotation.
    Charges do not match the number of picturesEvery feature on every image is a unitList only the features you use and compute units before a big batch.
    SafeSearch says VERY_UNLIKELY for something you would rejectThe rating describes likelihood, and the categories do not cover every kind of unwanted contentAdd your own rules, a second check for risky categories and a way for users to report pictures.
    An API key leaked in a repositoryThe key was committed or sent to a browser without restrictionsDelete or rotate it, restrict future keys to the Vision API and to known callers, and prefer service accounts.
    Face detection has no way to say who someone isThe API detects faces and does not identify peopleUse a service built for it with the right consent and review, and think hard about whether you should.
    A PDF job is refused, or finishes with an empty output bucketAn API key was used (the offline method needs a service account), the output prefix was wrong, the caller can’t write to it, or the operation is still runningCheck the operation’s status, give the identity write access to the output bucket and look under the prefix you set.

    Use cases: when and where to use it

    Good fit

    • Tagging and search for photo libraries and product catalogues
    • Reading text from photos, signs, labels and simple scans
    • Screening user uploads with SafeSearch before they are shown
    • Finding where a picture is used on the web, for rights and brand checks
    • Choosing crops and dominant colours for thumbnails and design
    • Quick prototypes where one call and a free monthly allowance are enough

    Consider something else

    • A sentence, a summary or an answer about a picture → Gemini on Vertex AI
    • Forms, invoices and structured documents → Document AI
    • Video analysis → the Video Intelligence API
    • Your own image categories → a model trained on Vertex AI
    • The same job on other clouds → compare Amazon Rekognition and Azure AI Vision

    Pros: why consider it?

    Why teams choose it

    • One request covers many kinds of analysis
    • A free allowance of 1,000 units per feature each month
    • Simple REST and gRPC with client libraries in many languages
    • Batch and asynchronous modes for PDFs and large sets
    • Works directly on images in Cloud Storage with service account permissions
    • No model to train or host for the standard features

    Trade-offs to weigh

    • Each feature on each image is billed, so units add up fast
    • No face identification and no face collection, unlike Rekognition
    • No sentence-style descriptions; that is Gemini territory
    • Limited choice of processing location, so check data residency needs
    • SafeSearch gives likelihood levels and not scores you can tune
    • Accuracy depends on your pictures, so you must test with your own

    Common threats, vulnerabilities & risks

    RiskSeverityWhy it mattersMitigation
    Personal pictures sent without a basisHighPhotos of people, documents and screens are personal data, and Google processes them for you.Say why you are sending them, send the least that works, and read Google’s data processing terms for the Vision API.
    A leaked API keyHighAnyone with the key can run up your bill, and keys end up in code and chat logs.Prefer service accounts, restrict keys by API and caller, rotate them and alert on spikes.
    Unsafe content let through on one ratingMediumSafeSearch is a likelihood, not a guarantee, and categories are limited.Draw a reject line and a lower review line, spot-check what passed, and give users a way to report a picture.
    Runaway costMediumA loop, a retry storm or an extra feature multiplies units quickly.Compute units before batches, set a budget alert and cap concurrency.
    Data residency assumptionsMediumProcessing may not happen in the Region of your bucket.Read the data residency and location notes for the features you use before making promises to customers.
    Bucket open to too manyMediumPictures in a broadly readable bucket are exposed whatever the API does.Use uniform access, public access prevention and a single read role for the application.
    Wrong tool for the jobLow–MedDense documents, face identity and video need other services.Map each need to Document AI, a face service or the Video Intelligence API at design time.
    Silent partial failures in batchesLow–MedA 200 response can hide per-image errors.Check each response’s error field and retry only the failures.
    Stale model behaviourLow–MedAnswers can change as Google updates models.Keep a labelled sample and re-run it on a schedule.

    Performance optimisation

    • Put up to 16 images in each request instead of one call per picture.
    • Use gs:// addresses when the pictures are already in Cloud Storage, so you don’t pay to base64 them through your own server.
    • List just the features you act on. Every extra one adds time and units.
    • Run offline PDF and TIFF work as asynchronous jobs and poll the operation.
    • Keep your workers in the same Region as the bucket to cut transfer time.
    • Resize large photos first. Most features work well at a couple of thousand pixels on the long side.
    • Use retries with backoff and jitter for 429 and 5xx answers.
    • Keep the answer for each image hash and reuse it, so a repeat upload does no new work.

    Reduce monthly cost

    FinOps is the habit of managing cloud spend together with engineering. These are the FinOps checks that matter most for Cloud Vision API.

    • Remember the unit rule: images times features. Compute it before a batch.
    • Use the free 1,000 units per feature each month for development, not for a production plan.
    • Ask for SafeSearch together with label detection if Google’s pricing page still lists it as free in that combination for your account.
    • Deduplicate and cache before calling the API.
    • Don’t request TEXT_DETECTION and DOCUMENT_TEXT_DETECTION for the same picture. They are separate features, so you pay for both.
    • Set a budget alert on the project with thresholds at 50, 80 and 100 percent.
    • Check the volume tiers; rates fall after a monthly threshold per feature.
    • Delete test projects and old keys.

    Rates change with the feature and the volume, and third-party posts and an older cached quotas page disagreed with the current documentation, so no dollar figures are quoted here. Check the live page (see Pricing).

    Security optimisation

    • Run the application as a service account with read access to one bucket, and no downloaded key file.
    • Use Application Default Credentials. On Google Cloud, attach the service account to the runtime.
    • If you must use an API key, restrict it to the Vision API and to your callers, and rotate it.
    • Turn on public access prevention and uniform bucket-level access on the bucket.
    • Delete pictures with a lifecycle rule and turn off soft delete if the pictures are personal.
    • Check whether VPC Service Controls support your setup, and read its limits for the Vision API.
    • Enable audit logging for the calls that your policy needs to record, where Google Cloud offers it.
    • Use customer-managed encryption keys on the bucket if your rules call for them.
    • Review the data processing terms and the notes on location before sending customer pictures.
    • Give the billing alert an owner who will look at it.

    Governance & compliance

    Guardrails

    • A Terraform module for the API, the service account, the bucket, the lifecycle rule and the budget, with labels and an owner
    • An organisation policy that blocks service account key creation
    • A rule that API keys must be restricted and have an expiry owner
    • A written list of what pictures may be sent and who approves new uses

    Continuous checks (Cloud Asset Inventory, Security Command Center and your own scripts)

    • A script that lists API keys and flags unrestricted ones
    • Asset Inventory queries for service accounts with keys and for buckets without public access prevention
    • Budget and quota alerts on the project
    • Once a month a person looks at a few pictures the pipeline rejected and a few it let through
    • A quarterly check of the documentation for changes in limits and pricing

    Cloud Audit Logs record who changed the configuration, Cloud Asset Inventory keeps the history of resources such as buckets and keys, and Security Command Center flags risky settings. Google runs the models. Everything about the content is on your side: which pictures go in, how long they stay and what the answers trigger.

    Reduce carbon footprint

    • Cache results and skip duplicates.
    • Smaller pictures mean less data moved.
    • Ask only for the features you use.
    • Delete test projects and old pictures.
    • Choose a bucket Region with a lower carbon footprint where your data rules allow it, and use the Carbon Footprint report for the project’s totals.
    • Google’s report works by project and service group, so quote no Vision figure of your own.

    Pricing

    Purchase options

    Free units 1,000 per feature each month

    The first 1,000 units of each feature every month are free, as the pricing page stated in October 2026.

    Per unit Per 1,000 units, by feature

    After the free units each feature is billed per 1,000 units. Label, text and document text detection are priced alike at low volume, and rates fall above a monthly threshold.

    SafeSearch Free with labels

    Google’s page lists SafeSearch at no extra charge when it is requested together with label detection, and as its own feature otherwise.

    Neighbours Billed separately

    Document AI, the Video Intelligence API, Product Search storage and Gemini on Vertex AI have their own meters.

    What you actually pay for

    • Units: one per feature per image, after the free allowance
    • Lower rates after a monthly volume threshold, per feature
    • Cloud Storage for the pictures and for batch output
    • Network egress, if the pictures or results leave Google Cloud
    • Separate meters for Document AI, Video Intelligence, Product Search and Gemini

    Google lists the free units, rates and tiers on its pricing page. See the official Cloud Vision pricing page and the Google Cloud Pricing Calculator.

    Important code references

    The API switched on for one project, a service account that can read a single private bucket, a bucket that deletes pictures after 30 days and a budget alert. The CLI tab enables the API, tries each feature, runs a PDF job and makes the same call as REST. Terraform describes the project pieces. The Python tab screens a list of gs:// pictures in batches of 16 with labels and SafeSearch, keeps one bad picture from failing the batch, and reads sparse or dense text. The C# tab does the same screening over a bucket and prints how many units the run used. Replace the project, bucket and names with your own.

    # Placeholders: replace the project, the bucket and the object names.
    PROJECT=my-project-id
    BUCKET=my-image-intake
    SA=vision-app
    BILLING_ACCOUNT=000000-AAAAAA-BBBBBB
    
    gcloud config set project $PROJECT
    
    # 1. Turn the API on and create the identity the application will run as. The caller needs permission to use the project's APIs.
    gcloud services enable vision.googleapis.com
    gcloud iam service-accounts create $SA --display-name="Image intake (Vision API)"
    gcloud storage buckets add-iam-policy-binding gs://$BUCKET \
      --member="serviceAccount:$SA@$PROJECT.iam.gserviceaccount.com" --role="roles/storage.objectViewer"
    
    # 2. Try each feature from the command line. A local path or a gs:// URL both work.
    gcloud ml vision detect-labels gs://$BUCKET/uploads/shopfront.jpg --max-results=10
    gcloud ml vision detect-safe-search gs://$BUCKET/uploads/shopfront.jpg
    gcloud ml vision detect-text gs://$BUCKET/uploads/shopfront.jpg --language-hints=en,hi
    gcloud ml vision detect-document gs://$BUCKET/uploads/invoice.png
    gcloud ml vision detect-objects gs://$BUCKET/uploads/shopfront.jpg
    gcloud ml vision suggest-crop gs://$BUCKET/uploads/shopfront.jpg --aspect-ratios=1:1,16:9
    
    # 3. Text from a multi-page PDF is an offline job: the result is written to Cloud Storage as JSON.
    gcloud ml vision detect-text-pdf gs://$BUCKET/uploads/contract.pdf gs://$BUCKET/results/contract-
    
    # 4. The same call as REST, which is what every client library sends. Two features in one request are billed as two units per image.
    curl -s -X POST "https://vision.googleapis.com/v1/images:annotate" \
      -H "Authorization: Bearer $(gcloud auth print-access-token)" \
      -H "x-goog-user-project: $PROJECT" -H "Content-Type: application/json" \
      -d '{"requests":[{"image":{"source":{"imageUri":"gs://'$BUCKET'/uploads/shopfront.jpg"}},
           "features":[{"type":"LABEL_DETECTION","maxResults":10},{"type":"SAFE_SEARCH_DETECTION"}]}]}'
    
    # 5. Cap the damage of a runaway client: a budget alert on the project, and a look at API usage.
    gcloud billing budgets create --billing-account=$BILLING_ACCOUNT --display-name="vision-monthly" \
      --budget-amount=50USD --filter-projects=projects/$PROJECT --threshold-rule=percent=0.8 --threshold-rule=percent=1.0
    gcloud services list --enabled --filter="config.name:vision.googleapis.com"
    
    # 6. Switch the API off again when the project ends.
    gcloud services disable vision.googleapis.com
    # Cloud Vision API for one project: the API switched on, a service account that can only read one bucket, a private bucket and a budget alert.
    terraform {
      required_providers {
        google = { source = "hashicorp/google", version = ">= 6.0" }
      }
    }
    
    variable "project_id" {
      type = string
    }
    
    variable "billing_account" {
      description = "Billing account ID, for example 000000-AAAAAA-BBBBBB"
      type        = string
    }
    
    provider "google" {
      project = var.project_id
      region  = "asia-south1"
    }
    
    data "google_project" "this" {}
    
    resource "google_project_service" "vision" {
      service            = "vision.googleapis.com"
      disable_on_destroy = false
    }
    
    resource "google_service_account" "app" {
      account_id   = "vision-app"
      display_name = "Image intake (Vision API)"
    }
    
    resource "google_storage_bucket" "images" {
      name                        = "my-image-intake-${var.project_id}"
      location                    = "ASIA-SOUTH1"
      uniform_bucket_level_access = true
      public_access_prevention    = "enforced"
    
      # Deleted pictures would otherwise stay recoverable for the default soft-delete period.
      soft_delete_policy {
        retention_duration_seconds = 0
      }
    
      # Uploads vanish after a month, so pictures of people do not pile up.
      lifecycle_rule {
        condition { age = 30 }
        action { type = "Delete" }
      }
    }
    
    # The application reads uploads and nothing else. Vision reads a gs:// picture with the caller's own access, so this bucket role is what lets the call work.
    resource "google_storage_bucket_iam_member" "app_reads" {
      bucket = google_storage_bucket.images.name
      role   = "roles/storage.objectViewer"
      member = "serviceAccount:${google_service_account.app.email}"
    }
    
    # An alert at 80 and 100 percent of a monthly amount for the whole project. A budget only notifies; it does not stop spending.
    resource "google_billing_budget" "vision" {
      billing_account = var.billing_account
      display_name    = "vision-monthly"
    
      budget_filter {
        projects = ["projects/${data.google_project.this.number}"]
      }
    
      amount {
        specified_amount {
          currency_code = "USD"
          units         = "50"
        }
      }
    
      threshold_rules { threshold_percent = 0.8 }
      threshold_rules { threshold_percent = 1.0 }
    }
    """Screening and reading pictures with the Cloud Vision API (google-cloud-vision). Pictures stay in Cloud Storage and are referenced by gs:// URL."""
    from google.cloud import vision
    
    F = vision.Feature.Type
    Likelihood = vision.Likelihood
    MAX_PER_REQUEST = 16          # the API accepts up to 16 images in one images:annotate call
    
    
    def image_from(uri):
        return vision.Image(source=vision.ImageSource(image_uri=uri))
    
    
    def units(image_count, feature_count):
        """What a batch will bill: every feature on every image is one unit. Check this before a big run, because 1,000 units a month per feature are free and the rest are not."""
        return image_count * feature_count
    
    
    def judge(safe):
        """'reject', 'review' or 'allow' from a SafeSearchAnnotation. Adult and violent content are strict; 'racy' only goes to a person."""
        strict = max(safe.adult, safe.violence)
        if strict >= Likelihood.LIKELY:
            return "reject"
        if strict == Likelihood.POSSIBLE or safe.racy >= Likelihood.LIKELY:
            return "review"
        return "allow"
    
    
    def screen(client, uris):
        """Labels and SafeSearch for many pictures. Returns {uri: result}. One bad picture fails alone: its entry carries the error and the rest of the batch is fine."""
        features = [vision.Feature(type_=F.LABEL_DETECTION, max_results=10), vision.Feature(type_=F.SAFE_SEARCH_DETECTION)]
        out = {}
        for start in range(0, len(uris), MAX_PER_REQUEST):
            chunk = uris[start:start + MAX_PER_REQUEST]
            reply = client.batch_annotate_images(requests=[vision.AnnotateImageRequest(image=image_from(u), features=features) for u in chunk])
            for uri, resp in zip(chunk, reply.responses):
                if resp.error.code:
                    out[uri] = {"error": resp.error.message}
                    continue
                out[uri] = {"decision": judge(resp.safe_search_annotation),
                            "labels": [(l.description, round(l.score, 2)) for l in resp.label_annotations if l.score >= 0.8]}
        return out
    
    
    def read_text(client, uri, dense=False):
        """TEXT_DETECTION suits a sign or a label inside a photo. DOCUMENT_TEXT_DETECTION suits pages, tables and handwriting and keeps the layout."""
        feature = vision.Feature(type_=F.DOCUMENT_TEXT_DETECTION if dense else F.TEXT_DETECTION)
        resp = client.annotate_image(vision.AnnotateImageRequest(image=image_from(uri), features=[feature]))
        if resp.error.code:
            raise RuntimeError(resp.error.message)
        if dense:
            return resp.full_text_annotation.text
        return resp.text_annotations[0].description if resp.text_annotations else ""
    
    
    if __name__ == "__main__":
        # Application Default Credentials: the service account on Cloud Run, or `gcloud auth application-default login` on a laptop.
        client = vision.ImageAnnotatorClient()
        print(screen(client, ["gs://my-image-intake/uploads/shopfront.jpg"]))
    // Screen pictures in a Cloud Storage bucket with SafeSearch and labels, in batches, and print how many billable units the run used.
    // Uses Application Default Credentials; the account needs read access to the bucket and permission to use the Vision API in the project.
    using Google.Cloud.Storage.V1;
    using Google.Cloud.Vision.V1;
    
    const string bucket = "my-image-intake";
    const int perRequest = 16;                     // the API accepts up to 16 images in one call
    
    var storage = await StorageClient.CreateAsync();
    var vision = await ImageAnnotatorClient.CreateAsync();
    
    var names = storage.ListObjects(bucket, "uploads/")
        .Where(o => o.Name.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) || o.Name.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
        .Select(o => o.Name).ToList();
    
    var features = new[] { new Feature { Type = Feature.Types.Type.LabelDetection, MaxResults = 10 }, new Feature { Type = Feature.Types.Type.SafeSearchDetection } };
    var units = 0;
    var held = 0;
    
    foreach (var chunk in names.Chunk(perRequest))
    {
        var requests = chunk.Select(name => new AnnotateImageRequest
        {
            Image = Image.FromUri($"gs://{bucket}/{name}"),
            Features = { features }
        });
        var reply = await vision.BatchAnnotateImagesAsync(requests);
        units += chunk.Length * features.Length;   // every feature on every image is one unit
    
        for (var i = 0; i < chunk.Length; i++)
        {
            var r = reply.Responses[i];
            if (r.Error != null)                   // one bad picture does not fail the batch
            {
                Console.WriteLine($"{chunk[i],-40} error: {r.Error.Message}");
                continue;
            }
            var safe = r.SafeSearchAnnotation;
            var worst = (Likelihood)Math.Max((int)safe.Adult, (int)safe.Violence);
            var verdict = worst >= Likelihood.Likely ? "reject" : worst == Likelihood.Possible || safe.Racy >= Likelihood.Likely ? "review" : "allow";
            if (verdict != "allow") held++;
            var labels = string.Join(", ", r.LabelAnnotations.Where(l => l.Score >= 0.8f).Select(l => l.Description));
            Console.WriteLine($"{chunk[i],-40} {verdict,-7} {labels}");
        }
    }
    
    Console.WriteLine($"{names.Count} picture(s), {units} billable unit(s), {held} held back");

    Best videos to explore

    Videos picked for this service. Each one is labelled with its source, opens on YouTube if you prefer, and loads only when you press play.

    Detect Labels, Faces, and Landmarks in Images with the Cloud Vision API || [GSP037] || UpdatedCommunity video · Beginner · Watch on YouTube
    Google Cloud Vision API for Images using Python: Google Vision API TutorialCommunity video · Intermediate · Watch on YouTube
    Google Vision API for OCR Text Extraction (Part 1): Tutorial Google Vision AICommunity video · Intermediate · Watch on YouTube
    Google Cloud Vision API (Part 2): Object Detection TutorialCommunity video · Intermediate · Watch on YouTube

    Interview questions

    BasicWhat is the Cloud Vision API?

    It is Google’s pre-trained image analysis service. You send a picture, or a Cloud Storage address, and name features such as labels, text, SafeSearch, objects or landmarks, and it returns JSON. You don’t train or host a model for these standard features.

    BasicHow is the Cloud Vision API billed?

    By unit. One feature applied to one image is one unit, so two features on one picture are two units. The first 1,000 units of each feature each month are free, and rates fall at high volume. Check the pricing page for current figures.

    BasicCan it tell me who is in a photo?

    No. Face detection finds faces and gives landmarks and likelihoods such as joy or headwear, but the API does not identify people and has no face collection. Landmark and logo detection name places and brands, not individuals.

    IntermediateWhat is the difference between TEXT_DETECTION and DOCUMENT_TEXT_DETECTION?

    TEXT_DETECTION is for a small amount of text inside a scene, such as a sign. DOCUMENT_TEXT_DETECTION is for dense text, pages and handwriting, and returns the structure of pages, blocks, paragraphs, words and symbols. Use Document AI when the document type matters.

    IntermediateHow do you process thousands of images or a PDF?

    For images, batch up to 16 per request with a capped number of workers. For PDFs and TIFFs use the asynchronous batch method with an output bucket, poll the operation, and read the JSON files it writes.

    IntermediateHow do you authenticate an application?

    Run it as a service account and use Application Default Credentials, with the account attached to the runtime on Cloud Run or GKE. Give it read access to the bucket. Use an API key only when you must, restrict it to the API and callers and rotate it.

    AdvancedHow would you design an upload moderation pipeline?

    Send each upload to a queue, call SafeSearch and label detection in batches, reject above one likelihood, send the middle band to a human queue, and cache results by image hash. Log the thresholds in force, sample what passed, and let users report pictures.

    AdvancedHow do you control cost at scale?

    Compute units as images times features before every batch, ask for only the features you use, cache by hash, cap concurrency, use the free units for development and put a budget alert with thresholds on the project. Watch the per-feature mix, since one extra feature doubles the bill.

    AdvancedVision API or Gemini for understanding images?

    Vision gives fixed, cheap, predictable outputs such as labels, text and ratings. Gemini on Vertex AI gives sentences, answers to questions about the picture and structured extraction, and is more flexible but costs per token and can vary in its answers. Many systems use Vision for screening and Gemini for the few pictures that need reasoning.

    AdvancedWhat do you check before promising data residency in India?

    Read Google’s data residency and location notes for each feature, since a bucket in Mumbai doesn’t mean the API processes the image there. Check which endpoints are location-specific, record what you found and get legal review before putting it in a contract.

    Similar or alternative services on other clouds

    CapabilityAWSAzureGoogle Cloud
    ServiceAmazon RekognitionAzure AI VisionCloud Vision API
    Labels and objectsDetectLabelsTags, objects, peopleLabel detection, object localization
    Reading textDetectText, Textract for documentsRead, Document Intelligence for documentsText and document text detection
    Unsafe contentModeration labels with a parent categoryAzure AI Content Safety (separate)SafeSearch, five levels
    FacesDetect, compare, collections, livenessAzure Face (separate, limited access)Detection only, no identification
    Landmarks, logos, webCelebrity recognition; no dedicated landmark or logo APINot in Image Analysis 4.0Landmarks, logos, web detection
    Own modelCustom LabelsCustom Vision and Foundry modelsVertex AI models
    VideoStored video jobsVideo retrieval, Content UnderstandingVideo Intelligence API (separate)
    Billing unitPer image or video minutePer 1,000 transactionsPer 1,000 units, 1,000 free per feature a month

    Typical callers are Cloud Run functions or Cloud Run services triggered by new objects in Cloud Storage, with results saved to Firestore or BigQuery and routed on with Eventarc. Request counts, errors and quota show up in Cloud Monitoring.

    Did you find this article helpful?

    Your answer helps us improve this page for the next reader.

    Sources and further reading

    CloudBrum wrote this page in its own words, using the provider’s public documentation listed below as the reference. Features, limits, names and prices change, so confirm anything that matters on the provider’s own pages before you decide.