Skip to content
Hails edited this page Jul 15, 2026 · 4 revisions

Events

The Events page at /events tracks every current and upcoming Pokemon GO event: Community Days, raid weekends, Spotlight Hours, GO Battle League rotations, seasonal events, and more. Cards show live countdowns, and clicking a card opens a detail view with bonuses, featured Pokemon, research, and shiny debuts. The whole list can also be subscribed to as a calendar feed, with the correct time in every subscriber's own timezone.

Browsing events

Events are split into two sections:

  • Current: events running right now, sorted by which ends soonest (events with no end time sort last)
  • Upcoming: future events, sorted by which starts soonest

Each card shows the event artwork, a category badge (its heading or event type), the name, the start and end times, and a countdown chip: "starts in 2d 5h" for upcoming events or "ends in 3h 41m" for current ones. Countdowns refresh every minute, and past events are filtered out entirely.

All times are displayed in your local time using your language's date format. Most Pokemon GO events run on local time, so what you see is when the event actually happens for you.

Event details

Click a card to open the detail modal. It shows the artwork, badge, name, and start and end times, then the full event writeup: bonuses, featured and boosted spawns, raid bosses, field or special research, and which Pokemon debut or appear as shinies (marked with a sparkle). A link at the bottom opens the original LeekDuck page.

If the full writeup is not available for an event, the modal falls back to structured data from the feed: Community Day spawns, bonuses, shinies, and special research steps; raid day bosses and shinies; Spotlight Hour Pokemon and bonus; and the current Research Breakthrough reward.

Subscribe to a calendar

The Subscribe to calendar panel at the top of the page turns the event list into a calendar feed you can add to Google Calendar, Apple Calendar, or any app that reads iCalendar (.ics) links. Once subscribed, the events sit alongside your own, and you can set native reminders and alarms on them.

Tick the kinds of events you want (Community Day, Spotlight Hour, Raids, GO Battle League, Research, or Everything), then either Copy link and paste it into your calendar app's "add by URL" option, or use Add to Google Calendar to open Google with the feed preselected. The link uses the webcal:// scheme, so most desktop and mobile apps hand it straight to the calendar. The feed refreshes on its own as new events are announced, so you subscribe once and leave it.

Getting the times right

This is the part other Pokemon GO calendars usually get wrong. The feed marks each event as one of two kinds, and the calendar keeps them distinct:

  • Local events (Spotlight Hour, Community Day, Raid Hour, and the like) happen at the same wall clock time in every region, for example 6pm local. They are written to the calendar as floating times with no timezone, so your app shows them at that time in whatever zone you are in.
  • Global events (GO Battle League rotations and other worldwide moments) happen at one instant everywhere. They are written in UTC, so your app converts them to your local time.

Because the two kinds are never flattened into a single fixed timezone, a subscriber anywhere sees Spotlight Hour at 6pm their time and a global rotation at the correct converted time, with no manual offset to apply.

Adding a single event

You do not have to subscribe to the whole feed to save one event. Click any event to open its detail popup, and near the times you will find two buttons. Both use the same floating versus UTC rule as the feed, so the saved event carries the correct time for wherever you are, and you can set an alarm on it.

On a phone, the Add to calendar button is a link to /events/event.ics?id=<eventID>, a one event .ics served with Content-Type: text/calendar so the phone opens it in its native calendar app: Apple Calendar on iOS (where the add sheet lets you pick which account to save into, including a Google account) and Google Calendar on Android. This is deliberately a real URL rather than an in browser blob, because a blob download of a calendar file is unreliable in mobile Safari. The single event .ics is generated by EventICS in internal/handlers/events_ics.go, sharing the writeVEVENT helper with the feed.

The Add to Google Calendar button is a plain calendar.google.com/calendar/render web link on every platform. A browser cannot reliably launch the Google Calendar app's event editor from a link (an Android intent:// deep link was tried and dropped for that reason), so the only dependable route into a native calendar app is the .ics link above. That is why the two buttons swap emphasis by platform: on desktop the Google button is the primary action and the .ics is labelled Download .ics, while on a phone the .ics link leads (labelled Add to calendar) because it opens the native app, and the Google web link sits alongside it as the secondary choice. For a floating (local) event the Google link also carries a ctz= parameter naming your timezone, so Google lands it at the same wall clock time you see.

Under the hood

The page is rendered by ts/events.ts from two server endpoints; see Data-Sources for the upstream attribution.

Event list. /api/events serves the event feed fetched from the ScrapedDuck project (the bigfoott/ScrapedDuck data branch on GitHub), which machine reads LeekDuck. The server refreshes it on a slow cycle, comfortably above ScrapedDuck's requested minimum interval. Most feed timestamps are timezone-less ISO strings (for example 2026-06-20T14:00:00.000) that JavaScript parses as local time, matching the local time semantics of most events; globally fixed events instead carry a Z (UTC) suffix. See Getting the times right for how the calendar feed preserves that distinction.

Calendar feed. /events/calendar.ics serves the same event list as an iCalendar file (internal/handlers/events_ics.go). An optional ?types= query filters to a comma separated set of event types, which the Subscribe panel builds from its toggles; an absent or empty value includes everything, and unrecognized tokens are ignored. Each event becomes a VEVENT with a stable UID, and its DTSTART/DTEND follow the source: a Z suffixed (UTC) time is emitted as UTC, and a timezone-less time is emitted floating so calendar clients read it in the viewer's own zone. Text fields are escaped and long lines folded per RFC 5545, and the calendar advertises a six hour refresh interval so subscribers re-poll periodically. The route is public and rate limited, and it honors the same maintenance switch as the Events page.

Detail content. /api/events/{id} serves the body of the matching LeekDuck event page, scraped server side on its own slow cycle with polite delays between page fetches. The HTML is sanitized server side with bluemonday before it is stored or served, only leekduck.com URLs are ever fetched, and relative links are resolved against the LeekDuck origin. The client caches each detail for the session and injects it directly; if a detail is empty or fails to load, it renders the structured extraData fallback instead.

Translated UI strings (section titles, "starts in", and so on) reach the script through the inline EV object defined in templates/events.html; see Localization for how that pattern works.

Clone this wiki locally