Docs/Discovery & Social Feed

Discovery & Social Feed

Discovery is how people find your events, a searchable web page and an in-app map and feed that surface public events near a viewer. This guide covers exactly how a public event shows up in Discover (visibility levels and geocoding), the map feed and how it blends your events with events from around the web, subscribable public calendars (ICS), universal search, the social event feed and who's-going, and the alerts people can subscribe to.

The /discover web page, the search bar, the category filter row, and a grid of upcoming event cards each showing cover image, title, date, venue, and starting price.
The /discover web page, the search bar, the category filter row, and a grid of upcoming event cards each showing cover image, title, date, venue, and starting price.

What Discovery Is

There are two Discovery surfaces, both fed from the same rules:

  • The web Discover page at /discover, a public, no-login page for browsing and searching upcoming events by name, place, or category. It renders fresh on every request (it's time-sensitive), showing only your own Modality events that are public and published.
  • The in-app map & feed (Modality mobile app), a location-first map and list that merges your Modality events with cached events from around the web, so a viewer sees what's happening near them even before your calendar is dense in that city.

Both surfaces are cross-workspace by default, they show events from every organizer, and anonymous viewers are fully supported. Signing in only adds personal touches (friends-going counts, personalized ordering, saved alerts).

Only public, published events with coordinates appear on the map and in cross-workspace discovery. Draft, private, unlisted, and searchable-only events are never placed on the Discover map or feed, see Visibility & Geocoding next.

How Public Events Surface: Visibility & Geocoding

Two things decide whether an event shows up in Discover: its visibility level and whether it has coordinates.

Visibility levels

Set the level in the Go Live dialog when you publish (see the Events guide). Discovery treats them as:

  • Public, eligible for the in-app Discover map/feed, the /discover page, and cross-workspace search. This is the only level that appears on the discovery map.
  • Searchable, indexable on Google and shown on your own public Events Page, but hidden from in-app Discover and the cross-workspace map.
  • Unlisted, reachable only by direct link; not on Discover.
  • Private, hidden entirely; only your team can access it.
One exception: your workspace's subscribable ICS calendar feed includes Public, Searchable, and Unlisted events (only Private is excluded), so a calendar subscriber sees more than a cross-workspace map browser does. See Subscribable Calendars below.

Coordinates (geocoding)

The map is a proximity query, it can only place an event that has a latitude and longitude. Modality resolves coordinates for you automatically:

  • Geocoded on write, when you save an event with a venue/address (and no explicit coordinates), Modality geocodes the address in the background and stores lat/lng plus city, region, and country on the event.
  • Provider, geocoding uses Google Places when a GOOGLE_PLACES_API_KEY is configured, and automatically falls back to OpenStreetMap Nominatim (free, no key) if Google is unavailable, so it never goes dark. Geocoding is best-effort and never blocks saving the event.
  • Venue-coordinate fallback, if an event row has no coordinates of its own but is linked to a Venue that does, the map query falls back to the venue's coordinates (COALESCE(event, venue)) so the event still places correctly.
If a public event isn't appearing on the map, the usual cause is missing coordinates: make sure the venue or address is filled in (ideally picked from the location autocomplete so it carries coordinates). Events created without any geocodable location can't be placed on the map.

"Upcoming" and recurring events

By default Discovery shows upcoming events, the event's own start date is in the future, it has no fixed date, or it has any future showing. This means a recurring / multi-showtime event stays in Discovery even after its first showing passes, and every card reports its next live date (not the stale first date) and sorts by it.

The Go Live dialog's four visibility levels (Public / Searchable / Unlisted / Private), highlighting that only Public feeds the in-app Discover map.
The Go Live dialog's four visibility levels (Public / Searchable / Unlisted / Private), highlighting that only Public feeds the in-app Discover map.

The Discovery Map

The in-app map feed answers a single question: "what's happening near this spot?" It takes a center point and radius and returns a merged, de-duplicated list of events to place as pins and list rows.

How the feed is built

  1. The app requests /api/v1/discover/map with a lat, lng, and radiusMi (default 25 mi, up to 500), plus an optional date window (from/to) or when=all.
  2. Modality runs a Haversine proximity query over its own public/published events and over a cache of external events, keeping anything within the radius.
  3. A date window is applied by default, a 7-day lookahead from the start of today when no explicit range is given. when=all drops the window (keeping past and undated events). A multi-night event stays on the map for every showing that falls inside the window, not just opening night.
  4. Results are de-duplicated and sorted (see below), then returned. A signed-in viewer also gets a per-event friendsGoing count and personalized ordering.

Where the "events from the web" come from

To make the map useful in a city where your own calendar is still thin, Modality maintains a cache of external events per metro (a rounded coordinate cell). When someone views a cold or stale metro, an ingest is triggered (via a durable Cloud Task, with an in-process fallback for local dev) and the response signals ingesting so the app can re-poll for the warmed results. The cache has a 12-hour freshness window, so repeated views don't re-hit upstream sources.

  • Aggregated sources, major public ticketing and event platforms feed the external cache (rate-limited sources are fetched less often to conserve quota).
  • Own venue harvest, a curated registry of public venue calendars is harvested directly, reading either schema.org Event JSON-LD from a venue's events page or a subscribable .ics feed, with the venue's coordinates as a fallback location.

De-duplication, boosting & personalization

  • Cross-source dedup, the same real event arriving from multiple providers is collapsed to one card; an external event that matches one of your native events (by normalized title + same day) is dropped in favor of the native one.
  • Boosted placement, a native Modality event whose workspace is on a paid plan (Pro or Business, active or in an unexpired trial) floats to the top of the feed with a Featured treatment.
  • Affinity ranking, for a signed-in viewer, ordering is personalized from learned category and metro affinity (boosted events still lead). Anonymous reads keep a deterministic order so the public map stays cacheable.
  • Friends going, a signed-in viewer sees how many of the people they follow are going to each event.

GIF: the in-app discovery map, panning to a new city triggers external-event ingest, pins populate, and a card shows a 'Featured' badge plus a 'friends going' count.

Demo GIF / screenshot to be added

Hidden-location events on the map

For events with a hidden/secret location (for example approval-gated events that reveal the address only to approved guests), the map protects the venue: for a viewer who isn't an approved guest, the pin is fuzzed to an approximate spot, the exact venue is withheld, and only a general locality label (city, region) is shown. Approved guests, and the same event on the /discover list, see the real details. External events can't be location-hidden; that protection is Modality-only.

Browse by City, Category & Featured Calendars

Beyond the map, Discovery offers curated ways in, all computed from upcoming public events:

  • Cities, the cities with the most upcoming public events power a "browse by city" rail (each with an event count and an average map center).
  • Categories, a live category-count filter bar; picking a category filters the feed. Category also drives the map's filtering and theming.
  • Featured Calendars, the workspaces (organizers) with the most upcoming public events, so a viewer can follow a prolific organizer's whole calendar. Served at /api/v1/discover/calendars.

Subscribable Public Calendars (ICS)

Every workspace exposes its public events as a live iCalendar (.ics) feed that people can subscribe to in Apple Calendar, Google Calendar, Outlook, and any other calendar app. Once subscribed, the app polls the feed and keeps the person's calendar in sync as you add, move, or update events.

The feed URL

The feed lives at /api/v1/calendars/<workspace-slug>/ics and is returned as text/calendar. Add ?category=<name> to publish a category-specific calendar (e.g. only your Music events). Responses are cached for an hour.

  • What it includes, published events that are Public, Searchable, or Unlisted (Private events are excluded), ordered by date.
  • One entry per showing, a multi-showtime event syncs every showing as its own calendar entry with a distinct UID (and its per-showing label in the title), instead of collapsing to the earliest date.
  • Rich detail, each entry carries the title, description, location (venue + address), and a link back to the public event page. Events default to a 2-hour duration when no end time is set.

Email subscriptions

People can also subscribe to a workspace calendar by email (optionally filtered to one category). Subscribing creates or updates a People/Contact record in your CRM (sourced as calendar_subscribe) and records the subscription, idempotently per email, so a repeat subscribe never duplicates the contact.

A public calendar page with the 'Subscribe' options, the copyable webcal/ICS feed URL and the email-subscribe form with an optional category filter.
A public calendar page with the 'Subscribe' options, the copyable webcal/ICS feed URL and the email-subscribe form with an optional category filter.

Universal search is the consumer discovery search that spans the whole platform, distinct from the operator CRM search inside your workspace. A single query fans out across five buckets and returns matches from every workspace:

  • People, public profiles, respecting the viewer's blocks/hidden users.
  • Events, both your native public events and external (cached web) events, matched on title, city, or venue, and ranked by next upcoming date.
  • Posts, feed posts whose text matches, media posts surfaced first for the explore grid.
  • Venues, venue places by name or city.
  • Tags, #hashtags mined and tallied from post text.

Search is exposed at /api/v1/discover/search. Passing a type narrows to a single bucket with a larger result cap (for a "see all" tab); the default all returns a small slice of each. A blank query returns nothing.

Screenshot: the mobile universal search screen with tabs for People, Events, Posts, Venues, and Tags, showing a mixed 'all' result set for a sample query.

Demo GIF / screenshot to be added

The Social Event Feed

Every event, native or external, has a social layer so attendees can talk about it and see who else is coming.

The event wall

Each event has a wall: the feed posts (text and photos) that reference it, keyset-paginated and public to read. It's served from /api/v1/discover/feed for exactly one event, pass an eventId for a native event or a discoveryEventId for an external one. Signing in only powers the "liked by me" state on posts.

Who's going

/api/v1/discover/going returns the going count and attendee avatars for any event, native or external. When the viewer is signed in, it also flags which attendees they follow ("friends") and surfaces a top-level friends-going count, the same signal that highlights events on the map.

Engagement signals

As people browse, the app logs lightweight view / click / share interactions to /api/v1/discover/interactions. These are best-effort and only recorded for signed-in users (anonymous browsing is a no-op), and they feed the affinity model that personalizes each viewer's map ordering.

The social layer is privacy-aware: blocked and hidden users are filtered out of search and post results, and hidden-location events keep their venue withheld from viewers who aren't approved guests.

Alerts: Notify Me & Region Subscriptions

Viewers can subscribe to be alerted about events. Alerts are delivered to the in-app Alerts feed and as push notifications, alongside social notifications.

Event subscriptions ("Notify me")

  1. A viewer taps Notify me on a specific event (native or external).
  2. If the event materially changes (date/time or location), subscribers are alerted with what changed.
  3. They also get a one-time "starting soon" reminder when a subscribed native event is within the next 24 hours (de-duplicated per subscriber, sent from the reminders cron).

Region subscriptions ("Alert me for this area")

A viewer can subscribe to an area, a center point and radius, optionally narrowed to a category and a maximum price. Whenever the discovery collector ingests genuinely new events in that area, matching subscribers get a new-event alert. This is explicit opt-in, and it's carefully throttled:

  • Idempotent, each new event alerts a subscription at most once, so re-ingesting the same event never re-notifies.
  • Capped & summarized, above a small per-run cap (so a metro's very first ingest, where every event is "new," can't flood a subscriber), the alerts collapse into a single "N new events near you" summary.
  • De-duplicated, subscriptions are reused for an equivalent area + category + price, so repeated "Alert me" taps don't stack duplicates, and cross-source duplicates of the same real event are collapsed before matching.

All of a viewer's event and region subscriptions are listed and manageable under /api/v1/discover/subscriptions (and its event / region sub-routes).

Screenshot: the mobile subscriptions manager listing 'Notify me' events and saved region alerts (area radius, category, max price), each with a toggle to turn alerts off.

Demo GIF / screenshot to be added