Submit URL to Google: Manual, Sitemap, and API Routes

There are 3 ways to submit a URL to Google, and they are not interchangeable. The manual request inside Search Console is rationed. An XML sitemap is unlimited and patient. The push API accepts only 2 kinds of page, and a blog post is not one of them.

Most people pick a side and stay there. One group opens Search Console after every publish and spends the day’s ration on posts nobody was waiting for. The other group assumes the sitemap has it handled, then discovers months later that a third of the site never made the index at all.

Neither habit is the mistake. The channel choice is.

Submitting a URL is a queue ticket, not a verdict. Google’s own documentation on asking it to recrawl puts it flatly: requesting a crawl “does not guarantee that inclusion in search results will happen instantly or even at all.” What you do control is which queue a URL enters, how many you can push through before the door shuts, and whether the page survives the quality check waiting on the other side.

Submission Channels Compared

Every channel below either reaches Google or it does not, and the ones that do not are still worth running for a different search engine. The column that settles most arguments is the scale ceiling, because volume is where the manual habit falls apart.

ChannelWhat it reachesScale ceilingAuthReaches Google
Request Indexing in Search Console1 URL at a timeRationed and elastic, no published numberProperty owner or full userYes
XML sitemapThe whole site50,000 URLs or 50MB per fileNoneYes, the primary discovery route
Sitemap ping endpointNothingReturns 404NoneNo, retired
Google Indexing APIJobPosting and BroadcastEvent pages only200 publish calls a day by defaultService accountYes, inside that scope
IndexNowAny URL you own10,000 URLs per POSTKey file at your domain rootNo
Bing URL Submission APIAny URL you ownUp to 10,000 a day per domainBing Webmaster API keyNo
Cloudflare Crawler HintsCached URLs that changeAutomatic, no cap you manageDashboard toggleNo, it feeds IndexNow
Internal links from indexed pagesAny URL you ownNoneNoneYes

Read that bottom row twice. A contextual link from a page Google already crawls on a schedule is the only unlimited, unauthenticated, Google-facing submission channel on the list, and it is the one that never appears in a tutorial about submitting URLs.

Scale is what should pick the channel for you, not habit.

How many URLsUseBecause
1 page, and the delay costs moneyRequest IndexingThe fastest path you personally control, and the ration is irrelevant at this volume
A handful a weekSitemap with honest lastmod, plus 2 or 3 internal linksKeeps the manual ration in reserve for the pages that need it
Dozens on a publishing scheduleIndexNow fired on publish, sitemap underneathThe only route that scales without a quota conversation
Thousands after a migrationSplit sitemaps by section, monitor with the URL Inspection APIAt this size you need measurement more than submission
Job listings or livestreamsGoogle Indexing APIThe only content Google’s push API is built to accept

The middle row is the one people get wrong. Publishing at volume is exactly when they reach hardest for the manual button, and exactly when it stops being available.

What Submission Buys You

It buys discovery. Nothing else.

Google’s pipeline runs in 3 stages that people collapse into one word. Crawling is a fetch. Indexing is a decision about whether the fetched page belongs in the database. Ranking is a separate decision about where it sits for a given query. Submitting a URL only touches the first stage, and it does it by moving your page up a priority queue rather than by adding it to anything. The rest of the machinery is covered in more depth in this breakdown of how search engines work.

Diagram showing Request Indexing, XML sitemap, internal links and the Indexing API converging into discovery, then crawl, then the index decision that no submission channel reaches past

The timing expectation most guides publish is also wrong. Google’s documentation says crawling “can take anywhere from a few days to a few weeks,” and that “requesting a recrawl multiple times for the same URL won’t get it crawled any faster.” Every article promising a 24 hour turnaround is describing a good day on an established site and selling it as a rule.

So resubmitting is not persistence. It is a no-op that feels like work.

Submitting a Single URL in Search Console

Paste the URL into the inspection bar at the top of Search Console, wait for the check, click Request Indexing. That is the entire mechanic. I keep it for pages where an hour of delay has a price attached: a pricing change, a corrected safety claim, a launch, a legal update. Everything else can wait for the sitemap.

The part nobody warns you about is the ration.

Google does not publish a number, and the limit is not a simple daily count. It responds to request load, which means it can trip far earlier than the folklore figure suggests.

The editor of Mountain Weekly News, a publication carrying more than a thousand technical gear audits, hit a “Quota Exceeded” wall after 5 requests.

5 requests. On a property with a 24 year history.

Treat the manual request as a scarce resource with no visible balance, because that is what it is.

If you want the full diagnostic surface of that panel, including what each Coverage line means and how the Live Test differs from the indexed state, the GSC URL Inspection tool guide covers it properly. This page is about which channel to reach for, not which button.

Submitting a Sitemap to Google

A sitemap is the only submission you make once. Add it in the Sitemaps section of Search Console, or declare it in robots.txt, and Google rechecks the file on its own schedule from then on.

# robots.txt, last line
Sitemap: https://example.com/sitemap_index.xml

That single line is the reason a sitemap works for sites that never open Search Console at all. Discovery does not require an account.

What died is the ping.

For years every CMS fired an HTTP request at a Google endpoint whenever a sitemap changed, and plugins still ship code that does it. Google deprecated that endpoint and it now answers 404. If your build script pings it, the request is not failing loudly, it is failing silently and has been for a long time.

Which leaves lastmod doing the work the ping used to do. It is the one field in a sitemap Google will act on, and the one most sites quietly corrupt. Any plugin or generator that stamps today’s date on every URL in the file has told Google that 4,000 pages changed at once, and the honest response to that signal is to stop trusting the field. Most WordPress SEO plugins get this right by default; the failure mode usually arrives with a custom generator or a static site build that writes the build timestamp into every entry.

Keep the file honest and small.

Google accepts 50,000 URLs or 50MB uncompressed per file, and splitting by post type keeps a broken section from poisoning the whole index. Leave tag archives, author pages, and attachment URLs out of it, which your SEO plugin can do in a checkbox.

A sitemap listing pages you would not want indexed is not a sitemap. It is a crawl budget leak with an XML extension.

Submitting URLs Through an API

3 APIs sit around this problem and they do 3 different jobs. Google’s Indexing API pushes, IndexNow pushes to everyone except Google, and the URL Inspection API cannot push at all.

Picking the wrong one wastes a service account setup.

The Google Indexing API is narrower than the internet thinks. Google’s documentation states it “can only be used to crawl pages with either JobPosting or BroadcastEvent embedded in a VideoObject.” The default allowance is 200 publish calls a day per project, and anything beyond that goes through an approval form tied to whether your site genuinely uses those schema types. Plenty of plugins will still happily fire blog post URLs at it.

That is a guidelines violation with a quota review attached, and it is a strange thing to build a publishing workflow on.

IndexNow is the one you can automate freely, and it does not reach Google. Bing, Yandex, Naver, Seznam and Yep consume the protocol. Google has watched it since launch without adopting it. That is still worth wiring up, because Bing feeds Copilot and a share of the assistant traffic that never touches a Google result, but do not install it expecting Google to move.

Setup is 3 steps and no account.

# 1. Generate a key: 8 to 128 hexadecimal characters
KEY=$(openssl rand -hex 16)

# 2. Publish it at the domain root, containing nothing but the key itself
echo "$KEY" > /var/www/example.com/public/$KEY.txt

# 3. Push up to 10,000 URLs in a single POST
curl -sS -X POST https://api.indexnow.org/indexnow \
  -H "Content-Type: application/json; charset=utf-8" \
  -d "{
    \"host\": \"example.com\",
    \"key\": \"$KEY\",
    \"keyLocation\": \"https://example.com/$KEY.txt\",
    \"urlList\": [
      \"https://example.com/first-post/\",
      \"https://example.com/second-post/\"
    ]
  }"

The key file is the whole ownership proof, which is why a 403 means the file is missing or does not contain the key, and a 422 means the URLs do not belong to the host you claimed. A 202 is normal: the submission landed and key validation is still running.

On Cloudflare you can skip all of it. Crawler Hints in the Caching settings watches for cache misses on changed content and fires IndexNow for you, which is the right amount of effort for a channel Google ignores.

The URL Inspection API is the one I would wire up first. It cannot request indexing at all. What it does is return the same status record the Search Console panel shows, at 2,000 calls a day and 600 a minute per property, which is enough to hold a real site under continuous observation instead of spot-checking it by hand.

from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession

SITE = "sc-domain:example.com"
ENDPOINT = "https://searchconsole.googleapis.com/v1/urlInspection/index:inspect"

creds = service_account.Credentials.from_service_account_file(
    "service-account.json",
    scopes=["https://www.googleapis.com/auth/webmasters.readonly"],
)
session = AuthorizedSession(creds)


def inspect(url):
    r = session.post(
        ENDPOINT,
        json={"inspectionUrl": url, "siteUrl": SITE},
        timeout=30,
    )
    r.raise_for_status()
    return r.json()["inspectionResult"]["indexStatusResult"]


for url in open("urls.txt").read().split():
    s = inspect(url)
    if s.get("verdict") != "PASS":
        print(
            url,
            s.get("coverageState"),
            s.get("pageFetchState"),
            s.get("googleCanonical"),
            sep=" | ",
        )

One setup detail eats an afternoon if you miss it: the service account has its own email address, and that address has to be added as a user on the Search Console property before any of this returns data. The API does not inherit your personal access.

Someone reviewing a web analytics dashboard on a laptop, the measurement habit that replaces manual resubmitting at scale
Photo by Myriam Jessier on Unsplash

The response fields are where the diagnosis lives, and 2 of them almost nobody reads.

FieldValue that passesWhat a failing value tells you
verdictPASSPARTIAL or FAIL means one of the checks below has already failed
robotsTxtStateALLOWEDDISALLOWED, a robots.txt rule covers this path
indexingStateINDEXING_ALLOWEDBLOCKED_BY_META_TAG or BLOCKED_BY_HTTP_HEADER, something on your side is saying no
pageFetchStateSUCCESSFULSOFT_404, SERVER_ERROR, REDIRECT_ERROR, the fetch itself broke
googleCanonicalMatches userCanonicalA mismatch means Google folded this page into a different URL
lastCrawlTimeRecentOld or absent, the page is not in the crawl rotation
referringUrlsNot emptyEmpty, no indexed page links here, which is an internal linking bug
sitemapNot emptyEmpty, the URL never made it into a submitted sitemap

The last 2 rows are the useful ones. An empty referringUrls array on a page you believed was well linked is a measurable fact about your internal linking, not a feeling about it, and a googleCanonical that disagrees with yours explains a whole category of pages that look fine and index as something else.

Automating Submission on Publish

Anything you have to remember after publishing will eventually not get done. On WordPress the hook you want is transition_post_status, because it fires on the actual state change and lets you ignore updates to already-published posts.

Code editor open on a web project template file, the kind of build where a publish step can fire a submission automatically
Photo by Mohammad Rahmani on Unsplash
add_action( 'transition_post_status', 'gl_indexnow_on_publish', 10, 3 );

function gl_indexnow_on_publish( $new_status, $old_status, $post ) {
    if ( 'publish' !== $new_status || 'publish' === $old_status ) {
        return;
    }
    if ( ! in_array( $post->post_type, [ 'post', 'page' ], true ) ) {
        return;
    }

    $key = get_option( 'gl_indexnow_key' );
    if ( ! $key ) {
        return;
    }

    wp_remote_post( 'https://api.indexnow.org/indexnow', [
        'headers'  => [ 'Content-Type' => 'application/json; charset=utf-8' ],
        'timeout'  => 5,
        'blocking' => false, // never make an editor wait on a third party
        'body'     => wp_json_encode( [
            'host'        => wp_parse_url( home_url(), PHP_URL_HOST ),
            'key'         => $key,
            'keyLocation' => home_url( "/{$key}.txt" ),
            'urlList'     => [ get_permalink( $post ) ],
        ] ),
    ] );
}

'blocking' => false is the line that keeps this out of your editors’ way. Without it, every publish click waits on somebody else’s API before the admin screen comes back.

On a static site the same job belongs in the deploy, where you already know exactly which files changed.

name: Notify IndexNow
on:
  push:
    branches: [main]

jobs:
  submit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 2

      - name: Collect added and modified content URLs
        id: urls
        run: |
          git diff --name-only --diff-filter=AM HEAD^ HEAD -- 'content/**/*.md' \
            | sed 's|^content/|https://example.com/|; s|\.md$|/|' \
            | jq -R -s -c 'split("\n") | map(select(length > 0))' > urls.json
          echo "list=$(cat urls.json)" >> "$GITHUB_OUTPUT"

      - name: Submit
        if: steps.urls.outputs.list != '[]'
        run: |
          curl -sS -X POST https://api.indexnow.org/indexnow \
            -H "Content-Type: application/json; charset=utf-8" \
            -d "{\"host\":\"example.com\",
                 \"key\":\"${{ secrets.INDEXNOW_KEY }}\",
                 \"keyLocation\":\"https://example.com/${{ secrets.INDEXNOW_KEY }}.txt\",
                 \"urlList\":${{ steps.urls.outputs.list }}}"

The --diff-filter=AM flag is doing the quiet work here: it submits what you added or modified and stays silent about deletions and renames, so a routine refactor does not announce 400 URL changes you did not make. If you are wiring this into a WordPress build instead, the WordPress REST API guide covers the authentication side.

Automate the push, then stop thinking about it. The push was never the hard part.

Why Submitted Pages Still Do Not Get Indexed

Because submission was never the constraint. Indexing Insight monitored 1.7 million pages across 18 websites and pulled the verdicts through the URL Inspection API, and the split came out lopsided in a way that reorganizes the whole problem:

  • 88% of not-indexed pages failed for quality reasons
  • 12% failed for technical reasons, the category most audits spend their time on
  • “URL is unknown to Google” and “Discovered, currently not indexed” together made up 67% of the quality bucket
  • Index coverage ran about 97% for news sites, under 90% for ecommerce, and under 70% for marketplace and listing sites
  • Across small through large brands, coverage clustered between 85% and 91%
Proportion bar showing 88 percent of not-indexed pages fail on a quality decision and 12 percent on technical issues, with 67 percent of the quality group unknown to Google or discovered but not indexed

Treat that last figure as a ceiling, not a failure. Even well-run sites leave roughly a tenth of their pages outside the index, which means a coverage gap is normal and only becomes a problem when it lands on pages that matter.

The submission tools fare no better.

A separate IndexCheckr analysis of 16 million pages found 61.94% not indexed overall, and URLs pushed through indexing tools reached a 29.37% success rate. So roughly 7 in 10 submitted pages stayed out anyway.

I have my own version of that number. A programmatic build on one of my own sites shipped 748 pages, every one of them discovered and submitted correctly. Over the following 90 days, 429 of them drew zero impressions and the whole set returned 13 clicks. The full breakdown of that experiment is worth reading if you are about to scale a template, because nothing in the submission layer was broken.

The pages were.

Bar chart comparing 61.9 percent of all studied pages not indexed against 70.6 percent of URLs pushed through an indexing tool, alongside a 748 page first-party result

Volume multiplies whatever signal you already had. If that signal is weak, faster submission just gets you rejected sooner.

Using AI to Diagnose a Stuck URL

An LLM cannot see Google’s index. It can read the evidence you hand it, and the quality of that evidence decides whether you get a diagnosis or a horoscope.

Most people hand it nothing.

What most people do:

Here is my article. It is not getting indexed by Google. Can you improve it so it ranks?

What works better:

Below is the URL Inspection API record for a page that is not indexed. Classify the blocker as technical or quality using this rule: any value other than PASS, ALLOWED, INDEXING_ALLOWED or SUCCESSFUL is technical and must be fixed before anything else. If every field passes and coverageState still reports the page as not indexed, the blocker is quality. Name the single field that decided your answer, name what evidence would change it, and say nothing about content until you have ruled out the technical path.

Same model, same page. The second prompt cannot produce a content rewrite for a page that is actually returning a soft 404, because you gave it a rule that has to be cleared first and the fields to clear it with.

Once the technical path is ruled out, the useful second pass is a gap diff rather than a rewrite request. Hand the model your page alongside the pages Google is currently surfacing for the query and ask which specific claim, number, comparison or artifact exists only in theirs. That answer is short, concrete, and usually uncomfortable. It is also the only version of “improve the content” that produces an edit list instead of an adjective.

If you want the loop to run without copy and paste, several Search Console MCP servers now expose inspect_url, sitemap status and search analytics directly to an assistant, so the diagnosis and the evidence live in the same window. Read-only ones are the sane default.

An agent with write access to your property is a bad trade for saving 3 clicks.

The boundary matters more than the technique.

A model handed a clean status record is doing classification, which it is good at. A model handed a vague complaint is doing improvisation, which is where confident wrong answers come from.

Feed it fields, not feelings.

Indexing Is the Gate for AI Answers

This is the part that changed the stakes. Google’s guidance on optimizing for generative AI features states that a page has to be indexed, eligible to show a search snippet, and reachable by Googlebot before it can appear in AI Overviews or AI Mode. There is no separate AI index, no AI-specific schema, and no llms.txt shortcut that routes around it.

So an unindexed page is not just missing from the blue links. It is invisible to the answer box that increasingly replaces them.

The retrieval layer behind those answers pulls from the same Search index, which is why the AI Overviews citation playbook reads like ordinary SEO with tighter evidence requirements. Nothing exotic gets you in.

Being indexed gets you eligible.

Worth separating from all of this: the assistants outside Google run their own fetchers. Getting indexed by Googlebot says nothing about whether ChatGPT or Perplexity can reach your pages, and a CDN rule written to stop scrapers often stops the retrieval crawlers too. That is a distinct access problem, covered in this breakdown of AI crawlers and what blocking them costs.

The Limits

Submission cannot make a page worth indexing. The quality decision happens after the crawl, using signals the submission channel never touches, which is why a thin page submitted 10 times behaves exactly like a thin page submitted once.

There is also no unlimited Google-facing push channel for ordinary pages, and there is unlikely to be one. Every route that scales, IndexNow and the Bing API, stops at Google’s door, and the route that reaches Google either rations you or restricts you to job listings and livestreams.

If your plan depends on pushing thousands of blog URLs into Google on demand, the plan has no mechanism.

The URL Inspection API will also not tell you why a quality rejection happened. It returns state, not reasoning. When coverageState says “Crawled, currently not indexed” and every other field passes, you have confirmed the blocker is quality and learned nothing about which part, so the diff against the pages Google did choose is still manual work you have to do.

And indexed is not permanent. Pages drop out of the index later, without an error state and without a notification, which means coverage is something you monitor rather than something you achieve.

Set the check on a schedule or you will find out from a traffic report instead.

What Quietly Ruins Indexing

Resubmitting the same URL every few days feels like pressure on Google. Google has said directly that it changes nothing, so the only thing it reliably burns is the ration you will want later for a page that genuinely matters.

Letting a generator stamp today’s date on every lastmod in the sitemap looks like freshness. It teaches Google that your dates carry no information, and once that field stops being trusted you have lost the one signal a sitemap can send.

Running 2 plugins that each manage an IndexNow key is a quiet one. The second plugin writes its own key file, the first keeps submitting the old key, and every push comes back 403 while both dashboards report success.

Tightening a firewall or bot rule at the CDN and never testing what it caught is how sites lock out the crawlers they were trying to attract. The rule is invisible from inside WordPress, the coverage decline arrives weeks later, and nobody connects the two.

Treating index coverage as a traffic metric is the most common one of all. 100% coverage on pages nobody searches for is a well-organized way to be ignored, and chasing that number pulls attention away from the handful of URLs whose absence you would feel.

Publishing more to fix a coverage problem makes it worse. A site that is already leaving pages outside the index is telling you its per-page signal is thin, and adding volume to a thin signal is how you end up with 748 pages and 13 clicks.

FAQs on Submitting URLs to Google

Not directly. Google retired the public submit-a-URL form years ago, and every remaining push channel requires verified ownership. What you can do without an account is make the page discoverable: declare your sitemap in robots.txt, and link to the page from another page Google already crawls. Both work without logging into anything.

Google does not publish a number for manual Request Indexing, and it is not a fixed daily count. The allowance responds to request load, so it can stop you after a handful on one day and let more through on another. Plan around it being scarce rather than around any figure you read, and route volume through your sitemap instead.

No. Google states that requesting a recrawl multiple times for the same URL will not get it crawled any faster. If a page is still missing after the first request, the answer is in the URL Inspection status fields or in the page itself, not in another submission.

No. Google’s documentation limits it to pages carrying JobPosting or BroadcastEvent embedded in a VideoObject, and quota approval is tied to whether your site actually uses those types. Plugins that submit ordinary posts through it are pushing you outside the documented scope for a channel Google can review.

Through a sitemap, which is the only bulk channel Google offers for ordinary pages. A single sitemap file carries up to 50,000 URLs or 50MB uncompressed, and you submit it once. IndexNow handles bulk pushes at 10,000 URLs per request, but it reaches Bing, Yandex, Naver, Seznam and Yep rather than Google.

Yes, on every channel. Search Console, sitemaps, the URL Inspection API, the Indexing API and IndexNow all cost nothing. Paid indexing services are reselling these same routes, usually the ones with no Google-facing effect, so check which channel you are buying before you pay for it.

Final Remarks

If you want a concrete next step, run the URL Inspection API across your published URLs once and sort the failures by coverageState. That single pass separates the pages with a technical blocker you can fix this week from the ones carrying a quality verdict, and it usually finds a canonical or robots surprise nobody knew about. The Search Console audit workflow covers the rest of the sweep, and bulk 404 triage handles the debris it turns up.

The reason submission feels unsatisfying is that most people are treating a selection problem as a discovery problem. Google usually knows the page exists. It has read it, weighed it against everything else competing for the same query, and declined.

No channel on this page argues with that decision, and the ones promising to are selling you a queue ticket you already had for free.

There is a trade, though. Automating the push costs an afternoon and buys back every publish day you would have spent clicking, and it moves your attention to the part that actually decides the outcome.

Submit once, wire it up, and spend the rest of your time on the page.

Tell Google you want more of this.

Add Gatilab as a preferred source

One tap, and this site shows up more often in your own Top Stories, AI Overviews and AI Mode. Remove it any time.