Documentation Index
Fetch the complete documentation index at: https://docs.launchmystore.io/llms.txt
Use this file to discover all available pages before exploring further.
App Bridge Actions Reference
App Bridge supports 19 action types for communicating between your embedded app and the LaunchMyStore admin. This page documents all available actions, their payloads, and responses.
Action Dispatch Methods
dispatch()
Fire-and-forget action that doesn’t wait for a response:
app.dispatch({
type: 'TOAST',
payload: { message: 'Saved!' }
});
dispatchAndWait()
Dispatch and wait for a response (returns a Promise):
const result = await app.dispatchAndWait({
type: 'RESOURCE_PICKER',
payload: { resourceType: 'product' }
});
UI Actions
TOAST
Show a toast notification:
app.dispatch({
type: 'TOAST',
payload: {
message: 'Changes saved successfully!',
duration: 3000, // ms, default 5000
isError: false // Red styling if true
}
});
| Field | Type | Required | Description |
|---|
message | string | Yes | Toast message |
duration | number | No | Display time in ms (default 5000) |
isError | boolean | No | Show as error toast |
MODAL_OPEN
Open a confirmation modal:
const result = await app.dispatchAndWait({
type: 'MODAL_OPEN',
payload: {
title: 'Delete Product?',
message: 'This action cannot be undone. All product data will be permanently removed.',
primaryAction: {
content: 'Delete',
destructive: true
},
secondaryAction: {
content: 'Cancel'
}
}
});
if (result.action === 'primary') {
// User clicked Delete
} else if (result.action === 'secondary') {
// User clicked Cancel
} else {
// Modal was dismissed
}
| Field | Type | Required | Description |
|---|
title | string | Yes | Modal title |
message | string | Yes | Modal body text |
primaryAction.content | string | Yes | Primary button label |
primaryAction.destructive | boolean | No | Red button styling |
secondaryAction.content | string | No | Secondary button label |
Response:
{
action: 'primary' | 'secondary' | 'dismissed';
}
MODAL_CLOSE
Close the current modal programmatically:
app.dispatch({
type: 'MODAL_CLOSE'
});
LOADING_START
Show the loading bar:
app.dispatch({
type: 'LOADING_START'
});
LOADING_STOP
Hide the loading bar:
app.dispatch({
type: 'LOADING_STOP'
});
FULLSCREEN_ENTER
Enter fullscreen mode:
app.dispatch({
type: 'FULLSCREEN_ENTER'
});
FULLSCREEN_EXIT
Exit fullscreen mode:
app.dispatch({
type: 'FULLSCREEN_EXIT'
});
Title Bar Actions
TITLE_BAR_UPDATE
Update the admin title bar:
app.dispatch({
type: 'TITLE_BAR_UPDATE',
payload: {
title: 'Product Reviews',
primaryAction: {
content: 'Add Review',
onAction: 'PRIMARY_ACTION' // Event name to listen for
},
secondaryActions: [
{
content: 'Export',
onAction: 'EXPORT_ACTION'
},
{
content: 'Settings',
onAction: 'SETTINGS_ACTION'
}
],
breadcrumbs: [
{ content: 'Apps', url: '/admin/apps' },
{ content: 'My App', url: '/admin/apps/my-app' }
]
}
});
// Listen for button clicks
app.subscribe('PRIMARY_ACTION', () => {
// Handle Add Review click
});
app.subscribe('EXPORT_ACTION', () => {
// Handle Export click
});
| Field | Type | Description |
|---|
title | string | Page title |
primaryAction | object | Main action button |
secondaryActions | array | Additional action buttons |
breadcrumbs | array | Navigation breadcrumbs |
Navigation Actions
REDIRECT
Navigate to a different page:
// Internal navigation
app.dispatch({
type: 'REDIRECT',
payload: {
url: '/admin/products/123',
newContext: false // Stay in app context
}
});
// External link
app.dispatch({
type: 'REDIRECT',
payload: {
url: 'https://external-site.com',
external: true,
newTab: true
}
});
| Field | Type | Description |
|---|
url | string | Destination URL |
newContext | boolean | Leave app context (default false) |
external | boolean | External URL |
newTab | boolean | Open in new tab |
Set up the app navigation menu:
app.dispatch({
type: 'NAVIGATION_MENU',
payload: {
items: [
{ label: 'Dashboard', destination: '/' },
{ label: 'Reviews', destination: '/reviews' },
{ label: 'Settings', destination: '/settings' }
],
active: '/reviews'
}
});
HISTORY_PUSH
Push a new state to browser history:
app.dispatch({
type: 'HISTORY_PUSH',
payload: {
path: '/reviews?filter=pending'
}
});
HISTORY_REPLACE
Replace current history state:
app.dispatch({
type: 'HISTORY_REPLACE',
payload: {
path: '/reviews'
}
});
Resource Picker
RESOURCE_PICKER
Open a picker to select resources:
const result = await app.dispatchAndWait({
type: 'RESOURCE_PICKER',
payload: {
resourceType: 'product',
multiple: true,
initialSelection: [
{ id: 'prod_123' },
{ id: 'prod_456' }
],
filter: {
status: 'active'
}
}
});
if (!result.cancelled) {
console.log('Selected:', result.selection);
// [{ id: 'prod_789', title: 'Product', ... }, ...]
}
| Field | Type | Description |
|---|
resourceType | string | Type of resource (see below) |
multiple | boolean | Allow multiple selection |
initialSelection | array | Pre-selected items |
filter | object | Filter criteria |
Resource Types:
| Type | Description |
|---|
product | Products |
product_variant | Product variants |
collection | Collections |
customer | Customers |
order | Orders |
blog | Blogs |
article | Blog articles |
page | Pages |
menu | Navigation menus |
file | Files/media |
metaobject | Metaobjects |
Response:
{
cancelled: boolean;
selection: Resource[]; // Array of selected resources
}
Save Bar
CONTEXTUAL_SAVE_BAR_SHOW
Show the save/discard bar:
app.dispatch({
type: 'CONTEXTUAL_SAVE_BAR_SHOW',
payload: {
saveAction: {
content: 'Save',
onAction: 'SAVE_ACTION'
},
discardAction: {
content: 'Discard',
onAction: 'DISCARD_ACTION'
},
fullWidth: false
}
});
app.subscribe('SAVE_ACTION', async () => {
await saveChanges();
app.dispatch({ type: 'CONTEXTUAL_SAVE_BAR_HIDE' });
});
app.subscribe('DISCARD_ACTION', () => {
discardChanges();
app.dispatch({ type: 'CONTEXTUAL_SAVE_BAR_HIDE' });
});
CONTEXTUAL_SAVE_BAR_HIDE
Hide the save bar:
app.dispatch({
type: 'CONTEXTUAL_SAVE_BAR_HIDE'
});
Leave Confirmation
LEAVE_CONFIRMATION_ENABLE
Show confirmation when leaving with unsaved changes:
app.dispatch({
type: 'LEAVE_CONFIRMATION_ENABLE',
payload: {
message: 'You have unsaved changes. Are you sure you want to leave?'
}
});
LEAVE_CONFIRMATION_DISABLE
Disable leave confirmation:
app.dispatch({
type: 'LEAVE_CONFIRMATION_DISABLE'
});
Session & Auth
SESSION_TOKEN_REQUEST
Get a session token for authenticated API calls:
const result = await app.dispatchAndWait({
type: 'SESSION_TOKEN_REQUEST'
});
const token = result.token;
// Use token for API calls
fetch('/api/data', {
headers: {
'Authorization': `Bearer ${token}`
}
});
Response:
{
token: string; // JWT token
expires: number; // Expiration timestamp
}
For convenience, use app.getSessionToken() which handles caching and auto-refresh.
User & Environment
USER_REQUEST
Get current user information:
const result = await app.dispatchAndWait({
type: 'USER_REQUEST'
});
console.log(result.user);
// { id: 'user_123', email: 'admin@store.com', name: 'Admin' }
CONFIG_REQUEST
Get app configuration:
const result = await app.dispatchAndWait({
type: 'CONFIG_REQUEST'
});
console.log(result.config);
// { apiKey: '...', shopDomain: 'store.launchmystore.io', ... }
ENVIRONMENT_REQUEST
Get environment information:
const result = await app.dispatchAndWait({
type: 'ENVIRONMENT_REQUEST'
});
console.log(result);
// { locale: 'en-US', timezone: 'America/New_York', mobile: false }
FEATURES_REQUEST
Check available features:
const result = await app.dispatchAndWait({
type: 'FEATURES_REQUEST'
});
console.log(result.features);
// ['contextual_save_bar', 'fullscreen', 'resource_picker']
Utility Actions
PRINT
Trigger browser print:
app.dispatch({
type: 'PRINT'
});
SHARE
Open share dialog (mobile):
app.dispatch({
type: 'SHARE',
payload: {
title: 'Check out this product',
url: 'https://store.com/products/widget'
}
});
CLIPBOARD_WRITE
Copy text to clipboard:
await app.dispatchAndWait({
type: 'CLIPBOARD_WRITE',
payload: {
text: 'Text to copy'
}
});
CLIPBOARD_READ
Read from clipboard (requires user interaction):
const result = await app.dispatchAndWait({
type: 'CLIPBOARD_READ'
});
console.log(result.text);
Clipboard read requires the action to be triggered by a user gesture (click, keypress). It will fail if called automatically.
SCANNER_OPEN
Open barcode/QR scanner (mobile):
const result = await app.dispatchAndWait({
type: 'SCANNER_OPEN'
});
if (!result.cancelled) {
console.log('Scanned:', result.data);
}
Lifecycle Events
Subscribe to lifecycle events:
// App is being unloaded
app.subscribe('LIFECYCLE_UNLOAD', () => {
// Cleanup
});
// App visibility changed
app.subscribe('LIFECYCLE_VISIBILITY', (data) => {
console.log('Visible:', data.visible);
});
// App was focused
app.subscribe('LIFECYCLE_FOCUS', () => {
// Refresh data
});
Error Handling
All dispatchAndWait calls can throw errors:
try {
const result = await app.dispatchAndWait({
type: 'RESOURCE_PICKER',
payload: { resourceType: 'product' }
});
} catch (error) {
switch (error.code) {
case 'TIMEOUT':
console.error('Action timed out');
break;
case 'CANCELLED':
console.log('User cancelled');
break;
case 'NOT_SUPPORTED':
console.error('Action not supported');
break;
default:
console.error('Unknown error:', error);
}
}
Complete Example
import { createApp } from '@launchmystore/app-bridge';
// Initialize
const app = createApp({
apiKey: 'your-client-id',
host: new URLSearchParams(location.search).get('host')
});
// Set up title bar
app.dispatch({
type: 'TITLE_BAR_UPDATE',
payload: {
title: 'Product Reviews',
primaryAction: {
content: 'Add Review',
onAction: 'ADD_REVIEW'
}
}
});
// Handle title bar actions
app.subscribe('ADD_REVIEW', async () => {
const result = await app.dispatchAndWait({
type: 'RESOURCE_PICKER',
payload: { resourceType: 'product' }
});
if (!result.cancelled && result.selection.length > 0) {
const product = result.selection[0];
// Get session token for API call
const token = await app.getSessionToken();
// Show loading
app.dispatch({ type: 'LOADING_START' });
try {
await fetch('/api/reviews', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ productId: product.id })
});
app.dispatch({
type: 'TOAST',
payload: { message: 'Review added!' }
});
} catch (error) {
app.dispatch({
type: 'TOAST',
payload: { message: 'Failed to add review', isError: true }
});
} finally {
app.dispatch({ type: 'LOADING_STOP' });
}
}
});