Gestures
Handle swipe gestures in your own page, so you can run your own back transition instead of the app's built-in swipe navigation.
Access: startiapp.Gesture
The app has its own swipe navigation — left-to-right for back, right-to-left for forward, both on by default. It runs the equivalent of history.back() and history.forward(), which in a single-page app is a full document navigation: the page jumps, or reloads, and whatever the user was looking at is gone.
startiapp.Gesture tells your page about the swipe instead, so you can run your own transition.
await startiapp.initialize({ allowSwipeNavigation: false });
startiapp.Gesture.addEventListener("swipe-back", () => {
myRouter.back();
});Listening for a gesture does not disable the app's swipe navigation, and the app's version covers both directions. Turn it off yourself, or one swipe gives the user your transition and a document navigation underneath it. See Turning the app's gesture off.
Events
swipe-back
The user swiped left-to-right, the direction both iOS and Android reserve for going back.
Event data: GestureDetail
startiapp.Gesture.addEventListener("swipe-back", (event) => {
myRouter.back();
});swipe-forward
The user swiped right-to-left. The mirror of swipe-back, carrying the same GestureDetail.
startiapp.Gesture.addEventListener("swipe-forward", () => {
wizard.next();
});Types
GestureDetail
interface GestureDetail {
distance: number;
duration: number;
velocity: number;
startX: number;
startY: number;
target: EventTarget | null;
}| Property | Type | Description |
|---|---|---|
| distance | number | How far the finger travelled horizontally, in CSS pixels. Always positive — the event name carries the direction. |
| duration | number | Milliseconds between the finger going down and coming up. |
| velocity | number | Speed in CSS pixels per millisecond, or 0 if the whole gesture landed in the same millisecond. |
| startX | number | Where the finger went down, in viewport coordinates. |
| startY | number | Where the finger went down, in viewport coordinates. |
| target | EventTarget | null | The element the finger went down on. |
Usage Patterns
Turning the app's gesture off
For a site that routes with history.pushState, the app's swipe navigation is wrong everywhere, so turn it off once for the whole app.
Prefer the Manager for this. allowSwipeNavigation is one of the initialization settings you can set for your brand under Development setup → Initialization settings, which keeps it out of your code. Pass it to initialize() only if the value has to be decided at runtime.
await startiapp.initialize({ allowSwipeNavigation: false });If it is wrong only on one screen — a carousel, a map, a signature pad — push it for that screen and pop it again on the way out. See App.pushOptions.
startiapp.App.pushOptions({ allowSwipeNavigation: false });
// Leaving the screen again.
startiapp.App.popOptions();Only from the screen edge
iOS starts a back gesture only near the edge. startX is what lets you match that, and it is also the cheapest way to stop a swipe meant for something else on the page from navigating.
startiapp.Gesture.addEventListener("swipe-back", (event) => {
if (event.detail.startX > 40) return;
myRouter.back();
});Ignoring a swipe that belongs to something else
startiapp.Gesture.addEventListener("swipe-back", (event) => {
const target = event.detail.target as Element | null;
if (target?.closest(".carousel")) return;
myRouter.back();
});Removing the listener with a screen
The recognizer is started when the first listener for a gesture arrives and stopped when the last one goes, so a page that never mentions gestures carries no touch listeners for them. Remove your listener when the screen it belongs to goes away, and an AbortSignal is the tidiest way — one controller tears down every listener the screen added.
const screen = new AbortController();
startiapp.Gesture.addEventListener("swipe-back", () => myRouter.back(), {
signal: screen.signal,
});
// When the screen is torn down — this also stops the recognizer.
screen.abort();Platform notes
A touch becomes a swipe only if all of these hold:
- it travelled at least 60 px horizontally,
- it travelled at least twice as far horizontally as it did vertically — so scrolling the page and drifting sideways never counts,
- it took no longer than 800 ms — a slow drag is not a flick,
- it was a single finger the whole way. A second finger landing cancels it, and so does the browser taking the touch over (a pinch-zoom, a native scroll).
The direction is geometric, not reading-order: left-to-right is always swipe-back, in a right-to-left layout too.
Two limits are worth knowing before you design around these events:
- The gesture is known when the finger lifts, not while it moves. There is deliberately no per-frame work here, which is what makes the recognizer nearly free — but it means you cannot drive a transition that follows the finger from these events. Track touches yourself for that.
- Touch only. A trackpad or mouse drag in a desktop browser fires nothing. Use a phone, or a browser's device-emulation mode, to try it.
See also
External Purchase
Manage Apple's External Purchase Custom Link entitlement (StoreKit external purchase API). This module lets you check eligibility, retrieve purchase tokens, display the mandatory Apple disclosure notice, and redirect the user to an external purchase page.
In-App Purchase
Purchase products, manage subscriptions, and retrieve product information through the native App Store / Google Play in-app purchase flow.