Google Indexing API for jobs — the parts the docs leave out

A reliable irritation among job board operators: you post a fresh role at 9am, the employer’s keen, candidates are searching for exactly that title — and Google takes until Thursday to index the page. By the time you rank, the role is half-staffed.

Google’s published answer is the Indexing API. It’s free, well-documented, and stable since 2018. Used correctly, it pushes new and updated JobPosting URLs into Google’s index in 5–30 minutes rather than 1–3 days. Used incorrectly — which is most boards I’ve audited — you’ll burn quota submitting URLs Google silently ignores, hit a daily ceiling that isn’t actually meant for production use, and conclude the API doesn’t work.

Where Google’s documentation confirms a detail, I’ll say so plainly. Where the only evidence is operator forums or my own testing, I’ll flag it.

What changed in September 2024

Three things shifted, none announced loudly. All matter.

1. The 200/day default is now explicitly for testing. The docs were updated to call it “initial API onboarding and submission testing.” Production use without an approved quota lift is now formally out of policy. In practice Google doesn’t appear to block boards that exceed 200/day with an unapproved quota — but the language change matters for compliance reviews.

2. Multiple service accounts are now banned as a quota workaround. Google added: “Any attempts to abuse the Indexing API, including the use of multiple accounts or other means to exceed usage quotas, may result in access being revoked.” This was a known operator trick pre-2024; it’s now grounds for losing API access.

3. Approved quota now floats with document quality. “The quota may increase or decrease based on the document quality.” Read: if your listings get thin, expire-heavy, or schema-invalid, Google can quietly cut your approved quota. Operators who got 5,000/day in 2023 have reported drops back to defaults after content quality reviews. The quota lift is not a one-time grant.

If your integration was built before September 2024 it’s worth a review.

What the API actually does

Authenticate with a service account JSON key (Google Cloud, IAM scope https://www.googleapis.com/auth/indexing), then call one of three endpoints:

  • urlNotifications:publish — submit one URL with type: URL_UPDATED (new or edited listing) or type: URL_DELETED (closed)
  • urlNotifications:batch — different endpoint URL (https://indexing.googleapis.com/batch), multipart/mixed encoding, up to 100 URLs per HTTP request
  • urlNotifications/getMetadata?url=... — check when Google last received your update for a given URL

That’s the whole surface. No webhooks, no async callbacks, no crawl status — just an acknowledgement and a timestamp.

The trade-off vs the other two indexing paths Google offers:

SitemapURL Inspection APIIndexing API
Time to crawl1–3 days typicalMinutes (manual, per URL)5–30 minutes
Content typesAllAllJobPosting + BroadcastEvent only
Daily quotaNone2,000200 default (lift via form)
Per-minuten/a600380 across all endpoints
AuthJust host the fileOAuth via Search ConsoleService account
Best forDiscovery, rulesSpot-checks, debuggingProduction indexing of fresh roles

The Indexing API isn’t a sitemap replacement. Keep your sitemap; layer the API on top for the time-sensitive fresh-role surface.

Three quotas, not one

The 200/day publish ceiling gets all the attention, but there are three:

  • 200 publish calls per day per project (URL_UPDATED + URL_DELETED combined)
  • 180 metadata read requests per minute per project
  • 380 total requests per minute per project across all endpoints

Quotas reset at midnight Pacific Time, not UTC. European boards setting cron jobs against UTC lose half a day of quota until they fix it.

The 180/min and 380/min limits are where most bulk imports break. A board doing a 500-URL bulk import via single calls will hit the 380/min ceiling at request ~382 and get 429s for the rest of that minute — even if daily quota remains. The batch endpoint is the fix; it doesn’t reduce the daily count, but it reduces per-minute pressure to zero.

Eligibility: what Google silently ignores

The API supports only JobPosting and BroadcastEvent (a livestream embedded in a VideoObject). Anything else is silently dropped. The API call returns success, your quota gets decremented, and Google ignores the URL.

The boards I’ve audited submit these in roughly this order of frequency, all of which Google drops:

  • Category index pages (/jobs/customs)
  • Employer profile pages (/employers/maersk)
  • Blog posts (/blog/best-logistics-jobs-2026)
  • Landing pages and homepages
  • Pages that will have JobPosting schema but 404 right now because of a build-pipeline race

If you’re not seeing the indexing speed-up you expected, the first thing to check is what your CMS is firing the API for. The single most common cause of “the API doesn’t work” tickets is wasted quota on non-JobPosting URLs.

Four mistakes that waste integrations

1. Submitting blog posts, category pages, and landing pages. This is the single biggest waste, and the most common cause of “the API doesn’t work” tickets. The API only accepts JobPosting (and livestream BroadcastEvent) URLs. Anything else — blog posts, category indexes, employer profiles, your homepage, salary guides — gets silently dropped, but the quota slot is still spent. Most CMS-based integrations fire the API on any page publish or edit by default. Audit yours: it should fire only for listing detail pages with valid JobPosting JSON-LD on them. Nothing else.

2. Skipping URL_DELETED on listing close. When a role expires, most boards 404 or redirect. The crawler eventually catches up — but it can take weeks, and during that window your SERP results link to dead listings, hurting CTR and ranking. URL_DELETED clears the URL within hours. Free, instant, and the lever that protects you from the portfolio penalty below.

3. Submitting on every edit. CMS field changes — a typo fix, a description tweak — often fire the API. Five edits to one listing in an afternoon is five quota slots gone. Dedupe: only fire URL_UPDATED when a meaningful field changes (title, salary, location, deadline, employment type, application URL). Cosmetic edits don’t need it.

4. Single requests instead of batching. A 50-role morning publish via single calls is 50 HTTP round trips against the 380/min ceiling. Batching collapses to 1 round trip (50 still counts against daily quota, but per-minute pressure drops to zero).

The portfolio penalty (the one most articles skip)

Boards with high rates of expired-but-still-indexed listings see site-wide visibility reduction in Google search results — not just on the dead URLs. Google’s signal: if your listings expire faster than they get fresh applicants, the board is stale, and that signal applies to your domain, not just the closed roles.

A board with 10,000 listings where 30% are expired-but-indexed will rank worse on its 7,000 live listings than a board of 5,000 all-live listings. Cleaning up expired URLs isn’t janitorial work; it’s ranking signal hygiene.

The Indexing API’s URL_DELETED is the fastest tool for this, and it’s the reason most operators should prioritize closures equally with new publishes — not as an afterthought.

About that quota-lift form

The form exists. The docs link to it. Many operators have submitted it. Here’s the part every other guide leaves out:

  • Google publishes no response-time SLA. None.
  • Many operators report no response at all — sometimes after months of waiting. Multiple threads on Google’s own Search Central community show requests pending indefinitely with no Googler reply.
  • There is no published approval rate or rejection criteria. The docs say “may increase or decrease based on document quality” without defining quality.
  • Paid Google Cloud Support has limited leverage. The Indexing API isn’t a billed product, so there’s no support SLA tied to it.

If you’re an operator who needs production-scale indexing and the form goes nowhere, here’s how to operate inside the 200/day default — durably:

Prioritize ruthlessly. New listings first, deletes second (they protect ranking), updates last. If you publish 50 new + need to delete 20 + want to update 100 in a day, the order is: 50 new + 20 deletes + however many updates fit. Updates are the cheapest to defer.

Dedupe by URL within a 6-hour window. Cache the last-submitted timestamp per URL. If the same URL fires twice in a day, send it once. Most boards send the same listing 3–4 times without realizing.

Use the batch endpoint. Daily quota is the same; per-minute pressure becomes a non-issue. Few CMS-based boards do this by default.

Don’t try multi-account workarounds. Since late 2024 it’s a fast path to losing API access entirely.

Keep the sitemap healthy as a safety net. For listings that don’t fit your daily quota, make sure they’re in the sitemap and the sitemap pings on update. Sitemap discovery is 1–3 days but it’s still your floor.

Re-submit the form annually with usage data. The operators I know who’ve gotten approvals — rare, but real — attached:

  • Specific volume needed (“we publish 1,200 fresh JobPosting URLs per day”)
  • Structured-data testing tool screenshot showing zero validation errors across sampled URLs
  • A clean, current sitemap
  • Search Console showing real traffic on JobPosting URLs

It’s not a guarantee. Approval rates are genuinely low. But submitting once and giving up is worse than re-submitting annually with concrete evidence.

A minimal working integration (Python)

The actual code is small. The wiring around it — the build-pipeline hook, the dedupe cache, the priority queue — is where most boards trip up.

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

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

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

def notify(url: str, deleted: bool = False) -> dict:
    body = {
        "url": url,
        "type": "URL_DELETED" if deleted else "URL_UPDATED",
    }
    return service.urlNotifications().publish(body=body).execute()

# Fire from the end of your build pipeline, after the page is live:
notify("https://logisticsrecruit.com/jobs/customs-broker-12345")

# Fire on listing close or expire:
notify("https://logisticsrecruit.com/jobs/warehouse-lead-7890", deleted=True)

Wrap that in a dedupe layer (one call per URL per 6 hours), a priority queue (new + deletes ahead of updates), and a hook into your build pipeline that fires after the static page is live. ~120 lines total in any language.

What the API doesn’t do

Two things:

  • It doesn’t improve ranking. It only improves speed-of-index. A fast-indexed but poorly-structured listing won’t outrank a slowly-indexed well-structured one.
  • It doesn’t bypass schema validation. Submit a URL whose JobPosting JSON-LD is missing required fields and Google indexes the URL but won’t surface it in JobPosting-eligible search experiences. Run the structured data validator first.

Worth doing

For boards publishing more than a handful of new roles a day, the integration takes an afternoon to get right and saves 1–2 days per listing in time-to-index. Over a year that’s the difference between competing for “posted today” traffic and competing for “posted a week ago.”

The constraints are real. 200/day is often all you’ll get, the quota-lift form rarely comes back, and Google can quietly down-rank approved quota if content quality slips. Inside those constraints, the API still beats every other indexing path for JobPosting content.

The boards that win on speed-to-index aren’t the ones with the highest quotas. They’re the ones who treat the 200/day default as the constraint and engineer around it.