How to Ping IndexNow Automatically After a Vercel Deploy, Using GitHub Actions

This is a how-to for a site that lives on Vercel and GitHub. If you use another host, read for the idea, then wire it your way. You should not paste IndexNow links by hand after every ship. When Vercel finishes a production deploy, GitHub Actions looks at what changed, picks those page links, and sends only those to IndexNow. That happens by itself. A preview deploy does not send anything. Change one page, one link goes out. Change a thousand pages in the same ship, about a thousand links go out together.

Published on

Share:

IndexNow is a push. When a page changes, your site tells search engines that use IndexNow the exact link. You do not wait for a bot to stumble onto it later. If you want what the ping is, who hears it, and how a small file on your site proves you own it, start with what IndexNow is. This post is the next step: make that ping happen by itself after the live site updates, and only for the pages that actually changed. Here, a ship means putting a new version of the site live.

This is the setup this site uses. The live site runs on Vercel. The code lives on GitHub. When Vercel finishes updating the live site (Vercel calls that Production, and it succeeded), GitHub starts a job. That job runs a small script we wrote. The script compares that version to the last live version, turns changed files into public page links, and sends only those links to IndexNow. A test copy of the site (a preview) does not ping. Shared code that is not a page does not ping. You do not paste a list. This does not run when someone opens a page, so it does not slow the site or affect Core Web Vitals (CWV).

Who this is for

These steps are for a site that goes live on Vercel from a GitHub code folder, the same way this one does. That pairing is what the job waits for: Vercel tells GitHub the live site just updated, and the job treats Production success as “the live site just updated.”

If your site is not on Vercel and GitHub, keep the idea and change the setup. The idea is: wait until the live site is actually updated, compare that version to the last live version, turn changed files into page links, then send those links to IndexNow. Do not copy this Vercel-and-GitHub job onto a site that never sends that “live site updated” message.

The problem a hand ping creates

Pasting links by hand fails in three boring ways. You forget. You paste yesterday’s link and miss today’s. Or you send every page on the site every time, including pages that did not change.

This site still has a separate button for a rare “send the whole site” ping or one hand-picked link. Everyday updates should not use it. After each live update, the GitHub job is the path. That is the whole point of automatic plus streaming: no paste, and no “send everything.”

Automatic vs. streaming, in plain words

Automatic means you do not paste links or submit them by hand/manually. Finishing a live-site update is what starts it. The job runs on GitHub’s computers, not in the visitor’s browser, and not on a clock that re-sends every page at dawn.

Streaming here means the list matches that update. Change one page, one link goes out. Change a thousand pages in the same update, about a thousand links go out together. IndexNow’s published limit is 10,000 links in one send; the script keeps the first 10,000 and drops the rest. A preview (a test copy) sends zero. An update that only touched shared pieces that are not a page also sends zero, on purpose.

When the job starts — and when it stays quiet

The job file waits for GitHub’s deployment_status message — that is GitHub’s “a deploy just reported in” note. It only starts the ping when that note says success and the label on the deploy is Production (or production). A Vercel preview uses a different label. The start rule says no. The job does not even download the code. No ping.

Everyday updates do not need a person. Vercel finishes the live site, GitHub starts the job. There is also a manual switch if you want to check the list yourself. GitHub’s built-in name for “run this job by hand” is workflow_dispatch. That name is GitHub’s, not this site’s. Any GitHub Actions job can turn it on. This IndexNow job has it on, so the Actions tab shows a Run workflow button on this job. A job that never added that switch would not show the button.

The Run workflow button itself is GitHub’s. Clicking it runs that job now. It does not wait for Vercel. That part is true of any GitHub job that turned the switch on.

What happens after you click is this IndexNow job’s rules, not GitHub’s default. GitHub lets each job add its own optional boxes. Other jobs may have different boxes, or none. This job added two:

  • Dry-run (a practice run) — this site’s script prints the link list in the log and does not ping IndexNow. Turn this on when you are only checking.
  • Previous version — this site’s script uses that older version to compare against. Leave it blank and the script picks the last live Production version on its own, same as the automatic path.

GitHub Actions: Run workflow panel

Swipe horizontally or scroll to the right to view the full screenshot.

GitHub Actions page for IndexNow after production deploy with the Run workflow panel open. A blue note says this workflow has a workflow_dispatch event trigger. The form shows Branch main, an empty Previous SHA to diff against box, and Log URLs only, do not ping IndexNow set to false.
This job’s Run workflow panel. The blue note and the button are GitHub’s. The two boxes are this job’s: Previous SHA to diff against (optional), empty, and Log URLs only, do not ping IndexNow set to false. False means a click would ping for real. The GitHub code-folder name is outside this crop.

On this job, if you click Run workflow and leave dry-run off, the ping is real. This job’s start rule also lets the button run even if Vercel did not just finish a live-site update. That mix — practice run, optional older version, ping unless you say otherwise — is how this IndexNow job is written. It is a check tool here, not the everyday start.

When the job runs — automatic after a live update, or from the button — it downloads that version of the code, including older saves, so the script can compare against the last live version. Then it runs that script. It only needs permission to read the code and the list of deploys.

How it builds the list

On this site, the list is not “every page.” It is “public page links whose page files changed between the last live version and this one.” That mapping is this job’s script.

The last live update, not the last save

Comparing only to the previous save (HEAD^) is the wrong default. You might land several saves in one live update. The script asks GitHub for the previous live Production version that is not the current one, then compares the files that changed between those two labels. That is “what went live,” not “what the last save touched.”

HEAD^ is a git shortcut, not a password. HEAD means “the version we have right now.” The caret ^ means “the one right before that.” So HEAD^ is “the save right before this one,” not “the last time the live site updated.” If two saves went live in the same update, that shortcut would miss the first one.

Those labels are often called a SHA (said “shah”). Think of it as a name tag for one version of the code: a long mix of numbers and letters, like the Diff line in the job log. GitHub also shows a short stub, like 7a341e4 on the Summary tab. It is not a password. It does not open the code folder. It just points at one version so the job can ask, “what files changed since the last live one?”

If GitHub has no previous live Production version (first time, or it cannot see deploys), it falls back to the save right before this one. If even that is missing, it logs that there is nothing to compare and stops without pinging. That skip is safer than inventing a huge list.

File to public URL — this site’s rules

How a changed file becomes a link is this site’s script, not a GitHub default and not IndexNow’s rulebook. Other sites can map files differently. Here, each changed file either becomes one public page link or is ignored. A page file lives in a folder; that folder path is the public link. For example, app/math/margin-vs-markup-calculator/page.tsx becomes /math/margin-vs-markup-calculator. A matching metadata.ts in that folder is the same link. Blog images under public/images/blog/{slug}/ ping that blog link — so dropping the screenshots for this post into its image folder will ping this post on the next live update. If you rename or move a page, this script adds both the old link and the new link, so IndexNow can hear about the link that went away and the link that appeared.

A real live update on this site is the worked example. The job log listed two links: the hedge funds vs. private equity post, and the Margin vs. Markup calculator. Two public pages showed up. Two links went out. The log line was Submitted 2 URLs. That is streaming, not “send every page.”

What gets a ping on this site — and what does not
What you changed in the codeWhat IndexNow gets
A page file (page.tsx) or its metadata.tsThat page’s public link
Images under public/images/blog/{slug}/That blog post’s link
The site-wide layout file app/layout.tsxThe homepage only — not every child page
The layout file for a section, like the main blog pageThat section’s main page only — not every page under it
Shared pieces, settings files, or server files that are not pagesNothing. Those files are not a public page.
A Vercel preview (a test copy of the site)Nothing. The job does not run.

What never becomes a ping

The skip list is the honest part. Changing a header that appears on every page does not ping every page. Changing globals.css (the site-wide style file) does not ping anything. Changing a server file named route.ts does not ping anything. The little site icon, the job file, and anything outside app/ (except those blog image folders) are ignored. If a shared header changed but no page file did, IndexNow stays quiet. That is a real limit. Do not treat this job as “the whole site is re-announced whenever the header moves.”

What you actually add

Two files. You do not paste extra passwords into GitHub for daily use. The script is the one that does the thinking. The job file is the one that starts it.

The chain on this site, in order:

  1. Vercel finishes updating the live site and tells GitHub “Production succeeded.” That poke is Vercel’s GitHub connection. Our script does not talk to Vercel.
  2. The GitHub job file hears that message, starts only on live success, downloads that version of the code, and runs the script. On this code folder that file is .github/workflows/indexnow-production.yml.
  3. The script does the work: find the last live Production version, see which files changed, turn those files into public page links, send only that list to IndexNow. On this code folder that file is scripts/ping-indexnow-from-diff.mjs. It sends to https://api.indexnow.org/indexnow— that address is IndexNow’s, not this site’s. What this script puts in the send is this site’s: this site’s name, this site’s already-published IndexNow key, and the address of that small proof file on this site.

So GitHub is the starter. Vercel is the “live site just updated” signal. The script is the worker that turns “a deploy happened” into “here are the pages that changed — ping those.”

Your live site already needs the IndexNow key file at https://your-host/{key}.txt so search engines can check you own the site. The script reads that same key from your existing IndexNow setup. Do not paste the key into this article, into a screenshot, or into a chat. The key file is meant to sit on the live site. Still do not copy it into places it does not belong.

Proof it ran: one live update, two links

Three original screenshots from one live Production update. Two public pages showed up. Two public links went out. GitHub shows the ping. Bing shows the same two links on the Submitted URLs list, both marked source Self.

GitHub Actions: ping-indexnow job log

Swipe horizontally or scroll to the right to view the full screenshot.

GitHub Actions log for the ping-indexnow job after a production deploy. The expanded step Ping IndexNow for changed URLs lists two URLs: the hedge funds vs. private equity blog post and the Margin vs. Markup calculator, then the line Submitted 2 URLs. The job succeeded.
A real ping-indexnow job log after a Vercel live-site update. The job found 2 URL(s): the hedge funds vs. private equity post and the Margin vs. Markup calculator. The last line is Submitted 2 URLs. The GitHub code-folder name and the rest of the GitHub page are outside this crop. That is streaming: only the pages that changed in that update.

The expanded step is mostly English once you know the lines:

  • if [ "" = "true" ] is the practice-run check. Empty quotes mean dry-run was not turned on, so this run sent for real. If it had said true, the job would only print links.
  • [IndexNow] Diff … is the compare step. The two long strings are SHAs: last live Production version, then this update. The three dots mean “files that changed between these two.”
  • 2 URL(s): is the count the script built from those files. The next two lines are the public links. Submitted 2 URLs means IndexNow accepted that list.

GitHub Actions: run summary

Swipe horizontally or scroll to the right to view the full screenshot.

GitHub Actions Summary for IndexNow after production deploy run 4. Status is Success. Triggered via deployment status. vercel bot created the run. The workflow file is indexnow-production.yml on deployment_status. The ping-indexnow job shows a green check and 9 seconds.
The same update’s Summary tab. GitHub shows Triggered via deployment status, created by vercel[bot], status Success. The job on the graph is ping-indexnow. That is the automatic half: Vercel finished the live site, GitHub ran the ping. A person did not paste a list. The GitHub code-folder name and the rest of the GitHub page are outside this crop.

Bing Webmaster Tools: IndexNow submitted URLs

Swipe horizontally or scroll to the right to view the full screenshot.

Bing Webmaster Tools IndexNow page. Submitted URLs list shows two definitivecalc.com addresses: the hedge funds vs. private equity blog post and the Margin vs. Markup calculator. Both rows say Today at 06:59 and Source Self. IndexNow is selected in the left menu.
Bing Webmaster Tools, IndexNow, Submitted URLs. The same two public links from the job log appear here, both Today at 06:59, both source Self. Self means your site sent them — not a paste in Bing’s own submit box.

When the log says there is nothing to ping

A successful live Production update can still print No indexable page URLs in this deploy; skipping ping. That is not a failure. It means the script looked at what changed and found no public page. Typical cases: you only changed a shared piece, a settings file, a server file that is not a page, or the little site icon. The job should finish cleanly. Do not “fix” that by sending every page on the site.

If you expected a link and did not see it, check the file path. The script only looks in app/ (minus app/api/) plus blog image folders. A typo in a folder name, or a change that lives only in components/ (shared pieces used by many pages), will not show up. Use the job’s dry-run (practice run) to print the link list without sending the ping.

Summary

After a Vercel Production update succeeds (the live site), Vercel tells GitHub. A GitHub job starts and runs this site’s script. The script compares that version to the last live version, turns changed page files into public links, and sends only that list to IndexNow. Preview copies do not run the job. Shared code that is not a page does not get pinged.

Automatic means you do not paste links or submit them by hand/manually. Streaming means the list matches that update: one page, one link; many pages in one update, many links together, up to IndexNow’s 10,000 limit. The script talks to IndexNow directly. It does not run in the visitor’s browser, so it does not affect Core Web Vitals (CWV).

If your site is not on Vercel and GitHub, keep that idea and change how you detect that the live site updated. Everyday updates should not be a hand-pasted list or “send every page.”

Shaleen Shah is the Founder and Technical Product Manager of Definitive Calc™. He is also a Sr. Analyst of SEO Operations at JD Power, specializing in systems and data behind modern search and information discovery.

Driven by technical rigor, Shaleen breaks down the practical math of whatever life brings, from homeownership nuances to long-term wealth building. He has a decade of investing experience, and the calculators run on a stateless, database-free architecture anyone can use without an account.

Continue Reading

Explore more insights on web development, cloud, and network architecture

Web & Network

August 28, 2026

What's the Difference Between a Wi-Fi Extender, a Mesh Kit, and a Longer Ethernet Cable?

A Wi-Fi extender is an extra box that sends your current Wi-Fi farther. A mesh kit is several boxes that cover the house as one network. A longer Ethernet cable is a wire from the router. This guide shows how they differ.

Read article
Web & Network

August 12, 2026

Cross-Origin Resource Sharing (CORS): The Browser's Permission Slip Between Sites

CORS means Cross-Origin Resource Sharing. It’s how browsers decide whether a page on one site can read a response from another. Learn what “origin” means, why you see CORS errors, how to spot them, and what actually has to change.

Read article
Computer & OSWeb & Network

August 1, 2026

How to Tell What Wi-Fi You're On—and Whether to Upgrade

See what Wi-Fi version your Windows laptop is using, why that label can mislead, and how to tell if you need a better router—or a faster computer.

Read article
Web & Network

July 27, 2026

AI Tokens Aren't Words — They're the Meter

How AI tokenization turns text into billable units, why chat context windows fill up and “forget,” and how input vs. output tokens change what you pay—explained in plain English.

Read article
Web & NetworkFinance

May 24, 2026

What Software Technical Debt Costs in Developer Hours (And Why It Grows Over Time)

Software technical debt is the ongoing developer time a web or app codebase needs for fixes, updates, and upkeep. Learn how those hours add up over time, why the load can increase year to year, and how to model the cost for your team.

Read article
Web & Network

May 20, 2026

Cookies, localStorage, and sessionStorage: What Gets Saved in Your Browser, How Long It Lasts, and Why a Cookie Banner Is Not the Whole Story

Websites stash data in more places than cookies. Learn how cookies, localStorage, and sessionStorage differ, what survives when you close a tab, and why consent banners often leave other storage alone.

Read article

The information in this article is for educational and informational purposes only and does not constitute professional, technical, or architectural advice. Definitive Calc is not liable for any outcomes related to your use or application of the concepts discussed.