Skip to main content

Event Check-in & Anonymous Identifiers

This document describes the event check-in system, anonymous registration flows, and how anonymous identifiers are used across the platform.

Check-in System Overview

The check-in system supports three primary flows:

Logged-in self check-in

Users with accounts check in from the event page or via token link

Token-based check-in

Anyone with a valid check-in token (QR code or link) can access check-in

Anonymous pick-your-registration

Unauthenticated users with a token search and select their registration to check in

Check-in Settings

Events can configure check-in behavior via checkInSettings:
SettingDescription
allowEarlyCheckInAllow check-in before event start time
allowAnonymousCheckInEnable anonymous (FormResponse) registrations in check-in list
allowOnPageCheckInAllow check-in from the event page (vs. token link only)
requireRegistrationRequire registration before check-in (logged-in users)
autoCheckInAutomatically check in when conditions are met

Check-in Token

Each event with check-in enabled has a checkInToken — a secret hex string used to gate check-in access. The token is:
  • Included in QR codes and check-in links (e.g. /check-in/:eventId/:token)
  • Required for anonymous flows — self-registrations and anonymous check-in endpoints validate the token
  • Not exposed to unauthenticated users except via the check-in URL (e.g. from QR scan)

Check-in Flows

1. Logged-in Self Check-in (no token)

Route: Event page → Check In button
Endpoint: POST /events/:eventId/check-in/self
Auth: Required (verifyToken)
  • User must be logged in
  • No token needed
  • Uses req.user.userId to find/create attendee
  • Validates event time and requireRegistration if set

2. Logged-in Token Check-in

Route: /check-in/:eventId/:token
Endpoint: POST /events/:eventId/check-in
Body: { token }
Auth: Optional (verifyTokenOptional)
  • User is logged in and has the token in the URL
  • Token validates access
  • Same logic as self check-in but with token validation

3. Anonymous Pick-Your-Registration

Route: /check-in/:eventId/:token (user not logged in)
Endpoints:
  • GET /events/:eventId/check-in/self-registrations?token=xxx — list registrations
  • GET /events/:eventId/check-in/registration/:formResponseId?token=xxx — form details
  • POST /events/:eventId/check-in/anonymous — check in by userId or formResponseId
    Auth: None (token validates)
Flow:
  1. User opens check-in link (from QR or event page) with token
  2. Frontend fetches registrations via self-registrations
  3. User searches by name/email and selects their registration
  4. User can “View details” to see their full registration form (anonymous only)
  5. User clicks “Check In” → POST /events/:eventId/check-in/anonymous with { token, formResponseId } or { token, userId }
Anonymous check-in is not locked to the browser. Users can register on one device and check in on another — they only need the token and to find their name in the list.

4. Manual Check-in (Organizer)

Endpoints:
  • POST /events/:eventId/check-in/:userId — check in logged-in attendee
  • POST /events/:eventId/check-in/by-form-response/:responseId — check in anonymous attendee
Auth: Required (verifyToken) + event management permission Organizers use the Event Dashboard Check-in tab to search and manually check in attendees.

Anonymous Registration

FormResponse Model

Anonymous registrations are stored as FormResponse documents with submittedBy: null:
{
  form: ObjectId,
  event: ObjectId,
  formSnapshot: Object,  // Form as it was when submitted
  submittedBy: null,    // null = anonymous
  guestName: String,
  guestEmail: String,
  answers: [ ... ],
  submittedAt: Date
}

Browser localStorage (anonymousRegistrationStorage)

The frontend uses meridian-anonymous-registrations in localStorage to track when the current browser has registered for an event without an account. Purpose:
  • Show “You are registered” on the event page
  • Verify with server that registration still exists (GET /events/:eventId/check-anonymous-registration?guestEmail=...)
  • Support “Add another registration” — allow multiple anonymous registrations per event from the same browser
Storage shape:
{
  [eventId]: {
    guestName: string,
    guestEmail: string,  // normalized (trim + lowercase)
    registeredAt: string,  // ISO date
    _v: number
  }
}
Key functions:
  • hasAnonymousRegistration(eventId) — whether this browser has a stored registration
  • getAnonymousRegistration(eventId) — get stored details
  • saveAnonymousRegistration(eventId, { guestName, guestEmail }) — save after successful registration
  • removeAnonymousRegistration(eventId) — clear when server says registration no longer exists
  • getAllAnonymousRegistrations() — for claim API
localStorage is browser-scoped. It does not gate check-in. Users can check in from any device with the token — the list comes from the server, not localStorage.

Claim Anonymous Registrations

When a user signs up or logs in, the frontend calls POST /claim-anonymous-registrations with { registrations: [ { eventId, guestEmail } ] }. For each matching anonymous FormResponse (same event, submittedBy: null, email match), the backend:
  1. Sets submittedBy to the user’s ID
  2. Updates guestName/guestEmail from the user account if the form collects them
  3. Adds the user to event.attendees if not already present
This links previously anonymous registrations to the new account.

Anonymous Identifiers (Analytics)

Separate from event registration, the analytics platform uses an anonymous_id for tracking events before and after login:
ConceptPurposeStorage
Analytics anonymous_idDevice-scoped persistent ID for analytics events (no PII)Client (e.g. AsyncStorage, localStorage)
Anonymous FormResponseEvent registration without account (submittedBy: null)Server (MongoDB)
localStorage registration”This browser registered for this event”Client (localStorage)
See Analytics Platform for the analytics envelope and anonymous_id usage.

API Reference

Public Check-in (token required, no auth)

MethodEndpointDescription
GET/events/:eventId/check-in/self-registrations?token=xxxList registrations (logged-in + anonymous) for pick-your-registration
GET/events/:eventId/check-in/registration/:formResponseId?token=xxxGet form snapshot + answers for an anonymous registration
POST/events/:eventId/check-in/anonymousCheck in by { token, formResponseId } or { token, userId }

Authenticated Check-in

MethodEndpointDescription
POST/events/:eventId/check-in/selfSelf check-in (logged-in, no token)
POST/events/:eventId/check-inToken check-in (body: { token })
POST/events/:eventId/check-outRemove own check-in

Organizer / Management

MethodEndpointDescription
POST/events/:eventId/check-in/enableEnable check-in
POST/events/:eventId/check-in/disableDisable check-in
PUT/events/:eventId/check-in/settingsUpdate check-in settings
GET/events/:eventId/check-in/qrGet QR code for check-in
GET/events/:eventId/check-in/linkGet check-in URL
GET/events/:eventId/check-in/attendeesList checked-in attendees
POST/events/:eventId/check-in/:userIdManual check-in (logged-in)
POST/events/:eventId/check-in/by-form-response/:responseIdManual check-in (anonymous)

Anonymous Registration Verification

MethodEndpointDescription
GET/events/:eventId/check-anonymous-registration?guestEmail=xxxCheck if anonymous registration exists (for localStorage sync)
POST/claim-anonymous-registrationsClaim anonymous registrations after sign-up (body: { registrations: [ { eventId, guestEmail } ] })

Frontend Components

ComponentLocationPurpose
EventCheckInButtonMeridian/frontend/src/components/EventCheckInButtonCheck-in button on event page; navigates with token for anonymous
CheckInConfirmationMeridian/frontend/src/pages/CheckInCheck-in page; handles token validation, anonymous pick UI, form details modal
ManualCheckInModalMeridian/frontend/.../EventCheckInTabOrganizer manual check-in (search + select)
RSVPButton / RSVPSectionMeridian/frontend/src/componentsRegistration; uses anonymousRegistrationStorage for “registered” state and “Add another”

Event dashboard

Event management, readiness, and organizer tooling around the same events.

Event management API

REST paths for RSVPs, agendas, and org-event operations used by check-in flows.

Beacon events

Event lifecycle, approvals, and RSVP from the Beacon product lens.

Platform analytics

Event pipeline, envelope schema, and anonymous_id–friendly tracking.

Analytics collected events

Named events and properties emitted by web and mobile clients.

Atlas messaging

Announcements and anonymous recipients tied to event outreach.