Scan for Global Entry / NEXUS appointment slots and get notified
Project description
Global Entry Appointment Scanner
Scan for open Global Entry / NEXUS appointment slots and get notified the moment one appears.
Install
Recommended — pipx (installs CLI tools in isolated environments, no conflicts):
brew install pipx # macOS
pipx install global-entry-scanner # core (email only)
pipx install "global-entry-scanner[slack]" # + Slack
pipx install "global-entry-scanner[discord]"# + Discord
pipx install "global-entry-scanner[sms]" # + Twilio SMS
pipx install "global-entry-scanner[mcp]" # + MCP server for AI agents
pipx install "global-entry-scanner[all]" # everything
On macOS, avoid using the system
pip3— it points to Python 3.9 which is too old, and Homebrew's Python will block system-wide installs.pipxhandles all of this automatically.
Alternative — pip (if you're inside a virtual environment):
pip install global-entry-scanner
pip install "global-entry-scanner[all]"
Quick start
# 1. Interactive setup — pick locations and configure notifications
global-entry-scanner setup
# 2. Run the scanner
global-entry-scanner scan
CLI
global-entry-scanner locations # list all enrollment centers
global-entry-scanner setup # interactive config wizard
global-entry-scanner scan # run with saved config
global-entry-scanner scan --locations "Chicago, Dallas" # override locations
global-entry-scanner scan --notify email,slack # override channels
global-entry-scanner mcp # start MCP server
Config is saved to ~/.config/global-entry-scanner/config.toml.
Python API
from global_entry_scanner import Scanner
from global_entry_scanner.notifications import SlackNotifier, DiscordNotifier, EmailNotifier
scanner = Scanner(location_ids=[5001, 5140])
scanner.add_notifier(SlackNotifier(webhook_url="https://hooks.slack.com/..."))
scanner.add_notifier(DiscordNotifier(webhook_url="https://discord.com/api/webhooks/..."))
scanner.add_notifier(EmailNotifier(from_email="you@gmail.com", to_email="you@gmail.com", password="app-password"))
scanner.start() # blocking; Ctrl+C to stop
Scanner options:
| Parameter | Default | Description |
|---|---|---|
location_ids |
required | List of enrollment center IDs |
check_interval |
900 |
Seconds between polls (no errors) |
error_interval |
60 |
Seconds between polls (on error) |
limit |
5 |
Max appointments to fetch per location |
Notification channels
| Channel | Extra | Credentials |
|---|---|---|
| (core) | Gmail address + app password | |
| Discord | [discord] |
Webhook URL |
| Slack | [slack] |
Webhook URL |
| SMS | [sms] |
Twilio account SID, auth token, phone numbers |
All configured channels fire concurrently. One failing channel does not block the others.
Discord webhook setup
- Open your Discord server → go to the channel you want notifications in
- Click Edit Channel (gear icon) → Integrations → Webhooks → New Webhook
- Give it a name, optionally set an avatar, then click Copy Webhook URL
- Paste the URL into
setupwhen prompted, or add it to your config:
[notifications.discord]
webhook_url = "https://discord.com/api/webhooks/1234567890/xxxx"
Twilio SMS setup
- Sign up at twilio.com (free trial includes a small credit)
- From the Twilio Console dashboard, copy your Account SID and Auth Token
- Go to Phone Numbers → Manage → Buy a number to get a Twilio number to send from (free trial includes one)
- Add the credentials to your config:
[notifications.sms]
account_sid = "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
auth_token = "your_auth_token"
from_number = "+12125550000" # your Twilio number
to_number = "+12125551234" # number to notify
Free trial note: Twilio trial accounts can only send SMS to verified numbers. Go to Phone Numbers → Manage → Verified Caller IDs to add your personal number.
Slack webhook setup
- Go to api.slack.com/apps → Create New App → From scratch
- Under Add features and functionality, choose Incoming Webhooks → toggle it on
- Click Add New Webhook to Workspace, pick a channel, and click Allow
- Copy the webhook URL that appears, then paste it into
setupwhen prompted or add it to your config:
[notifications.slack]
webhook_url = "https://hooks.slack.com/services/T00000000/B00000000/xxxx"
Claude Code skill
This repo ships a skill for Claude Code that lets you ask Claude directly about slot availability, set up monitoring, and configure notifications — without remembering any commands.
Install the skill
Option 1: From this repo (available now)
In Claude Code, run:
/plugin marketplace add JaiminBrahmbhatt/Global-Entry-Appointment-Scanner
/plugin install global-entry-scanner@global-entry-scanner
Option 2: Official Anthropic marketplace (pending review)
/plugin install global-entry-scanner
What you can ask Claude
Once installed, just talk to Claude naturally:
- "Are there any open Global Entry slots near Chicago or Dallas?"
- "Set this up to text me whenever a slot opens at JFK or Newark"
- "How do I hook up the MCP server to Claude Desktop?"
- "Run the scanner in the background and notify me on Discord"
Claude will detect whether the MCP server is running and use it directly, or fall back to guiding you through the CLI.
MCP server
Install with pip install global-entry-scanner[mcp], then run global-entry-scanner mcp.
Exposes six tools to AI agents: get_locations, search_locations, check_appointments, start_scan, stop_scan, get_scan_status.
Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"global-entry-scanner": {
"command": "global-entry-scanner",
"args": ["mcp"]
}
}
}
Configuration file
~/.config/global-entry-scanner/config.toml
[scanner]
check_interval = 900
error_interval = 60
limit = 5
[locations]
ids = [5001, 5140]
[notifications.discord]
webhook_url = "https://discord.com/api/webhooks/..."
[notifications.slack]
webhook_url = "https://hooks.slack.com/..."
[notifications.email]
from_email = "you@gmail.com"
to_email = "you@gmail.com"
password = "app-password"
[notifications.sms]
account_sid = "..."
auth_token = "..."
to_number = "+12125551234"
from_number = "+12125550000"
Development
git clone https://github.com/JaiminBrahmbhatt/Global-Entry-Appointment-Scanner
cd Global-Entry-Appointment-Scanner
pip install -e ".[all,dev]"
# Run tests
pytest
# Run live API tests
pytest -m integration
# Lint + type check
ruff check .
mypy global_entry_scanner/
Credits
Inspired by:
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file global_entry_scanner-0.1.3.tar.gz.
File metadata
- Download URL: global_entry_scanner-0.1.3.tar.gz
- Upload date:
- Size: 347.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3264f12a8f3fb495787e7c75390664858f08b8903aa9f8db21250f4e3f441aa6
|
|
| MD5 |
87adb4837f81754d5ec4f3bdc3889fd0
|
|
| BLAKE2b-256 |
e6b82e2aca015929cba3d01bafaf0247d0912efaad804146c2f6f03e3f6a490b
|
Provenance
The following attestation bundles were made for global_entry_scanner-0.1.3.tar.gz:
Publisher:
publish.yml on JaiminBrahmbhatt/Global-Entry-Appointment-Scanner
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
global_entry_scanner-0.1.3.tar.gz -
Subject digest:
3264f12a8f3fb495787e7c75390664858f08b8903aa9f8db21250f4e3f441aa6 - Sigstore transparency entry: 1191592092
- Sigstore integration time:
-
Permalink:
JaiminBrahmbhatt/Global-Entry-Appointment-Scanner@ec0c35898ada17b73cd755b0449f3aa004a3eefc -
Branch / Tag:
refs/tags/v0.1.3 - Owner: https://github.com/JaiminBrahmbhatt
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ec0c35898ada17b73cd755b0449f3aa004a3eefc -
Trigger Event:
release
-
Statement type:
File details
Details for the file global_entry_scanner-0.1.3-py3-none-any.whl.
File metadata
- Download URL: global_entry_scanner-0.1.3-py3-none-any.whl
- Upload date:
- Size: 16.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b68191c0a72c8d0c0f2ff23a69af0942f51a002f0f2e0cd4d8e95b55b5682682
|
|
| MD5 |
e1acf61a51c2aa775269f29c15959373
|
|
| BLAKE2b-256 |
f0f477dc3f0c3e7a3423e0bb921e668fa7583164b1742634486d5cb04dc0d706
|
Provenance
The following attestation bundles were made for global_entry_scanner-0.1.3-py3-none-any.whl:
Publisher:
publish.yml on JaiminBrahmbhatt/Global-Entry-Appointment-Scanner
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
global_entry_scanner-0.1.3-py3-none-any.whl -
Subject digest:
b68191c0a72c8d0c0f2ff23a69af0942f51a002f0f2e0cd4d8e95b55b5682682 - Sigstore transparency entry: 1191592093
- Sigstore integration time:
-
Permalink:
JaiminBrahmbhatt/Global-Entry-Appointment-Scanner@ec0c35898ada17b73cd755b0449f3aa004a3eefc -
Branch / Tag:
refs/tags/v0.1.3 - Owner: https://github.com/JaiminBrahmbhatt
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ec0c35898ada17b73cd755b0449f3aa004a3eefc -
Trigger Event:
release
-
Statement type: