Skip to content

Performance Group picker

Let a buyer choose seats across a fixed or flexible-date performance run, hold the selected allocations together, and hand the group to your checkout.

Updated View as Markdown

PerformanceGroupPicker is the complete buyer seating step for a run of two to eight performances that share one published seating chart. It is available in @seatlayer/js 0.64.0 and later. Try the buyer flow first in the multi-performance seat selection demo.

Use this page for picker configuration and behavior. Read the end-to-end Performance Group integration for provisioning, checkout, booking, and fulfilment, or the Performance Groups API for exact trusted operations.

It is not a season-ticket, subscription, pass, or renewable season membership. The organizer chooses whether every date is required or partial seats may be sold only on their available dates. Your application still owns the offer, checkout, payment, commercial order, ticket delivery, and support.

Use the separate Fixed Renewable Season integration when the offer needs an immutable 2–20-Event Plan, incumbent Seat Rights, and renewal offers rather than one Performance Group purchase.

Choose the inclusion policy

inclusionMode Buyer experience Compatibility
fixed Every date is included. A seat is selectable only when it is available on every performance. Default; existing integrations keep their current behavior.
flexible_dates A partial seat shows which dates are available. The buyer can select it for those dates and continue from the same chart. Same-seat flow; the selected dates are returned in the checkout handoff.

The flexible flow loads one chart and one per-performance availability projection. Selecting or clearing a partial seat re-collapses those cached availability planes locally; it does not load a chart for each date.

Choose the selection mode

Mode Buyer experience Use it when
same_seat The buyer selects once; those exact seats are held for every included performance. The run promises the same seat each night.
per_performance The buyer chooses an equal number of seats on each dated tab; seats may differ by performance. The buyer needs the same party size but not the same physical seats.

Both modes create one all-or-nothing group hold. The browser never makes a separate hold for each Event.

Before you render

Your trusted backend must create the Performance Group, activate it, and mint a short-lived bsg_… buyer-access session for the exact browser origin. See the Performance Groups API for that server-side setup.

Return only { token, expiresAt } to the browser. Do not put the token in a URL, persistent browser storage, analytics, or logs.

Same seat for every performance

browser/group-picker.tsts
import { PerformanceGroupPicker } from "@seatlayer/js";

const picker = new PerformanceGroupPicker({
  container: "#seat-picker",
  performanceGroup: "pg_opening_weekend",
  buyerAccessTokenProvider: async () => {
    const response = await fetch("/api/seatlayer/group-access", {
      method: "POST",
      credentials: "same-origin",
      cache: "no-store",
    });
    if (!response.ok) throw new Error("Unable to open seat selection");
    return response.json(); // { token: "bsg_…", expiresAt }
  },
  onCheckout: (handoff) => {
    // This starts your checkout. It does not book inventory yet.
    startCheckout({
      performanceGroup: handoff.performanceGroup.key,
      holdId: handoff.holdId,
      operationId: handoff.operationId,
    });
  },
  onError: (error) => reportSeatSelectionError(error),
});

await picker.render();

The picker presents the complete date list, one shared chart, an accessible selection summary, and one Hold seats for all performances action. When the hold completes, the primary action becomes Continue to checkout.

For a flexible_dates group, a two-tone partial seat can be opened to see its available and unavailable dates. Select for 2 available dates updates the persistent date summary, selects the seat, and submits one atomic hold for only those two performances. Clearing the selection restores the full date view.

Different seats on each date

Use per_performance only when your offer permits different seats. The picker reuses one chart and shows dated tabs; it requires the configured party size on every performance before the hold action becomes available.

browser/per-performance-picker.tsts
const picker = new PerformanceGroupPicker({
  container: "#seat-picker",
  performanceGroup: "pg_three-night-run",
  selectionMode: "per_performance",
  numberOfPlacesToSelect: 2,
  buyerAccessTokenProvider: getGroupBuyerAccess,
  onCheckout: (handoff) => {
    beginCheckout({
      holdId: handoff.holdId,
      operationId: handoff.operationId,
    });
  },
});

await picker.render();

For example, a two-person purchase must have two seats selected on each tab. The buyer cannot hold two seats on Friday and one on Saturday.

Constructor options

Option Type Notes
container string | HTMLElement Required inline mount target.
performanceGroup string Required active pg_… key. Do not pass an Event key.
selectionMode "same_seat" | "per_performance" Defaults to same_seat. This is an offer decision made before the picker opens.
numberOfPlacesToSelect number Required and at least one for per_performance; each tab must contain this many places.
buyerAccessTokenProvider ({ reason }) => Promise<{ token, expiresAt }> Preferred group-and-origin-bound credential refresh path.
buyerAccessToken string | { token, expiresAt } Non-refreshing alternative; prefer the provider.
holdTtlMs number Requested common group hold duration; the server clamps it.
initialHoldId + initialOperationId string pair Restore only a matched group hold/operation pair. Supply both or neither.
restoreHold boolean Defaults to true; group storage is separate from single-Event holds.
locale, messages, languages, theme, colorblindSafe Presentation options Use the same accessibility and branding controls as SeatPicker.
enable3D, max3DSeats, seatView Presentation options The canonical shared chart is rendered once.
maxSelection, selectedObjects, selectableObjects, selectionValidators Selection options In per-performance mode, exact party size is still required for every date.

event, custom transport, Best Available, runtime pricing overrides, and hosted checkout are intentionally unavailable. Passing a group through SeatPicker or calling one Event’s hold route would make the purchase unsafe.

Checkout handoff

onHold and onCheckout receive this group-specific object:

PerformanceGroupCheckoutHandoff.tsts
interface PerformanceGroupCheckoutHandoff {
  operationId: string;
  holdId: string;
  expiresAt: number;
  performanceGroup: PerformanceGroupDescriptor;
  selectionMode: "same_seat" | "per_performance";
  performanceKeys: string[];
  seatLabels: string[];
  allocations?: Array<{
    eventKey: string;
    seatLabels: string[];
  }>;
}

performanceKeys is the chronological set actually held. It contains every member for a fixed group and the selected available dates for a flexible group. Treat it, seatLabels, and allocations as buyer display data only. Send the opaque holdId and operationId to your backend; it must inspect the group hold before calculating a charge or booking inventory.

The handoff deliberately never includes child Event hold IDs, authoritative prices, payment data, or ticket information.

Hold, recovery, and release

Buyer state Picker behavior Host behavior
Selecting Seats are candidates only. Do not create an order yet.
Securing seats Interaction is locked while the single group operation resolves. Keep the buyer on the picker; do not start a second hold.
Held Every selected performance is protected by one common expiry. Start checkout using the opaque handoff.
Conflict Nothing is presented as held after safe cleanup. Explain that availability changed and let the buyer choose again.
Recovery The picker checks the same operation after a lost response. Do not create another operation or guess the outcome.
Expired or released Selection resets and availability refreshes. Clear the in-progress checkout/cart reference.

Call picker.destroy() when the host route unmounts. The picker clears its timers, chart instance, and polling connection. It never books inventory; booking belongs to your server.

Continue with the end-to-end integration guide and group hold inspection and booking.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close