Skip to main content

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
  }
});
FieldTypeRequiredDescription
messagestringYesToast message
durationnumberNoDisplay time in ms (default 5000)
isErrorbooleanNoShow as error toast
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
}
FieldTypeRequiredDescription
titlestringYesModal title
messagestringYesModal body text
primaryAction.contentstringYesPrimary button label
primaryAction.destructivebooleanNoRed button styling
secondaryAction.contentstringNoSecondary button label
Response:
{
  action: 'primary' | 'secondary' | 'dismissed';
}
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
});
FieldTypeDescription
titlestringPage title
primaryActionobjectMain action button
secondaryActionsarrayAdditional action buttons
breadcrumbsarrayNavigation breadcrumbs

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
  }
});
FieldTypeDescription
urlstringDestination URL
newContextbooleanLeave app context (default false)
externalbooleanExternal URL
newTabbooleanOpen 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', ... }, ...]
}
FieldTypeDescription
resourceTypestringType of resource (see below)
multiplebooleanAllow multiple selection
initialSelectionarrayPre-selected items
filterobjectFilter criteria
Resource Types:
TypeDescription
productProducts
product_variantProduct variants
collectionCollections
customerCustomers
orderOrders
blogBlogs
articleBlog articles
pagePages
menuNavigation menus
fileFiles/media
metaobjectMetaobjects
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' });
    }
  }
});