Web SDK
Every method the in-webview Appbrew Web SDK exposes, with payload shapes.
The Web SDK is the JavaScript API a web page uses to call the Appbrew app it is running inside. For a walkthrough, start with the Web SDK guide. This page is the surface.
<script src="https://solutions.appbrew.tech/web-sdk/appbrew-sdk.js"></script>The script defines window.appbrewSDK. It is untyped JavaScript with no build step and no npm package. It also leaves a helper named getRequestId on window, so avoid that name in your own code.
Methods
| Method | Returns | Waits for the app |
|---|---|---|
isApp() | boolean | no, synchronous |
getUserDetails() | Promise<UserDetails> | yes, 5 s |
addToCart(handle, variantId, quantity) | Promise<CartResult> | yes, 5 s |
addMultipleItemsToCart(items) | Promise<CartResult> | yes, 5 s |
gotoLink(link) | Promise<undefined> | no |
goBackInApp() | Promise<undefined> | no |
sendEvent(event, data) | Promise<undefined> | no |
isApp() is synchronous. The three methods that do not wait are declared async, so they return a promise, but it resolves immediately with undefined and carries no information about whether the app acted. There is nothing useful to await.
Every method except isApp() returns undefined when the bridge is absent, after logging to the console. Check isApp() first.
isApp
isApp(): booleantrue when the app's bridge is present on the page. Equivalent to typeof window.appbrew !== 'undefined'.
getUserDetails
getUserDetails(): Promise<UserDetails | undefined>Asks the app for the signed-in customer. Resolves within five seconds in every case, and never rejects.
The result is one of two shapes. On success the app sends every field below. On timeout the SDK synthesises { status: 'error', message: 'Could not fetch user details' } and nothing else — isLoggedIn, customerAccessToken, customer and tags are absent, not null. Branch on status before reading anything else.
type UserDetails =
| {
status: 'success'
isLoggedIn: boolean
customerAccessToken: string | null
customer: Customer | null
tags: string[]
}
| { status: 'error'; message: string }The success arm:
Prop
Type
Customer:
Prop
Type
Address carries id, address1, address2, city, province, country, countryCodeV2, zip, firstName, lastName, and phone. Every one of them is string | null.
The app serves a cached profile and only fetches when the cache is empty, so an edit made elsewhere may not be reflected until the next fetch.
addToCart
addToCart(
handle: string,
variantId: string,
quantity: number
): Promise<CartResult | undefined>Adds one item to the app's cart. variantId is a Shopify variant global id. The handle is sent along but the app ignores it: items are added by variant.
type CartResult = { status: 'success' | 'error'; message: string }status is 'error' only when the app did not confirm within five seconds. Success is weaker than it looks: the app replies once it has finished handling the request, and an error on its side still resolves as 'success'. A rejected or out-of-stock variant produces silence, and therefore a timeout. Re-read the cart rather than trusting either answer.
addMultipleItemsToCart
addMultipleItemsToCart(items: CartItem[]): Promise<CartResult | undefined>Adds several items in one cart update. Same result shape and same timeout as addToCart.
type CartItem = {
handle?: string // ignored
variantId: string
quantity: number
sellingPlanId?: string
customAttributes?: Record<string, string> | Array<{ key: string; value: string }>
}gotoLink
gotoLink(link: Link): Promise<undefined>Hands navigation to the app. Returns before the app has done anything.
interface Link {
kind: string
value: string
params?: Record<string, any>
external?: boolean
}Link kinds
kind | value | Result |
|---|---|---|
product | product handle | Native product screen |
collection | collection handle, or a global id | Native collection screen |
cart | 'cart' | The cart screen |
screen | screen name | That screen, with params |
page | page name | That page, with params |
url | a URL | Opens the matching native screen when the URL resolves to one, otherwise the app's webview. Goes to the device browser when external is true, or when the value is not an http(s) URL |
share | the message | The device share sheet |
back | any non-empty string | Goes back one screen |
Anything else is treated as a screen name.
A value is always required. gotoLink returns without doing anything when kind or value is empty, including for back and cart, where the value is otherwise unused.
Three screen values behave specially:
default-signinresolves to whichever sign-in screen this app is configured to use, which is the right way to open sign-in from a page. A hard-coded'signin'is wrong for apps that use a different one.searchis ignored unlessparams.searchQueryis long enough to search for.notifications-inboxopens the push provider's inbox rather than navigating to a screen.
kind: 'product' and kind: 'screen' with value: 'products' reach the same screen. The first is shorter; the second lets you pass extra params.
window.appbrewSDK.gotoLink({ kind: 'product', value: 'blue-tee' })
window.appbrewSDK.gotoLink({
kind: 'screen',
value: 'products',
params: { productHandle: 'blue-tee' },
})goBackInApp
goBackInApp(): Promise<undefined>Pops the current screen, returning the shopper to wherever they were before your page.
sendEvent
sendEvent(event: string, data?: Record<string, any>): Promise<undefined>Forwards an event to every analytics tracker the app has configured. Use one of the platform's own event names to join the app's existing funnel, or your own name for something only your page emits.
window.appbrewSDK.sendEvent('viewed_loyalty_page', { tier: 'gold' })Failure and timeouts
Nothing here rejects, and the app never sends an error. The three methods that wait resolve with { status: 'error' } five seconds after a call that got no reply. A timeout means one of:
- The app is older than the action you called. Unknown actions are dropped silently.
- The page is not rendered by a web-view block, so nothing is listening.
- The underlying operation failed, and the app reports failure by staying quiet.
Distinguishing them from the page is not possible. See version gates.
Live sample
A page exercising every method is published at solutions.appbrew.tech/web-sdk/appbrew-sdk-sample. Open it inside an app to see real payloads for that app's configuration.

