Quick start
Everything happens in your DMs with the bot. Nobody else can use it, and it never posts in a server channel.
- Open a DM with the bot. In your server, click PractiScore Neo in the member list and choose Message. Type
/to see its commands. - Check it's healthy. Run
/status. You want Scraping: On and Health: OK. - See what's tracked.
/clubslists your clubs and/matcheslists their upcoming matches. - Add a club.
/addclub url:https://practiscore.com/clubs/<club>. The reply lists its matches with a picker to star the ones you care about. - Tune the noise. Use the Star / Normal / Mute buttons on alerts,
/manageto change several matches at once, or set rules so new matches of a type start at the right level.
How it works
The bot loads each club's PractiScore page, such as practiscore.com/clubs/tps-uspsa. Every listed match has a registration label, which the bot reads as a state:
| Label on the club page | State | Meaning |
|---|---|---|
| π’ green open | Open | You can register now. |
| β³ grey opens in 2 days | Not yet open | Registration opens later. The countdown is rounded down: 11 days shows as "1 week". |
| π grey closed | Closed | The match director set it to Closed. The match stays listed. |
| β anything else | Unknown | A label the bot hasn't seen before, such as full or waitlist. You get a DM so you can check the match yourself. |
Alerts come from changes between checks: a match appearing, its state changing, its date changing, or it disappearing from the page.
That's why an early manual opening is caught. It doesn't matter what date registration was supposed to open: the moment the label turns green, the next check sees it.
Club tiers
A tier sets how often a club's page is checked. Change it with /tier.
| Tier | Checked | Details |
|---|---|---|
| watched | Every 3 hours | During the day (8 AM β 9 PM ET). For clubs where you can't miss anything. New matches start β starred. |
| standard | Every 12 hours | For clubs you follow casually. New matches start normal. |
| manual | Only when you ask | Checked when you /scan, then once a day only while a starred match is waiting to open. New matches start π muted. |
| paused | Never | Everything is kept. When you un-pause, you get one summary of what changed instead of a flood of alerts. |
One page load covers every match at a club, so the cost of a club depends only on its tier, not on how many matches it has.
Match levels
A level sets which alerts you get for a match. Change it with the buttons on any alert, /star, /unstar, /mute, /manage, the /scan picker, or rules.
| Alert | β Starred | Normal | π Muted |
|---|---|---|---|
| New match posted | β | β | β |
| Registration now open | β | β | β |
| Registration reopened | β | β | β |
| Registration closed / closed again | β | β | β |
| Match date changed | β | β | β |
| Match removed from listing | β | β | β |
| Match back on listing | β | β | β |
| Unrecognized registration label | β | β | β |
| Extra checks around the opening time | β | β | β |
Where a new match starts: the matching rule if there is one, otherwise the club tier's default (watched β starred, standard β normal, manual β muted).
Alerts
Every alert is a DM. The coloured edge tells you what kind it is at a glance.
Every alert except "Match Removed" has Star Β· Normal Β· Mute buttons, and alerts with a match page have a View Match or Register Now link.
You'll also get a red Scraping is failing DM if checks keep failing (three in a row by default), and a green Scraping recovered DM when they work again. That's one pair per outage, not a DM every time a check fails.
When checks run
The bot looks every 5 minutes for anything that's due.
Regular checks
Regular checks follow each club's tier, and only between 8 AM and 9 PM Eastern. A watched club is checked about 8, 11 AM, 2, 5 and 8 PM, depending on when it was last checked. Restarting the bot doesn't trigger extra checks.
Registration-time checks
When a starred or normal match's label says "opens in N hours" or "opens in N minutes", the bot schedules extra checks around that moment. These run at any hour, including overnight.
They work the same at every tier except paused: a starred or normal match at a standard or manual club gets exactly the same extra checks as one at a watched club. The tier only decides how often a regular check comes along to read the countdown.
| Label seen | Opening is between | Extra checks at |
|---|---|---|
| opens in 5 hours | 5 and 6 hours from now | +5h 30m and +6h 2m |
| opens in 40 minutes | 40 and 41 minutes from now | +42m |
| opens in 2 days / 1 week | too far off | none yet. A later check will see hours |
The evening checks see any opening before the next morning as hours, so an opening at 2 AM gets checked at about 2 AM.
How close to the opening the alert arrives
The first extra check lands halfway through the hour the countdown points to:
- Opening in the second half of that hour: the halfway check sees "opens in N minutes" and schedules one more for just after. The alert arrives about 1β2 minutes after opening.
- Opening in the first half: the halfway check finds it already open. The alert arrives up to 30 minutes after opening.
If a match director opens registration early, before its listed time, there's no countdown to schedule from, so the bot sees it at the club's next regular check. During the day that's up to about 3 hours for a watched club and about 12 for a standard one. At night it's the first morning check (~8 AM).
A countdown is only seen in hours during the last day before opening. If a match is posted or rescheduled with less than a day's notice, a standard or manual club may not be checked in that window, and the opening is caught at the next regular check instead. For matches where minutes matter, make the club watched.
Rules
A rule sets the starting level of a club's newly posted matches based on their type or title.
/rule club:TPS USPSA text:Steel level:normal
/rule club:TPS USPSA text:PCSL level:muted
How text matches
- It's compared against the match's type (e.g.
Steel Challenge: Blank,USPSA level I,PCSL 1-GUN) and its title together. - Case doesn't matter, and it matches anywhere, even inside a word (
pcslmatchesPCSL 1-GUN). - It's literal text: no wildcards and no "or". Spaces and punctuation count.
- If several rules match, the longest text wins, so a specific rule can override a broad one.
- No match? The tier default applies (watched β starred, standard β normal, manual β muted).
- Rules only apply to matches posted after you create them. Change existing matches with
/star,/unstar,/muteor the buttons.
Example at a watched club
| Match | Type | Rules Steel β normal, PCSL β muted |
|---|---|---|
| TPS USPSA October | USPSA level I | no rule matches β β starred |
| TPS HALLOWEEN Night Steel | Steel Challenge: Blank | normal |
| Guardian Steel Training Event | Steel Challenge: Blank | normal |
| TPS PCSL Carbine | PCSL 1-GUN | π muted |
Challenge would also catch "Tactical Team Challenge", a USPSA match. USPSA catches almost every TPS match because the club name is in the titles. Copy the distinctive part of the Type field shown on any alert instead: it's more consistent than title words.
To remove a rule, run it again with level:remove. Every /rule reply lists the club's current rules, and /clubs shows them too.
Commands
All commands work in the bot's DMs only. Club and match names autocomplete as you type. /help command:<name> shows the same details inside Discord.
/status
/status
Whether scraping is on, whether recent checks succeeded, how many clubs are in each tier, when the next regular check is due, and the next registration-time check.
/clubs
/clubs
Each tracked club with its tier, when it was last checked, upcoming and starred match counts, its rules, and a link to its page.
/matches
/matches [club:<club>]
Upcoming matches with date, registration state and level (β starred, π muted). Reads the bot's saved data, so it's free and instant, but only as current as each club's last check.
Examples: /matches Β· /matches club:TPS USPSA
/manage
/manage club:<club>
One message for looking after a club, built from saved data, so opening it costs nothing. It lists the club's upcoming matches with their levels and has these controls:
- Match menu + β Star Β· Normal Β· π Mute
- Select any number of matches, then press a level. The list redraws with the new icons, so you can do several batches in a row. Unlike the
/scanpicker, matches you don't select are never changed. - Tier menu
- Same as
/tier. - π Scan now 1 request
- Checks the club and redraws the list with what changed. The only control that costs a request.
- π Remove club
- Asks you to confirm first, then does the same as
/removeclub.
Clubs with more than 25 upcoming matches get β Prev / Next βΆ buttons. The controls stop working after 30 minutes or a bot restart; run /manage again for fresh ones.
Example: /manage club:TPS USPSA
/addclub 1 request
/addclub url:<club page URL> [tier:<tier>]
- url
- The club's PractiScore page,
https://practiscore.com/clubs/<club>. Find it by searching the club on practiscore.com and copying the address. - tier
- watched (default), standard, manual or paused.
Loads the page once to confirm the club exists and get its name, then replies with its upcoming matches and a picker to star some. Existing matches don't each trigger a "new match" alert.
Example: /addclub url:https://practiscore.com/clubs/gainesville_practical_shooters tier:standard
/removeclub
/removeclub club:<club>
Stops tracking the club and deletes its matches, rules and scheduled checks. To stop checking but keep everything, use /tier with paused instead. /manage has a Remove button too.
/tier
/tier club:<club> tier:<watched|standard|manual|paused>
Changes how often a club is checked (see Club tiers). Leaving paused sends one catch-up summary on the next check. Existing matches keep their levels.
Example: /tier club:Friendly Gun Club tier:paused
/scan 1 request
/scan club:<club>
Checks a club right now, whatever its tier (even paused), and replies with its upcoming matches plus a picker. Use it to check on demand, or to pick matches at a manual club. Starring a manual club's match is how you ask to be told when its registration opens.
/star Β· /unstar Β· /mute
/star match:<match> Β· /unstar match:<match> Β· /mute match:<match>
Set one match's level: starred, normal (unstar) or muted. The match list autocompletes from upcoming matches and shows each one's current level.
/rule
/rule club:<club> text:<text> level:<starred|normal|muted|remove>
Sets the starting level for a club's new matches whose type or title contains text. See Rules.
Examples: /rule club:TPS USPSA text:Steel Challenge level:normal Β· /rule club:TPS USPSA text:PCSL level:remove
/scraping
/scraping state:<on|off>
Turns every scheduled check off or on. The bot stays online and commands still work. Handy for a break or to save requests. The setting survives restarts. Turning it back on sends one catch-up summary per club.
/usage
/usage
What the scraping service (Zyte) has charged this billing period, against the $100 monthly cap: dollars spent, requests and cost per 1,000, failed requests, a projection to the reset date, and the last 7 days. It asks Zyte's stats service, which doesn't use up any requests. The bot also DMs you once per period as spend passes 50%, 80% and 95% of the cap.
/help
/help [command:<command>]
Without a command: the command list plus a tier and level cheat sheet. With one: its description, usage and examples.
Example: /help command:rule
Recipes
Never miss a squad at your home club
Make it watched (the default). New matches arrive starred, so early opens, closes and reopens all reach you. Add /rules for match types you don't shoot.
Follow a club casually
/tier it to standard. You'll hear about new matches and openings within about 12 hours, for a fraction of the requests.
One match at a far-away club
/addclub with tier:manual and pick that match. The bot checks once a day until registration opens, then DMs you.
Unstar several matches at once
/manage club:β¦, select the matches, press Normal (or Mute). Free, no scan needed.
Stop steel alerts
/rule club:β¦ text:Steel level:muted for future ones, then /mute any already listed.
Going on vacation
/scraping state:off. When you're back, state:on gives you one summary per club.
Check right now
/scan club:β¦ costs one request and shows the live listing.
Request usage
Each check loads one club page through the scraping service, which costs one request no matter how many matches the club lists. Commands that only read saved data (/matches, /clubs, /status, and /manage unless you press Scan now) cost nothing. /usage shows what's actually been spent.
| What | Approx. requests / month |
|---|---|
| One watched club (~5 checks a day) | 150 |
| One standard club (2 a day) | 60 |
| One manual club with a starred match waiting | 30 while waiting, 0 otherwise |
| Registration-time checks | about 2 per starred or normal match as it nears opening |
/addclub, /scan | 1 each time |
Limits worth knowing
- No exact registration times yet. Club pages only show a rounded countdown, and match pages hide exact times behind a login. Registration-time checks work from the "hours" and "minutes" countdowns. Exact times from PractiScore's search index are planned.
- Removal takes two checks. A match must be missing twice in a row, so one bad page load never causes a false alarm. At a watched club that's about 3β6 hours after it disappears.
- An empty page is treated as a failed check, not as every match being cancelled.
- Past matches drop off the listing naturally and are never reported as removed.
- Full and waitlist labels haven't been seen yet. When one appears you get an "Unrecognized Registration Label" DM.
- Manual clubs aren't checked at all unless a starred match is waiting to open, so news about their other matches only arrives when you
/scan.
Troubleshooting
| Problem | What to do |
|---|---|
| Commands don't appear, or an option is missing | Close and reopen the DM, or restart Discord. New commands can take a minute to show up. |
| "This is a private bot." | You're not the bot's owner. It only answers one account. |
| No alerts for a club | Check /clubs: is it paused or manual? Check /status: is scraping on? Are the matches muted? |
| "Scraping is failing" DM | The scraping service or PractiScore is having trouble. The DM includes the error. The bot keeps retrying on its normal schedule and tells you when it recovers. |
| A picker or button says the interaction failed | The picker expired (1 hour, or a restart). Run /scan again. /manage controls expire after 30 minutes; run /manage again. Level buttons on alerts don't expire. |
| "Unrecognized Registration Label" | Open the match and check it yourself. The label is quoted in the DM so the bot can be taught it. |