Skip to content

Native app SDKs

Compare SeatLayer SDKs for Flutter, React Native, Swift and Kotlin. Choose a complete native buyer UI, custom controls, composed layout or raw seat map.

Updated View as Markdown

SeatLayer has four first-party native app SDKs. They share inventory, selection, hold, recovery, and checkout concepts. Flutter is 0.8.0; React Native, iOS and Android are independently verified at 0.3.4 in the SDK catalog.

The native event picker accepts one published Event per picker. Performance Groups and Fixed Renewable Seasons are browser/API/server products and are not native SDK configurations.

Use this page to choose the platform package and the amount of buyer UI your application owns. Every platform supports the same four-level product ladder: drop in the complete picker, customise it, compose your own layout from public parts, or use only the raw map.

SDK capability matrix

Platform Install Complete picker Host-owned layout Raw map
Flutter seatlayer: 0.8.0 SeatLayerPicker SeatLayerPickerScope + Flutter widgets SeatLayerView + controller
React Native @seatlayer/react-native@0.3.4 SeatLayerPicker or SeatLayerPickerModal SeatLayerPickerScope + React Native components SeatLayerView + controller
iOS Swift package 0.3.4 SeatLayerPicker or SeatLayerPickerViewController SwiftUI scope/components or UIKit map/controller SeatLayerView
Android Core + Compose 0.3.4 Compose SeatLayerPicker or View/XML SeatLayerPickerView Compose scope/components or headless Android Views SeatLayerView

Choose an integration path

Ship one cross-platform screen

Choose Flutter or React Native. Both packages provide the complete picker and public components for a custom layout.

Use the platform-native stack

Choose iOS for SwiftUI/UIKit or Android for Compose/View/XML. The buyer chrome is native and every layer remains replaceable.

Build a completely custom experience

Use the platform scope/state holder, one map, the typed controller, and public components. You own hierarchy and expression without rebuilding inventory, holds, recovery, or checkout state.

Keep only the venue surface

Use the preserved raw map when your application intentionally owns every surrounding control, confirmation, cart, timer, recovery path, and hold transition.

What “native picker” means

The SDKs divide responsibility at a deliberate seam:

Native application UI owns SeatLayer SDK owns
Header, event identity, filters, navigation, confirmation, quantities, cart, hold status, checkout, loading and errors Seats, labels, section geometry, map hit testing, pan and pinch, venue camera, authored 3D, and panorama pixels
Platform layout, accessibility semantics, back navigation, safe areas, app lifecycle and haptics Authoritative inventory projection and map capabilities

The native picker is therefore not a screenshot or generic hosted checkout. Its buyer chrome is made from Flutter widgets, React Native components, SwiftUI or UIKit, or Compose/Android Views. SeatLayer keeps venue geometry, inventory, and map behavior consistent behind the public native APIs. The map itself uses the shared WebView renderer; native UI refers to the controls and layout around it.

The customization ladder

All four SDKs follow the same product model:

  1. Drop in the complete flow. Supply an event configuration and a checkout callback.
  2. Keep the flow, change its expression. Apply theme, strings, options, style slots, or replace one complete part through a builder.
  3. Own the hierarchy. Place the SDK scope/state holder, map, controller, and public components in a layout your app controls.
  4. Use only the raw map. Own every piece of buyer UI and hold orchestration yourself.

Moving down the ladder does not move booking into the app. Every path ends at an opaque holdId that goes to your trusted backend.

Install the SDKs

pubspec.yamlyaml
dependencies:
  seatlayer: 0.8.0
ticket_screen.dartdart
import 'package:seatlayer/seatlayer.dart';

SeatLayerPicker(
  configuration: SeatLayerConfiguration(
    event: 'ev_your_event_key',
    publicKey: 'pk_test_your_public_key',
  ),
  themeMode: SeatLayerThemeMode.auto,
  onCheckout: (handoff) async {
    await checkoutBackend.begin(holdId: handoff.holdId);
  },
);

Continue with the Flutter guide, customisation, or a custom layout.

npm install @seatlayer/react-native@0.3.4 react-native-webview
TicketPickerScreen.tsxtsx
import React, { useMemo } from 'react';
import {
  SeatLayerPicker,
  type SeatLayerConfiguration,
} from '@seatlayer/react-native';

export function TicketPickerScreen() {
  const configuration = useMemo<SeatLayerConfiguration>(
    () => ({
      event: 'ev_your_event_key',
      publicKey: 'pk_test_your_public_key',
      currency: 'USD',
    }),
    [],
  );

  return (
    <SeatLayerPicker
      configuration={configuration}
      themeMode="auto"
      onCheckout={(handoff) =>
        checkoutBackend.begin({ holdId: handoff.holdId })
      }
    />
  );
}

Continue with the React Native guide, native-picker composition, or raw map.

Package.swiftswift
dependencies: [
    .package(
        url: "https://github.com/seatlayer/seatlayer-ios.git",
        exact: "0.3.4"
    )
]
TicketPicker.swiftswift
import SeatLayer
import SwiftUI

struct TicketPicker: View {
    var body: some View {
        SeatLayerPicker(
            configuration: SeatLayerConfiguration(
                event: "ev_your_event_key",
                publicKey: "pk_test_your_public_key",
                currency: "USD"
            ),
            onCheckout: { handoff in
                try await checkoutBackend.begin(holdId: handoff.holdId)
            }
        )
    }
}

Continue with the iOS guide, SwiftUI/UIKit composition, or raw map.

app/build.gradle.ktskotlin
dependencies {
    implementation("io.seatlayer:seatlayer-android:0.3.4")
    implementation("io.seatlayer:seatlayer-android-compose:0.3.4")
}
CheckoutActivity.ktkotlin
class CheckoutActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            SeatLayerPicker(
                configuration = SeatLayerConfiguration(
                    event = "ev_your_event_key",
                    publicKey = "pk_test_your_public_key",
                    currency = "USD",
                ),
                modifier = Modifier.fillMaxSize(),
                onCheckout = { handoff ->
                    checkoutBackend.begin(holdId = handoff.holdId)
                },
                onError = ::reportPickerError,
                onClose = ::finish,
            )
        }
    }
}

Continue with the Android guide, Compose/View composition, or raw map.

The examples use a publishable key for Public inventory. For login-gated, presale, partner, channel, or other private inventory, omit publicKey and use the platform’s renewable buyerAccessTokenProvider. Implement that provider with POST /v1/events/:key/buyer-access-sessions on your authenticated backend. Mint a native buyer-access session for the Event, return only the short-lived token to the provider, and treat the SDK’s access context as opaque. Keep the token in memory and never expose a SeatLayer secret to the application.

Shared security boundary

The mobile app may select inventory and create or resume a temporary hold. It must not decide the amount to charge or book inventory with a secret key.

  1. Send the opaque holdId and your own order context to your backend.
  2. Inspect the hold and calculate the price from trusted server data.
  3. Charge through your payment provider.
  4. Reuse the same bookingRef so retries remain idempotent.
  5. Treat expiry and inventory conflicts as recoverable selection states.

Read holds and checkout before connecting a production order flow.

Troubleshooting

Start with the typed SDK error or event; do not infer failure from an empty screen or a paused countdown.

Symptom or signal Likely boundary Safe response
Load fails before ready No network, temporary service failure, or a zero-sized/unmounted view Give the view a definite mounted size, verify connectivity, and retry through the SDK’s public reload path. Do not issue commands until ready.
accessUnavailable, origin_mismatch, or an access-provider failure The native buyer-access session is invalid, expired, revoked, or the provider did not return a token Mint again from your backend through buyer access sessions, return only the token to the provider, and keep it in memory. Do not fall back from private to Public inventory.
sl_incompatible or the platform’s compatibility error The installed app SDK is no longer compatible with the service contract This is not retryable in place. Upgrade to a current SDK version, validate it, and ship an app update.
sl_timeout A command did not receive its correlated response before the configured deadline Show a retryable state. For inventory-changing commands, inspect getCurrentHold() or resume the known hold before retrying so a late success is not duplicated.
destroyed or a command after unmount The view/controller lifecycle ended Stop sending commands and create one new view/controller pair for the next session.
holdExpired or a null hold after foreground/restoration Server ownership ended while the app timer was paused Clear checkout state, return to selection, and let the buyer choose again. Never extend or book from a local countdown alone.
selectedObjectsUnavailable, conflict details, or sold_out Inventory changed concurrently Remove only the reported unavailable objects, explain the change, and let the buyer reselect. Do not silently recreate a charge.
Test inventory appears live The host ignored ReadyInfo.mode Render an unmistakable Test Mode disclosure; test Events do not create live bookings.
Pan/pinch is unreliable or controls cannot be reached The venue map is nested in another scrolling/gesture surface or covered by an intercepting overlay Let the map own its gestures, keep host overlays accessible, and use typed camera/navigation commands rather than raw touch forwarding.

Platform guides add the exact error types, event names, lifecycle hooks, and tagged source references for their package.

Product scope

The documented mobile SDK contracts select inventory for one published Event. The browser SDK separately provides PerformanceGroupPicker and SeasonPicker. Do not assume those browser products can be passed to a native SDK’s event configuration until a platform release documents a versioned native contract for them.

Production checklist

  • Pin the exact package version or release tag you validated.
  • Give the map a definite size; do not place it inside another pan/zoom surface.
  • Keep buyer tokens in memory and secrets on the server.
  • Preserve an open holdId only when your checkout promises restoration.
  • Test background/foreground reconciliation, rotation, safe areas, back navigation, expiry, release, conflict, and retry behavior.
  • Verify test/live mode disclosure and any required SeatLayer attribution.
  • Smoke-test supported physical iOS and Android devices before rollout.
  • Confirm the backend derives price from the inspected hold, not app input.

Platform guides

Navigation

Type to search…

↑↓ navigate↵ selectEsc close