Indexer by DependsiT

Setting Up a Google Cloud Project for the Indexing API from Scratch

google cloud project indexing api setup flow from creation to first submission

If you want to notify Google directly when a job posting or livestream page changes, you need a Google Cloud project first. The project holds your API enablement, your service account, your quota, and your logs. Without it, there is no place to create credentials and no counter that tracks usage. This guide is for site owners, SEOs, and developers who are starting from zero and want a clean setup that lasts. The primary keyword for this guide is google cloud project indexing api, and every step connects that project to a working Indexing API submission.

You will create a dedicated project in Google Cloud Console, enable the Indexing API, create a service account with a JSON key, connect that account to Search Console, and run a safe first test. You will also learn how to organize multiple sites, avoid common permission failures, and keep quota and logs readable over time. By the end you will have a project you can hand to a teammate with confidence, plus a checklist for what to do next. For the broader end to end flow once the project exists, see the complete setup guide for the Indexing API.

Key takeaways

  • A Cloud project is the billing, quota, and identity container for every Indexing API call, so use one dedicated project per site or client.
  • The setup order is fixed: create project, enable the Indexing API, create a service account and JSON key, then add that account as Owner in Search Console.
  • The Indexing API officially supports JobPosting and BroadcastEvent URLs with URL_UPDATED and URL_DELETED notifications, and it only requests a crawl.
  • Quota is per project, usually around 200 publish requests per day for new projects, so isolate testing from production.
  • Google does not support IndexNow, so plan a separate IndexNow workflow if you also need Bing, Yandex, Naver, or Seznam coverage.

google cloud project indexing api setup flow from creation to first submission <!-- IMAGE-PROMPT cover: 1200x630, DependsIt brand, deep charcoal #121212 background, vibrant mint #22E3B0 accent glow, thin node-network line art, Clash Display style bold heading space on left, General Sans clean labels, subject: Google Cloud Console project creation flow to Indexing API enablement to service account key, flat vector, high contrast, accessible, no photorealistic faces, no text smaller than 24px, no em dash in rendered text, export PNG then cwebp -q 82 to WEBP -->

What your google cloud project indexing api setup actually controls

A Google Cloud project is a container, not a server. It groups together enabled APIs, credentials, quota counters, IAM permissions, logs, and billing linkage. When you call the Indexing API, Google checks four things against that project: is the Indexing API enabled here, does the credential belong to this project, is quota left for today, and does the service account have access to the Search Console property for the URL. If any answer is no, the call fails, even if the other three are correct. That is why a clean project saves hours later. You can see exactly what is enabled, who changed what, and how much quota remains.

Many teams reuse an old project that already hosts Analytics, Maps, or internal tools. That works, but it mixes concerns. Quota graphs become hard to read, IAM changes by other teams can break indexing, and disabling an API to save cost can stop submissions silently. A dedicated project named clearly, for example site-indexing-prod, keeps indexing isolated. You can grant access narrowly, track spend and usage separately, and revoke everything by disabling one project without touching other systems. For agencies, one project per client prevents a busy client from consuming shared quota and makes reporting simple.

The project does not store your content. It stores configuration. Your URLs stay on your site. Google still crawls them with Googlebot after a notification. The project only records that a notification was sent, when, for which URL, and with what result. The getMetadata method can show the most recent notification Google recorded for a URL, but your own database should remain the source of truth for submission history. Keep a table with URL, notification type, timestamp, HTTP status, and response body. That log matters more than the console view when you debug.

Billing often causes confusion. The Indexing API itself does not charge per call under normal use, but Cloud Console may still ask for a billing account depending on account history and organization policy. You can usually complete setup without paid services. What costs real money is engineering time, monitoring, and maintenance. Record the project ID and project number in your runbook now. The project ID appears in CLI commands, the project number appears in logs and support tickets. Both are safe to store in docs. Only the JSON key and tokens are secret.

Before you proceed, confirm fit. The Indexing API is documented for pages that contain JobPosting structured data and pages that contain BroadcastEvent markup for livestreams. The notification types are URL_UPDATED when content is new or changed and URL_DELETED when it is removed. There is no ranking promise. There is no Bing coverage. Google does not support IndexNow. If your goal is faster discovery for jobs or livestreams on Google, a Cloud project is the right starting point. If you need broader coverage, you will add IndexNow separately later.

ConceptWhat it means for indexingWhere you see it
Project IDUnique identifier used in CLI and configProject picker, runbook, gcloud commands
Project numberNumeric ID used in logs and supportProject settings, audit logs
Enabled APIsWhich Google services this project may callAPIs and Services, Enabled APIs list
Service accountMachine identity that signs API callsIAM and Admin, Service Accounts
QuotaDaily and per minute limits for publish callsAPIs and Services, Quotas page
IAM rolesWho can edit the project or keysIAM page, audit log

By the end of this section you should be able to explain the project to a teammate in one sentence: it is the named container that holds API access, credentials, quota, and logs for our indexing work. That shared definition prevents the most common early mistake, which is creating keys in one project while enabling the API in another.

If you are new to Cloud administration, start with a guided google cloud console setup before touching the command line. The console walkthrough helps you create a new google cloud project with the right name, organization folder and labels, then confirm ownership in IAM. Once the console path feels clear, mirror the same steps with a repeatable gcloud setup script so staging and production stay identical. Teams that document both paths onboard faster because visual learners follow clicks while automation minded teammates copy commands. Either route leads to the same container, but recording both prevents drift when staff changes.

What to prepare before you click anything

Preparation determines whether setup takes 25 minutes or two days. Gather access first. You need a Google account that can create Cloud projects, or Editor or Owner rights on an existing project you plan to use. You need verified ownership of the site in Search Console for the exact property you will submit. Domain properties cover all subdomains and protocols, URL prefix properties cover one prefix only. If you will submit https://example.com/jobs/123, the property must include that URL. You also need Owner role in Search Console so you can add the service account as Owner later. Without that role, delegation fails and every publish call returns 403 permission denied.

Next, decide where secrets will live. The service account JSON key is a password file. Anyone with that file can attempt API calls against your quota and, where the account has Search Console access, submit notifications for your URLs. Choose storage now: a secrets manager such as Google Secret Manager, HashiCorp Vault, or AWS Secrets Manager for production, plus environment variables on the server at runtime. Avoid storing the key in Git, in tickets, in chat history, in front end code, or in shared drives. Decide who may rotate the key and where the rotation steps are documented. If vendors are involved, prefer that they run under your project with limited access rather than receiving a copy of the key by email.

On the technical side, pick one primary language for submissions. Python is the fastest path for most SEO teams because the official client handles JWT signing and token refresh. Node.js fits teams that already run JavaScript backends or edge functions. PHP fits WordPress and Laravel stacks. cURL is useful for manual tests even if production uses another language. You do not need all four in production. You need one tested path plus cURL for debugging. Install your toolchain now: Python 3.10 or later with pip, or Node 18 or later with npm, or PHP 8.1 or later with curl extension, plus the gcloud CLI if you like terminal workflows.

Choose a safe test URL on your own verified property. Ideally it is a real job or livestream page that you control and can update without harm. Avoid testing with a homepage or a revenue critical product page on the first run. You want a URL where a 200 response and a later getMetadata check prove success without risk. Write down the exact URL, the Search Console property that contains it, and the Cloud project name you will use. This three line record prevents mismatches later when_teams debug.

Time and access checklist:

  1. Google account with project creation rights or Editor access to target project.
  2. Search Console property verified for the exact domain or prefix you will submit.
  3. Owner role in Search Console so you can delegate to the service account.
  4. Server or laptop with your chosen language runtime and package installer.
  5. Secrets location decided and access tested.
  6. One safe test URL on your own property.
  7. Agreement on project naming, for example site-indexing-prod and site-indexing-test.

A note on environments. Authentication uses the service account email, not your personal login session. That means cron jobs, CI pipelines, and build hooks can submit without interactive login. It also means local testing uses the same key as production unless you separate projects. Create two projects from the start when possible: one for production and one for testing. Quota is per project, so testing will not consume production allowance. Label them clearly and store both IDs in your runbook. The prerequisites in the official docs list the same ownership and enablement requirements, and they are worth reading once before you begin.

Create the project in Cloud Console

Open Google Cloud Console and sign in with the account that should own the project. For companies, prefer a Workspace account or a shared admin identity rather than a personal Gmail, because handover is easier when staff changes. Click the project picker at the top bar, then New Project. Enter a clear name such as Example Jobs Indexing Prod. The console suggests a project ID with a numeric suffix. You may edit the ID now, but you cannot change it after creation. Keep it short, lowercase, with hyphens, for example example-jobs-indexing-prod. Select the correct organization and folder if prompted. Your company may require projects to live under a specific folder for policy inheritance. Confirm billing linkage if asked. Normal Indexing API use does not require paid services, but the prompt varies by account.

Wait for provisioning to finish, then select the new project in the picker. Open IAM and Admin, then IAM, and confirm your account is listed as Owner. Add a second owner for production, so access survives vacations and departures. Document the project ID and project number in your runbook. Open Project Settings to copy both values. Create a label such as purpose:indexing and env:prod. Labels help filter usage and cost reports later and cost nothing to add. If your organization uses folders, verify now that the project sits in the intended folder, because moving it later can reset inherited policies and confuse access for a day.

Common mistakes at this stage are predictable. The first is creating the project under the wrong identity and then losing admin access when that person leaves. The second is creating two projects by accident and later enabling the API in one while creating keys in the other. The third is assuming quota follows the key. It does not. Quota follows the project where the API is enabled and where the OAuth client belongs. If publish calls report quota exceeded on the first day, you are likely authenticating against the wrong project. The fourth is vague naming such as My Project 7, which makes logs unreadable in three months. Use names that include site, purpose, and environment.

For teams that prefer the terminal, the same result takes three gcloud commands. This block only creates and selects the project. Enabling the API comes in the next section. Keep the commands in your runbook so staging matches production.

# Create and select the project with gcloud
gcloud projects create example-jobs-indexing-prod --name="Example Jobs Indexing Prod"
gcloud config set project example-jobs-indexing-prod
gcloud projects describe example-jobs-indexing-prod
# Python: no API call yet. Record the project ID for later auth.
# PROJECT_ID = "example-jobs-indexing-prod"
# Store it in env, not in source: os.environ["GOOGLE_CLOUD_PROJECT"]
// Node: no code needed at this stage. Record project ID for later auth.
// const PROJECT_ID = "example-jobs-indexing-prod";

If you already have a project for SEO tooling, you may reuse it, but a dedicated project remains cleaner for quota tracking. The quota dashboard shows per method usage, and a dedicated project makes the graph readable at a glance. It also lets you revoke all indexing access by disabling one project without touching analytics or other integrations. For single site owners the difference is minor. For agencies managing many clients, one project per client prevents one busy site from consuming shared quota and simplifies audits. Record your decision and the reason in one line in the runbook so future teammates do not merge projects to save clicks.

StepAction in consoleHow to confirm
1. New projectProject picker, New Project, clear name and IDProject appears in picker list
2. Select projectSwitch picker to new projectProject ID shown in top bar and settings
3. Confirm ownershipIAM and Admin, IAM, check Owner roleYour account listed as Owner
4. Add second ownerIAM, Add, second admin as OwnerTwo owners visible
5. Label and documentLabels purpose:indexing, record ID and numberRunbook updated, labels visible

By the end of this section you should have a selected project, two owners for production, labels applied, and the ID and number recorded. Do not create keys yet. Enable the API first so later steps have a working service to call.

Enable the Indexing API in the API library

Enabling the API activates the urlNotifications publish and getMetadata methods for your project and makes quota visible in the console. Until you complete this step, publish calls fail with service disabled or not found style errors even with a valid key. The fix is a two minute toggle, but it is the most skipped step in failed setups. Open APIs and Services, then Library. Search for Indexing API. Select the result owned by Google, often labeled Web Search Indexing API, and press Enable. Wait for the confirmation banner. Then open APIs and Services, then Enabled APIs, and confirm the Indexing API appears in the list. Open Quotas from that page and note the actual limits for Publish requests per day and per minute. New projects often show around 200 publish requests per day and a small per minute rate. Values vary by account age and history, so record what you see instead of trusting screenshots from old tutorials.

If you manage infrastructure as code, enable the service programmatically so staging and production match. The service name is indexing.googleapis.com. After enabling, allow a few minutes for propagation before testing. Immediate calls can return 403 with service disabled messages that clear on retry. That delay is normal and does not mean your key is broken. Wait five minutes, then test once more before rebuilding anything.

# Enable via gcloud so environments match
gcloud services enable indexing.googleapis.com --project=example-jobs-indexing-prod
gcloud services list --enabled --project=example-jobs-indexing-prod | grep indexing

Verification matters more than the click. After enabling, check three places: Enabled APIs list shows the Indexing API, Quotas page shows publish limits, and IAM audit log shows who enabled it and when. Screenshot or copy these values into your runbook with the date. When quota questions arise later, that baseline proves whether limits changed or usage grew. If you run multiple projects, repeat the check per project. Enabling in prod does not enable in test. Each project has its own toggle and its own quota counter.

A frequent error is enabling the wrong API. Google hosts many similarly named services, including Search Console API, Custom Search API, and Indexing API. Only the Indexing API provides urlNotifications publish. If your Enabled APIs list shows Search Console API but not Indexing API, publish calls will fail. Remove confusion by searching for the exact service name indexing.googleapis.com in the gcloud output. Another frequent error is enabling in one project while authenticating with a key from another. The console top bar shows the active project. The key file contains a project ID in the project_id field. Those two values must match the project where you enabled the API.

CheckWhereExpected
API enabledAPIs and Services, Enabled APIsIndexing API listed, owned by Google
Service namegcloud services listindexing.googleapis.com present
Daily quota visibleQuotas page for Indexing APIPublish per day value recorded
Per minute quota visibleQuotas page, per minute viewSmall per minute value recorded
Audit entryIAM audit logEnable event with actor and timestamp

If enablement fails due to organization policy, you will see a permission denied message with the policy name. That is an admin task, not a code bug. Ask your Workspace admin to allow service enablement for your folder or to enable it for you. Do not work around policy by creating shadow projects under personal accounts. That creates ownership risk and breaks handover. Once enabled, leave the toggle on. Disabling and re enabling resets propagation delay and can interrupt production submissions.

To keep enablement repeatable, treat the console clicks as indexing api activation steps you can checklist every time. First, open the api library indexing view, search for the exact service name and press enable, then confirm the entry in Enabled APIs and note quota. Second, record screenshots or gcloud output with dates so audits show who enabled what. When you need to enable indexing api access for a second environment, follow the same checklist rather than improvising. That habit prevents the classic split where prod is enabled but test is not, which causes confusing service disabled errors during promotion.

Create a service account and download the JSON key

A service account is a machine identity that signs API calls without interactive login. It has an email address ending in iam.gserviceaccount.com and a JSON key file that proves identity. Create one service account per purpose, for example indexing-publisher for production submissions and indexing-tester for local tests. Open IAM and Admin, then Service Accounts, with the correct project selected. Press Create Service Account. Enter a clear name and ID, for example indexing-publisher. Add a description with owner and date, for example Prod publisher for jobs site, owner SEO team, created 2026-10-05. Grant no broad IAM roles at this stage. The service account does not need Editor or Owner on the Cloud project to call the Indexing API. It needs Search Console delegation, which you configure in the next section, plus the ability to sign JWTs, which it has by default.

After creation, open the account, go to Keys, then Add Key, then Create New Key, then JSON. The console downloads a JSON file with fields including type, project_id, private_key_id, private_key, client_email, and token_uri. Store that file immediately in your secrets manager. Note the client_email value, because you will add exactly that email to Search Console. Verify that project_id inside the JSON matches the project where you enabled the API. If it does not, you created the key in the wrong project. Delete it and repeat with the correct project selected. Do not email the file, do not paste it into tickets, and do not commit it to Git. For a detailed walkthrough with screenshots and rotation notes, see the step by step service account guide.

Key handling rules that prevent incidents:

  1. Store the JSON in a secrets manager and load it at runtime via environment or mounted secret.
  2. Restrict file permissions to the service user only where a file must exist on disk.
  3. Record key ID, creation date, creator, and purpose in your runbook, but never the private key itself.
  4. Create separate keys for prod and test so rotation in one does not break the other.
  5. Set a calendar reminder to review keys quarterly and rotate at least yearly or on staff changes.

The JSON structure looks like this in outline form. Do not share real values. Use this only to confirm you downloaded the right kind of file.

{
  "type": "service_account",
  "project_id": "example-jobs-indexing-prod",
  "private_key_id": "abc123...",
  "private_key": "-----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY-----",
  "client_email": "indexing-publisher@example-jobs-indexing-prod.iam.gserviceaccount.com",
  "token_uri": "https://oauth2.googleapis.com/token"
}

If your stack runs on Google Cloud, you can attach the service account to the workload instead of downloading a key, for example a Compute Engine service account or Workload Identity for GKE. That avoids key files entirely and is the safest option where available. For servers outside Google Cloud, a downloaded JSON key plus Secret Manager remains the standard path. Either way, the Search Console delegation in the next section is still required. The key proves who you are to Google Cloud. Search Console delegation proves you may act for that site property. Both must be true before publish succeeds.

Field in JSONWhat to checkRisk if wrong
project_idMatches enabled API projectQuota errors, service disabled errors
client_emailExact email added to Search Console403 permission denied on publish
private_keyPresent, starts with BEGIN PRIVATE KEYAuth fails, invalid grant
token_uriGoogle OAuth token endpointToken fetch fails if edited

By the end of this section you should have a service account email recorded, a JSON key stored safely, and confirmation that project IDs match. Do not test publish yet. Add Search Console access first, or the test will fail for the wrong reason and waste time.

Connect the service account to Search Console

Search Console controls which identities may request crawling for a property. The service account email must be added as Owner on the exact property that contains your test and production URLs. Open Search Console, select the property, then Settings, then Users and permissions, then Add user. Paste the full service account client_email, select Owner, and save. Repeat for each property you will submit, including both domain property and URL prefix variants where you use both. Changes can take 10 to 15 minutes to propagate. Immediate publish tests often return 403 during that window even when everything else is correct. Wait, then retry once before changing keys.

Verification must match the URLs you will notify about. If you verify the domain property example.com, you may submit any URL under that domain, including subdomains, as long as the service account is Owner on that domain property. If you verify only the URL prefix https://example.com/jobs/, you may only submit URLs under that prefix. A common failure is verifying http while submitting https, or verifying example.com while submitting www.example.com under a prefix property. Use domain properties where possible to avoid prefix mismatches. For ownership proof details, see Google guidance to verify site ownership. That page explains DNS, file, and tag methods. You verify once as a human Owner, then delegate to the service account as an additional Owner.

Roles matter. Search Console has Owner, Full user, and Restricted user. Only Owner can add other users and only Owner delegation allows publish for the Indexing API in practice. Adding the service account as Full user leads to persistent 403 errors that look like key problems but are really role problems. Open Users and permissions after adding and confirm the service account row shows Owner. If it shows Pending, wait and refresh. If your property is a delegated property with multiple owners, confirm with the primary owner that delegation is allowed by organization policy.

Checklist for this section:

  1. Property verified for exact domain or prefix you will submit.
  2. Service account email added as Owner, not Full user.
  3. Row shows Owner status, not Pending.
  4. Same delegation repeated for each property you will use.
  5. 10 to 15 minute wait observed before first publish test.
  6. Test URL confirmed to sit inside the delegated property.

If delegation fails with a permission message, you are likely not Owner yourself. Ask an existing Owner to add the service account or to promote you first. Do not create a new Search Console property to work around roles, because the new property will not match your URLs and publish will still fail. Keep a record of which human added which service account to which property and when. That line in the runbook resolves most handover questions. Once delegation shows Owner, you are ready for a safe first test. The next section runs one publish and one status check with minimal quota use.

google cloud project indexing api delegation showing service account added as Owner in Search Console <!-- IMAGE-PROMPT diagram-01: 1600px max, DependsIt brand mint #22E3B0 on charcoal #121212 or white, node-network line art, subject: service account email delegation to Search Console property Owner role diagram, flat vector, accessible, no em dash, Clash Display and General Sans feel --> google cloud project indexing api diagram: to prepare before you, enable the indexing api, connect the service account <!-- IMAGE-PROMPT diagram-02: 1600px max, DependsIt brand, subject: lifecycle loop with 4 stages and return arrow about What to prepare before you click anything | Enable the Indexing API in the API library |, flat vector, accessible, no em dash -->

Run a safe first test call

Test with the smallest possible footprint: one publish for URL_UPDATED on your safe test URL, then one getMetadata check for the same URL. Use cURL first, because it shows HTTP status and JSON clearly without client library magic. You will need an access token derived from the JSON key. The easiest manual path is to use gcloud or a small OAuth helper to mint a token, then call the publish endpoint with that token. Do not paste the JSON key into the command line. Store it as a file with restricted permissions and reference it by path.

# Mint a token from the service account key, then publish one URL
export GOOGLE_APPLICATION_CREDENTIALS="/secure/path/indexing-publisher.json"
export TEST_URL="https://example.com/jobs/test-page-123"
gcloud auth activate-service-account --key-file="$GOOGLE_APPLICATION_CREDENTIALS"
export TOKEN="$(gcloud auth print-access-token)"
curl -s -X POST "https://indexing.googleapis.com/v3/urlNotifications:publish" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"url\": \"$TEST_URL\", \"type\": \"URL_UPDATED\"}"

Expected success returns HTTP 200 with JSON containing urlNotificationMetadata, including the URL, latestUpdate with type URL_UPDATED and notifyTime. Save that response. Then check status with getMetadata to confirm Google recorded the notification. The endpoint uses a query parameter with the encoded URL. A 200 here with matching notifyTime proves the round trip works.

# Check what Google recorded for the test URL
curl -s -G "https://indexing.googleapis.com/v3/urlNotifications/metadata" \
  -H "Authorization: Bearer $TOKEN" \
  --data-urlencode "url=$TEST_URL"

If you prefer Python for the first test, use the official client so JWT signing and refresh are handled. This snippet publishes one URL and prints the response. It uses the same key file and the same test URL, so results are comparable to the cURL test.

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

KEY_PATH = os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", "/secure/path/indexing-publisher.json")
TEST_URL = "https://example.com/jobs/test-page-123"
SCOPES = ["https://www.googleapis.com/auth/indexing"]

creds = service_account.Credentials.from_service_account_file(KEY_PATH, scopes=SCOPES)
service = build("indexing", "v3", credentials=creds)
resp = service.urlNotifications().publish(body={"url": TEST_URL, "type": "URL_UPDATED"}).execute()
print(resp)

Success criteria are simple. Publish returns 200, getMetadata returns matching URL and recent notifyTime, quota dashboard shows one publish used, and your own log records URL, type, timestamp, status, and response. If any of those four disagree, trust the HTTP response first, then the quota graph, then getMetadata, in that order. getMetadata shows recent API activity, not full index state. A 200 means Google accepted the notification for crawling consideration. It does not mean the page is indexed or ranked. That distinction prevents false celebration and keeps reporting honest.

Quota note for testing: one or two calls use negligible quota. Do not bulk test with hundreds of URLs on day one. Confirm single URL success, then move to small batches with throttling. The next section covers the failures you are most likely to see at this stage and the exact fix for each, so you can move from first success to reliable automation without guessing.

Fix the setup errors you will likely see

Most setup failures fall into five buckets: wrong project, API not enabled, key mismatch, Search Console role, and token handling. Each has a distinct message. Read the full response body, not just the numeric code, because the message names the missing piece. For a deeper error catalog with 403, 429, and JWT cases, keep the fixes for 403, 429, and JWT failures open in a second tab while you debug.

403 permission denied almost always means Search Console delegation is missing or not yet propagated. Confirm the service account email is Owner on the exact property, confirm the test URL sits inside that property, and wait 15 minutes after any role change. Then retry once. If 403 persists, check that you are using the key whose client_email matches the delegated email. Teams often create two service accounts and delegate one while testing with the other. Compare the client_email in the JSON file to the email in Search Console Users and permissions character by character.

403 service disabled or API not enabled means the publish call hit a project where the Indexing API toggle is off. Confirm the active project in the console top bar, confirm project_id inside the JSON, and confirm indexing.googleapis.com appears in Enabled APIs for that project. If you use gcloud, print the active config and the service list. If they disagree, set the correct project and retry. Do not create a new key to fix an enablement problem. Keys do not enable APIs.

401 invalid credentials or invalid grant points to key handling. Common causes include an edited JSON file with broken line breaks in private_key, a revoked key, a system clock far off correct time, or a token minted for the wrong scope. Re download the key if you edited it, confirm system time with NTP, and confirm the OAuth scope is exactly https://www.googleapis.com/auth/indexing. In Python, pass scopes explicitly when loading credentials. In cURL manual flows, confirm the token was minted from the same key file you intend to use.

404 not found usually means a malformed endpoint or URL parameter. Confirm the publish path is exactly v3/urlNotifications:publish and the metadata path is v3/urlNotifications/metadata with url as query. Confirm the notified URL is absolute, public, and uses the correct protocol. Submitting a staging URL that is blocked by robots or auth will not produce a clean success signal. Test with a public URL on the verified property.

429 and quota exceeded mean you hit daily or per minute limits. New projects often allow around 200 publishes per day. Check Quotas page for actual values and check quota graph for spikes from retries. Stop hammering, wait for reset, then resume with throttling and exponential backoff. The fix is pacing, not new keys. Creating more projects to dodge quota violates intent and complicates audits.

Message patternLikely causeFix
403 permission deniedService account not Owner or not propagatedVerify delegation, wait 15 min, retry once
403 service disabledAPI not enabled in this projectEnable indexing.googleapis.com in correct project
401 invalid grantBroken key, wrong scope, clock skewRe download key, confirm scope, fix NTP
404 not foundWrong endpoint or bad URL paramCorrect path, use absolute public URL
429 quota exceededDaily or per minute limit hitPause, check quota graph, throttle resumes

Log every failure with timestamp, URL, status, response body, project ID, and key ID. That record turns a confusing stall into a one line diagnosis on the next run. If you see a new message not in this table, add it to your runbook with the fix you used. Over a quarter, that table becomes the most valuable page in your docs.

Organize multiple sites clients and environments

One project per site or per client scales best. Quota is per project, so isolation prevents one busy property from starving others. Logs stay readable because every entry belongs to one site. Access stays safe because you grant each service account only to its own Search Console properties. Naming should encode site, purpose, and environment, for example acme-jobs-indexing-prod and acme-jobs-indexing-test. Record project ID, project number, owner, Search Console properties, quota baseline, and key IDs in a registry table. That table is the first page you open during any incident.

Environments deserve separation. Keep prod, staging, and local test projects distinct. Staging can use a smaller quota and a test property, for example a staging subdomain verified separately in Search Console. Local development should use the test project key, never prod. In CI, inject the key via secrets, not via repo files. In deploy pipelines, submit only URLs that actually changed in that deploy, not the full sitemap on every build. That discipline keeps quota use proportional to real changes and avoids 429 spikes after routine deploys.

Agencies need an extra layer: a client registry plus a key rotation calendar. Each client row lists Cloud project, service accounts, Search Console properties, who approved access, and when keys were last rotated. Review quarterly. Rotate on staff changes and at least yearly. When a client leaves, remove the service account from Search Console, disable the project or delete keys, and archive logs. Do not reuse a departed client project for a new client to save clicks. Leftover IAM bindings and quota history create confusion and audit risk.

For enterprises with organization policy, place indexing projects in the correct folder from the start. Folder policies control who may enable services, create keys, or grant external access. Creating projects outside the approved folder to move faster causes policy blocks later that look like code bugs. Work with your admin once to define the approved pattern, then copy it for each new site. Document the folder path in the runbook alongside project IDs.

PatternWhen to useTradeoff
One project per siteMost teams, agenciesMore projects to track, cleanest quota and logs
One project per client with many sitesSmall agency, few URLs per siteShared quota risk, simpler admin
Prod plus test per siteTeams with CI and stagingDouble the projects, safest testing
Single shared projectSolo owner, one site, low volumeSimplest, but mixes test and prod quota

Access hygiene applies in every pattern. Grant least privilege in Cloud IAM, keep service accounts out of broad roles like Editor, and grant Search Console Owner only to the accounts that must publish. Review IAM and Search Console users together each quarter. Remove dormant accounts. The goal is a setup where any teammate can answer three questions in one minute: which project serves this site, which key is live, and how much quota remains today.

What to do right after setup quotas and first submissions

Once the test succeeds, shift from setup to steady operation. First, record your actual quota. Open APIs and Services, Quotas, select the Indexing API, and note publish per day and per minute for your project. New projects often show around 200 per day, but values vary. Treat that number as a hard budget. Build a simple queue that sends URLs one by one with a short delay, logs every response, and backs off on 429. Do not loop over thousands of URLs on day one. Start with new and updated job or livestream URLs from the last seven days, then expand as you learn real headroom.

Second, decide notification types correctly. Send URL_UPDATED when a supported page is created or meaningfully changed. Send URL_DELETED when a supported page is removed or permanently retired. Do not send URL_DELETED for temporary outages or for pages that moved with a redirect. For moves, update the canonical and notify the new URL as URL_UPDATED after the redirect is live. Keep your own history table with URL, type, timestamp, status, and response. That table lets you answer whether a URL was already notified and avoids duplicate sends that waste quota. For type semantics with examples, the notification guide is useful background reading.

Third, connect submissions to real events instead of manual runs. In WordPress, hook into publish and update actions for job post types. In custom stacks, emit from your CMS publish webhook or deploy pipeline only when a supported template changed. In static builds, diff the sitemap or content manifest and submit only changed URLs. In every case, filter to absolute public URLs inside the verified property, deduplicate, and throttle. A queue with persistence, for example a database table or a message queue, survives restarts and prevents loss during 429 pauses. Log request IDs where present.

Fourth, watch the first week closely. Check quota use daily, review 4xx errors for permission or URL issues, and review getMetadata for a sample of URLs to confirm notifyTime recency. If you see 403s after a quiet period, check whether Search Console roles changed or keys were rotated without updating the server. If you see 429s, reduce batch size and increase delay before requesting more quota. Quota increase requests are rarely the first answer. Efficient selection of URLs usually solves the pressure. For pacing patterns and safe bulk limits, the quota guide pairs well with this setup.

Task in first weekActionSignal of health
Quota baselineRecord daily and per minute limitsBudget written in runbook
Queue livePersistent queue with delay and loggingNo lost URLs on restart
Event wiringPublish hook emits only changed supported URLsSubmissions match CMS publishes
Error reviewDaily scan of 401, 403, 404, 429Zero persistent 4xx, rare 429 with backoff
Sample verificationgetMetadata on 10 URLsRecent notifyTime for each

Resist the urge to submit every historical URL at once. Backfills consume quota quickly and provide less value than steady notification of fresh changes. If a backfill is truly needed, pace it across days, prioritize revenue critical or time sensitive URLs, and pause when 429 appears. Steady, event driven submission beats bulk blasts for both quota health and crawl efficiency.

Keep the project healthy over time

Healthy projects share three habits: reviewed access, watched quota, and readable logs. Review access quarterly. List Cloud IAM members, service accounts, keys by age, and Search Console users per property. Remove accounts that no longer need access. Rotate keys yearly or on team changes, and test rotation in the test project first. Rotation should be a practiced routine: create new key, deploy to secrets, verify one publish, then disable old key, then delete after a week of clean operation. Document each rotation with date, actor, key ID, and verification result.

Watch quota as a trend, not a single number. Export daily publish counts to a sheet or dashboard. Alert when use exceeds 70 percent of daily budget or when per minute 429s appear. Correlate spikes with deploys, imports, or bulk edits. If a CMS migration suddenly notifies thousands of URLs, pause the queue, deduplicate, prioritize supported types, and resume with throttling. If growth is sustained, request a quota review only after proving efficient selection and backoff. Reviewers respond better to logs that show discipline than to requests that follow a flood.

Keep logs queryable. Store URL, type, timestamp, project ID, key ID, HTTP status, response body snippet, and retry count. Retain at least 90 days. That history answers the questions owners actually ask: did we notify Google about this URL, when, and what did Google say. It also speeds debugging because you can filter by status and see whether failures cluster by URL pattern, time window, or key. Archive logs with your regular backups. They contain URLs and timestamps but should not contain private keys or tokens. Scrub secrets before storage.

Maintenance calendar that works for small teams:

  1. Weekly: glance at quota use and error counts, confirm queue depth near zero.
  2. Monthly: review submission volume versus CMS publish volume, tune filters.
  3. Quarterly: audit IAM, Search Console users, key ages, and rotate if due.
  4. Yearly: review project naming, folder placement, and whether per site isolation still fits.
  5. On incident: record cause, fix, and prevention in runbook within one day.

Finally, remember scope honesty as you grow. The Indexing API remains documented for JobPosting and BroadcastEvent URLs. If your site expands into blogs or product catalogs, do not assume the same workflow covers everything. Keep sitemaps fresh, internal linking shallow, and canonicals clean for all content, and add IndexNow separately for engines that support it. A tidy Cloud project plus honest scope keeps expectations aligned and results measurable. That is the whole point of starting from scratch with care.

google cloud project indexing api diagram: create the project in, create a service account, run a safe first <!-- IMAGE-PROMPT workflow-02: 1600px max, DependsIt brand, subject: maintenance workflow queue quota logs key rotation cycle, flat vector, accessible, no em dash, mint #22E3B0 on charcoal #121212, node-network line art, Clash Display and General Sans feel -->

FAQ

Do I need a Google Cloud project if I only want to submit a few URLs?

Yes. Every Indexing API call belongs to a project that holds enablement, credentials and quota, so there is no keyless path for server calls. The good news is that one small dedicated cloud project for seo covers a few URLs as easily as many, and setup takes under half an hour once access is ready. Create the project once, enable the API, create one service account, delegate it in Search Console, and reuse that setup for all future submissions. The overhead is front loaded while ongoing use is a single queue with logging, monitoring and rotation.

Is the Indexing API free once the project exists?

API calls do not carry a per call fee under normal use, but the project still consumes real resources such as engineering time, monitoring, secrets management and maintenance. Quota is limited, usually around 200 publishes per day for new projects, so bulk work needs pacing and queueing. Check cloud project billing linkage in Console settings to confirm whether your organization requires a billing account for API enablement, even when usage itself stays free. Treat quota as the budget and engineering attention as the cost. If someone promises unlimited free submissions, they describe a workaround, not the documented API.

Why does my publish call return 403 even with a fresh key?

The most common cause is Search Console delegation, not the key itself. The service account email must be Owner on the exact property that contains the URL, and changes can take 10 to 15 minutes to propagate. Confirm the email matches character by character, confirm the URL sits inside that property, and confirm the row shows Owner rather than Pending or Full user. Retry once after waiting. If 403 persists, verify project_id in the JSON matches the project where the API is enabled, and confirm you waited for propagation plus matching IDs across console, key file and quota graphs before rebuilding keys.

Can I use one Cloud project for many websites?

You can, but one project per site or per client scales better for most operations. Quota is per project, so a shared project lets one busy site consume allowance needed by others. Logs also mix, which slows debugging and reporting. Separate projects keep quota, IAM and history isolated and make handover cleaner. Use a shared project only for a solo owner with one low volume site. Agencies should default to per client projects with clear names. The google cloud for developers docs show the same isolation pattern for staging versus production, and that guidance applies well when client work grows past a single property.

How is this different from IndexNow?

The Indexing API notifies Google about JobPosting and BroadcastEvent URLs with URL_UPDATED and URL_DELETED signals. IndexNow is an open protocol co developed by Microsoft Bing and Yandex that notifies participating engines about any URL change, using a key file hosted at your site root. Google does not support IndexNow. The two systems have separate credentials, quotas and endpoints. Many sites run both for full coverage: Indexing API for Google plus IndexNow for Bing, Yandex, Naver, Seznam and others listed on indexnow.org. Do not send IndexNow pings to Google or Indexing API notifications to Bing, because each endpoint only trusts its own proof method.

What should I automate first after the project works?

Automate event driven submission of new and updated supported URLs with deduplication, throttling and logging. Hook CMS publish events or deploy pipeline diffs so only changed URLs enter the queue. Store URL, type, timestamp, status and response for every attempt. Add exponential backoff on 429 and alerts at 70 percent of daily quota. Before you scale, open the console page where you google api enable services and confirm the Indexing API still shows enabled with expected quota for prod. Leave bulk backfills for later, paced across days with prioritized templates. That order delivers steady value without quota incidents or access surprises.

Sources

  • https://developers.google.com/search/apis/indexing-api/v3/prereqs
  • https://developers.google.com/search/apis/indexing-api/v3/quickstart
  • https://support.google.com/webmasters/answer/9008080
  • https://developers.google.com/search/docs/appearance/structured-data/job-posting
  • https://www.indexnow.org/documentation

Further reading

Put this into practice. Indexer submits URLs to the Google Indexing API and IndexNow, audits coverage with Search Console, and shows exactly which pages are indexed. Start free or see how it works.