Skip to content
arduralab
·9 min

Google Indexing API — who it is for and how to set it up [2026]

Indexing APIGoogle Search Consoleindexingtechnical SEOPython
MG
Marcin Godula

Współzałożyciel & Head of SEO/Tech

Specjalista SEO, GEO i web development z ponad 15-letnim doświadczeniem. Pomaga firmom B2B budować widoczność w wyszukiwarkach klasycznych i AI.

The Indexing API is Google's interface for notifying it about added, updated and removed pages, but only for job postings (JobPosting) or livestreams (BroadcastEvent in a VideoObject). If you run a job board or a livestreaming site, this tutorial walks you through setup and gives you a ready-to-use script. If you run a blog, a store or a company website, the Indexing API is not for you, and below I cover what to use instead.

TL;DR — Google Indexing API in 5 points

#WhatDetails
1. ScopeOnly pages with JobPosting or BroadcastEvent in a VideoObjectper Google's documentation
2. SetupGoogle Cloud project + Indexing API enabled + service accountJSON key
3. Search ConsoleService account as owner of the propertywithout it the API rejects submissions
4. Quota200 publish requests per day per projectresets at midnight Pacific Time
5. EndpointurlNotifications.publish with {url, type: URL_UPDATED}OAuth scope indexing

What the Indexing API is and what it is for

The Indexing API is Google's programmatic interface that lets a site owner tell Google a page has been added, updated or removed, so Google can schedule it for a fresh crawl. It also lets you check when Google last received a notification for a given URL, and combine up to 100 calls into a single HTTP request.

Scope according to Google's documentation

Google's documentation says it plainly:

"The Indexing API can only be used to crawl pages with either JobPosting or BroadcastEvent embedded in a VideoObject."

The reasoning is practical: job postings and livestreams are short-lived, so search results need to reflect quickly when they appear and disappear. The same documentation warns that all submissions undergo spam detection, and that attempts to abuse the API, including using multiple accounts to exceed quotas, may result in access being revoked.

When does the Indexing API make sense?

SituationUse it?Why
Job board (JobPosting)✅ YESWithin the documented scope
Livestreaming site (BroadcastEvent)✅ YESWithin the documented scope
A job posting expired or was removed✅ YESURL_DELETED tells Google the page is gone
Blog, store, service page❌ NOOutside the API's scope; use a sitemap and URL Inspection
Migration or new domain without job postings❌ NOOutside the API's scope; see how to speed up indexing

Step-by-step setup

Step 1: Google Cloud Console — project + API

  1. Open console.cloud.google.com
  2. Create a new project (e.g., seo-indexing-tools)
  3. In the menu choose APIs & Services → Library
  4. Search for Indexing API and click Enable
  5. You'll be redirected to the API dashboard, which confirms it is enabled

Step 2: Service account + JSON key

  1. Open the Service accounts page in Google Cloud Console and select the project
  2. Click Create Service Account, enter a name (e.g., seo-indexing-bot) and a description
  3. The service account permissions section is optional; continue
  4. In the Create key section choose JSON and click Create
  5. The JSON file downloads automatically and is the only copy of the key. Store it securely and never commit it to a repository

You'll find the service account email in the client_email field of the downloaded JSON file. It has the format name@project-id.iam.gserviceaccount.com; you'll use it in step 3.

Step 3: Google Search Console — service account as owner

  1. Verify site ownership in Search Console with any supported method (a Domain property or a URL-prefix property)
  2. Open Search Console and select the property you verified
  3. Add the service account email from step 2 as a (delegated) owner
  4. Confirm

Google's documentation requires owner status; lower permission levels are not enough to send submissions.

Step 4: Test the setup — first request

from google.oauth2 import service_account
from googleapiclient.discovery import build

CREDENTIALS_PATH = "/path/to/gsc-service-account.json"
SCOPES = ["https://www.googleapis.com/auth/indexing"]

credentials = service_account.Credentials.from_service_account_file(
    CREDENTIALS_PATH, scopes=SCOPES
)
service = build("indexing", "v3", credentials=credentials)

response = service.urlNotifications().publish(body={
    "url": "https://your-domain.com/jobs/123",
    "type": "URL_UPDATED"
}).execute()

print(response)

Expected response:

{
  "urlNotificationMetadata": {
    "url": "https://your-domain.com/jobs/123",
    "latestUpdate": {
      "url": "https://your-domain.com/jobs/123",
      "type": "URL_UPDATED",
      "notifyTime": "2026-05-03T20:14:32.123456Z"
    }
  }
}

The response confirms that the notification was received. It does not mean the page has already been crawled or indexed.

Most common errors:

  • 403 Permission denied → the service account is not an owner of the Search Console property (step 3)
  • 403 saying the API has not been used in the project → the Indexing API was not enabled in Google Cloud (step 1)
  • 400 Invalid argument → invalid URL (it must be a full URL including the protocol)

Python script for bulk submissions

The script submits URLs from a text file, respects the daily quota, retries on 5xx errors and writes a JSON log. It is meant for job posting or livestream pages.

#!/usr/bin/env python3
"""Bulk Indexing API submissions — template for the default 200/day quota."""
import json
import sys
import time
from datetime import date
from pathlib import Path

from google.oauth2 import service_account
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError

CREDENTIALS_PATH = Path("/path/to/gsc-service-account.json")
SCOPES = ["https://www.googleapis.com/auth/indexing"]
RATE_LIMIT_SLEEP = 0.5  # 0.5 s between requests = ~120 req/min
DAILY_QUOTA = 200

def submit_url(service, url: str) -> dict:
    """Submit 1 URL with retry on 5xx."""
    body = {"url": url, "type": "URL_UPDATED"}
    for attempt in range(5):
        try:
            return service.urlNotifications().publish(body=body).execute()
        except HttpError as e:
            if e.resp.status >= 500:
                time.sleep(2 ** attempt)
                continue
            raise
    raise RuntimeError(f"Failed after 5 retries: {url}")

def main(urls_file: str) -> None:
    urls = Path(urls_file).read_text().splitlines()
    urls = [u.strip() for u in urls if u.strip() and not u.startswith("#")]

    if len(urls) > DAILY_QUOTA:
        print(f"WARN: {len(urls)} URLs > daily quota {DAILY_QUOTA}. Truncating.")
        urls = urls[:DAILY_QUOTA]

    creds = service_account.Credentials.from_service_account_file(
        CREDENTIALS_PATH, scopes=SCOPES
    )
    service = build("indexing", "v3", credentials=creds, cache_discovery=False)

    results = []
    for i, url in enumerate(urls, 1):
        print(f"[{i}/{len(urls)}] {url}")
        try:
            response = submit_url(service, url)
            results.append({"url": url, "status": "OK", "response": response})
        except Exception as e:
            results.append({"url": url, "status": "ERROR", "error": str(e)})
        time.sleep(RATE_LIMIT_SLEEP)

    log_path = Path(f"indexing-log-{date.today().isoformat()}.json")
    log_path.write_text(json.dumps(results, indent=2))
    ok_count = sum(1 for r in results if r["status"] == "OK")
    print(f"\nDone: {ok_count}/{len(urls)} OK. Log: {log_path}")

if __name__ == "__main__":
    main(sys.argv[1] if len(sys.argv) > 1 else "urls.txt")

urls.txt file format

https://your-domain.com/jobs/123
https://your-domain.com/jobs/124
# comments are ignored
https://your-domain.com/live/conference-2026

Run

python3 indexing_bulk.py urls.txt

The output is a JSON log of every request and response. You can load it into a dashboard or simply check which URLs returned an error.


What the Indexing API won't fix

A notification asks Google to crawl a page. It does not guarantee indexing or rankings.

Situations where the Indexing API won't help

  1. The page has noindex in meta robots — Google will crawl it but won't index it. First fix <meta name="robots">.
  2. Robots.txt blocks the URL — Googlebot won't crawl it at all. Check robots.txt.
  3. The page has little valuable content — Google may crawl it and decide it isn't worth indexing.
  4. A duplicate without a clear canonical — Google will choose the version to index itself. Configure <link rel="canonical">.
  5. The page is neither a job posting nor a livestream — then the API is the wrong tool altogether.

What to use for other pages

ToolPurposeWhen
Sitemap.xmlA map of URLs to crawlEvery site; the basic signal for new and changed pages
URL Inspection in Search ConsoleDiagnosing a single page and requesting indexingIndividual important pages
Internal linkingA path to new pagesEvery new page should be linked from one that is already indexed
IndexNow (Bing/Yandex)Notifications for search engines that support the protocolA complement on the Bing side

FAQ — most common questions

Can I use the Indexing API for a client's site?

Yes, if the client's site contains job postings or livestreams. The service account must be an owner of the client's Search Console property, which requires the client's consent. Keep in mind that the 200-a-day quota applies to the Google Cloud project, so several clients in one project share the same quota.

What is the URL_DELETED type?

urlNotifications.publish also accepts type: URL_DELETED. It tells Google that the page has been removed from your server, so Google can remove it from the index and stop crawling it. For a job board this is the typical case: a posting has expired, the page returns 404 or 410, and the API speeds up its removal from results.

How do I check whether Google received the notification?

The urlNotifications.getMetadata endpoint returns the time of the latest notification for a given URL (latestUpdate.notifyTime). That confirms the signal was received, not that the page was indexed. You can check indexing status in Search Console with the URL Inspection tool.

Can I submit the same URL every week to improve its ranking?

No. A notification makes sense when a page is new, has changed significantly or has been removed. Repeating submissions without changes uses up the quota and does not affect rankings.


What's next

  1. Check whether your pages are in scope — if you have no job postings or livestreams, start with a sitemap and internal linking.
  2. Job board — complete steps 1-3 and hook the script into publishing and expiry (URL_UPDATED when a posting is added, URL_DELETED when it is removed).
  3. Read next:

Get an SEO audit

Your sitemap lists many URLs, but only a few of them are in Google's index? In our free SEO audit we check indexing, robots.txt, the sitemap, redirects and canonicalization. You get a prioritized report within 48 business hours.

Need help with this topic?

Get a free audit and find out how we can help your business grow online.

Get a free quote