Skip to Content

App download

Every download export of @appfunnel-dev/sdk, generated from the SDK source. Signatures and descriptions are exact; for how these fit together, see the guides.

useAppDownload

hook · download/DownloadButton.tsx

useAppDownload(stores: AppStores & DownloadTracking): UseAppDownloadResult

The headless download — everything DownloadButton does, without the markup. Reach for it when the handoff isn’t a link: a redirect after a countdown, a QR code’s payload, a button that has to do other things first.

const app = useAppDownload({ ios: 'https://apps.apple.com/app/id1234567890', android: 'https://play.google.com/store/apps/details?id=com.acme.app', }) return <button onClick={() => app.open()}>Download the app</button>

usePlatform

hook · download/DownloadButton.tsx

usePlatform(): AppPlatform

usePlatform()'ios' | 'android' | 'other' for the current visitor. The store decision on its own, so copy and artwork can agree with where the button goes (platform === 'android' ? 'Get it on Google Play' : 'Download on the App Store').

DownloadButton

component · download/DownloadButton.tsx

DownloadButton({ ios, android, fallback, event, target, children, onClick, ...rest }: DownloadButtonProps): ReactNode

A link to the app store, picked from the visitor’s device.

iPhones and iPads get ios, Android phones get android, everyone else gets fallback — so the finish page is one button rather than a row of badges the visitor has to choose between. Renders a plain <a href="{store url}">: real link semantics, keyboard-focusable, and styleable entirely through className/style like any anchor.

Calling preventDefault() in your own onClick cancels the navigation, matching <Next>/<Back>.

<DownloadButton ios="https://apps.apple.com/app/id1234567890" android="https://play.google.com/store/apps/details?id=com.acme.app" fallback="https://acme.com/get-the-app" className="btn-primary" > Download the app </DownloadButton>

platformFor

function · download/store.ts

platformFor(context: FunnelContext): AppPlatform

The platform for a funnel context. Reads context.os.name rather than sniffing the user-agent again: the SDK has exactly one detector (../state/context.osFromUserAgent) and a second one drifting alongside it is how a funnel ends up sending iPhones to Google Play.

That detector was wrong until 2026-07-31 — every iOS user-agent contains “like Mac OS X”, so the mac test matched first and reported every iPhone as macOS. Replaying all 144,938 stored sessions put 85.7% of them in the wrong bucket. This function is only as good as that fix, which is why the fix has its own test file pinned against real user-agents.

resolveStore

function · download/store.ts

resolveStore(stores: AppStores, platform: AppPlatform): string

Pick the store URL for a platform, specific → generic.

The other chain ends in a store URL rather than nothing on purpose: a desktop visitor landing on the App Store’s web listing is a mildly wrong destination, whereas a dead button on the page they just paid on is a refund.

withScheme

function · download/store.ts

withScheme(url: string): string

Normalise a destination: a bare host/path gets https://. Already-schemed URLs, protocol-relative (//cdn…), absolute paths (/thanks) and bare ?/# are returned as given.

AppStores

interface · download/store.ts

export interface AppStores { ios?: string android?: string fallback?: string }

Where each platform goes. Every field optional — give the stores you actually have.

DownloadButtonProps

interface · download/DownloadButton.tsx

export interface DownloadButtonProps extends AppStores, DownloadTracking, Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href' | 'target'> { children?: ReactNode }

DownloadTracking

interface · download/DownloadButton.tsx

export interface DownloadTracking { event?: string | false target?: DownloadTarget }

What useAppDownload accepts on top of the store URLs.

UseAppDownloadResult

interface · download/DownloadButton.tsx

export interface UseAppDownloadResult { platform: AppPlatform url: string open: (target?: DownloadTarget) => string }

AppPlatform

type · download/store.ts

export type AppPlatform = 'ios' | 'android' | 'other'

The store platform, collapsed to what a download button can act on. other is desktop and anything unrecognised — a real destination in its own right (a QR page, the marketing site), not an error state.

DownloadTarget

type · download/DownloadButton.tsx

export type DownloadTarget = '_self' | '_blank'

Where the store page opens. Same values as the HTML attribute, and passed through as one.

Last updated on