Automation
Check domain expiry in GitHub Actions, and fail before a domain lapses
A scheduled GitHub Actions workflow can check every domain you depend on against its registry once a week and fail the run before one expires. The free Domain Expiry Check action reads the expiry date, registrar and lifecycle stage over RDAP, with no API key.
Published · Figures checked against primary sources, not recalled.
Check it now: the free bulk domain expiry checker will check up to 100 domains at once before you put them in a workflow.
Domains expire quietly. The registrar's reminder goes to an address nobody reads, the card on file has lapsed, and the first anyone hears of it is a dead website. If your team already lives in GitHub, the cheapest safety net is a workflow that looks the domains up every week and goes red when one is close.
The workflow
Save this as .github/workflows/domain-expiry.yml in any repository:
name: Domain expiry
on:
schedule:
- cron: '0 8 * * 1' # 08:00 UTC every Monday
workflow_dispatch: # and a "Run workflow" button
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: webvoguetech/domain-expiry-check@v1
with:
domains: |
example.com
example.co.uk
client-site.com
warn-days: 30 # warning annotation inside 30 days
fail-days: 7 # fail the job inside 7 days
Each run writes a table to the job summary: every domain with its lifecycle stage, expiry date, days left and registrar. A domain inside warn-days gets a warning annotation; one inside fail-days fails the job.
What makes it fail
Days are only half of it. The action reads the registry's status codes before the date, because the date alone misleads in both directions. A domain in its auto-renew grace period still shows a past expiry date and is perfectly safe, while one in redemption is in trouble whatever its date says.
| Registry says | Result |
|---|---|
Active, more than warn-days left | Pass |
Active, inside warn-days | Warning |
Active, inside fail-days | Fail |
| Auto-renew grace | Warning |
| Expired, redemption, pending delete, on hold | Fail, always |
| Not registered at all | Fail, always |
| Registry did not answer, or the TLD has no RDAP | Warning, never a failure |
The last row is deliberate. A registry outage is someone else's problem, and it should not break your build. It should not pass silently either.
Who gets told
GitHub sends notifications for a scheduled workflow to the person who created it (or who last re-enabled it), so a failed Monday run reaches that person by email and in the GitHub notifications inbox with nothing else to set up. If someone else should hear about it, have them create the workflow, or add a step that posts to your chat tool when the job fails.
The action also sets outputs, failed, soonest-domain and soonest-days, for anything later in the job that wants to act on the result.
How the lookup works
There is no service in the middle. For each domain the action reads IANA's RDAP bootstrap file, which names the authoritative RDAP server for every TLD that has one, and asks that registry directly (the method in RFC 9224). The answer is the registry's own current record, not a WHOIS mirror's copy of it. Subdomains are resolved to the registered name, so app.example.com checks example.com.
A few TLDs, .us among them, still publish no RDAP service. The action reports those as such rather than guessing.
From the command line
The same check runs anywhere Node.js 20 or later does, and exits with status 1 when a domain fails, so it fits a cron job or a deploy script:
npx domain-expiry-check example.com client-site.com --warn-days 30 --fail-days 7
A weekly check is a backstop, not monitoring. It only knows what was true on Monday morning. A domain that enters redemption on a Tuesday sits there for six days before the next run, and redemption is the stage where the restore fee starts. If that gap matters, check more often or use a service that looks every day.
Common questions
Does the Domain Expiry Check action need an API key?
No. It reads each domain from its own registry over RDAP, which is a public protocol. There is no account, no key and no third-party service involved.
How often should a domain expiry workflow run?
Weekly is enough to catch an approaching renewal well inside a 30-day warning window. Daily runs narrow the gap if a domain slips into redemption between checks.
Which TLDs does it support?
Every TLD with an RDAP service in the IANA bootstrap registry, which covers all generic TLDs and many country-code TLDs such as .uk. A TLD with no RDAP service yet, such as .us, is reported as unsupported with a warning rather than a failure.
Who is notified when the scheduled run fails?
GitHub notifies the person who created the scheduled workflow, or who last re-enabled it, by email and in their GitHub notifications.
Sources
- GitHub Marketplace — Domain Expiry Check
- GitHub Docs — Events that trigger workflows (schedule)
- GitHub Docs — Notifications for workflow runs
- RFC 9224 — Finding the Authoritative RDAP Service
- IANA — RDAP bootstrap file for DNS
Rather have an email than a red build?
DropPerch runs the same registry lookups every day and emails you before a renewal is missed, then through grace, redemption and the drop if one is.
Related
- What actually happens when a domain expires
- Redemption period vs pending delete
- Domain redemption fees by registrar
- RDAP vs WHOIS: what changed and why it matters
- Domain monitoring for agencies and resellers
- Domain status codes, and which ones mean trouble
- How to check when a domain expires
- How a domain drop actually works