Cookbook

Events & Extensions

Subscribe to real-time events pushed from the host via the framework, and extend identity claims. Each event type has a dedicated hook — never use capabilities.events.* directly.

Identity Events

Subscribe to login, logout, refresh, and expired events. Useful for tracking agent authentication state in your extension.

Permission: events:identity Event types: login, logout, refresh, expired

Hook usage

import { useIdentityEvent } from '@stackable-labs/sdk-extension-react'

useIdentityEvent('login', (event) => {
  console.log('User logged in:', event.data.state.user?.email)
})
useIdentityEvent('logout', () => {
  console.log('User logged out')
})

Full component example

import { useIdentityEvent, Surface, ui } from '@stackable-labs/sdk-extension-react'
import type { IdentityEvent } from '@stackable-labs/sdk-extension-contracts'
import { useState } from 'react'

export function Header(): React.ReactElement {
  const [user, setUser] = useState<string | null>(null)

  useIdentityEvent('login', (event: IdentityEvent) => {
    setUser(event.data.state.user?.email ?? null)
  })

  useIdentityEvent('logout', () => {
    setUser(null)
  })

  return (
    <Surface id="slot.header">
      <ui.Text className="text-xs">{user ?? 'Not logged in'}</ui.Text>
    </Surface>
  )
}

Messaging Events

Subscribe to postback button clicks from the Zendesk messaging widget. The actionName is the button's display text, not a programmatic identifier.

Permission: events:messaging

Hook usage

import { useMessagingEvent } from '@stackable-labs/sdk-extension-react'

useMessagingEvent('postback:Buy Now', (event) => {
  console.log('Postback:', event.data.actionName, event.data.conversationId)
})

Full component example

import { useMessagingEvent, Surface, ui } from '@stackable-labs/sdk-extension-react'
import type { MessagingEventHandler } from '@stackable-labs/sdk-extension-contracts'
import { useState } from 'react'

export function Content(): React.ReactElement {
  const [lastPostback, setLastPostback] = useState<string | null>(null)

  useMessagingEvent('postback', (event) => {
    setLastPostback(event.data.actionName)
  })

  return (
    <Surface id="slot.content">
      <ui.Text className="text-xs">{lastPostback ?? 'No postbacks yet'}</ui.Text>
    </Surface>
  )
}

Activity Events

Subscribe to host site activity events like page views, clicks, and purchases pushed from the host via the framework. Activity event names are domain-stripped — use useActivityEvent('product_view', ...) not 'activity:product_view'.

Permission: events:activity Well-known events: click, page_view, form_submit, product_view, add_to_cart, purchase, search

Hook usage

import { useActivityEvent } from '@stackable-labs/sdk-extension-react'

useActivityEvent('product_view', (event) => {
  console.log('Activity:', event.eventName, event.data)
})

Full component example

import { useActivityEvent, Surface, ui } from '@stackable-labs/sdk-extension-react'
import type { ActivityEventHandler } from '@stackable-labs/sdk-extension-contracts'
import { useState } from 'react'

export function Content(): React.ReactElement {
  const [lastEvent, setLastEvent] = useState<string | null>(null)

  useActivityEvent('page_view', (event) => {
    setLastEvent(event.data.url as string)
  })

  return (
    <Surface id="slot.content">
      <ui.Text className="text-xs">{lastEvent ?? 'No activity yet'}</ui.Text>
    </Surface>
  )
}

Extend Identity

Enrich identity JWT claims before signing. The host sends base claims (external_id, email, name) and your handler returns additional claims to merge into the token.

Permission: extend:identity

Hook usage

import { useExtendIdentity } from '@stackable-labs/sdk-extension-react'

useExtendIdentity((claims) => ({
  external_id: `custom_${claims.external_id}`,
  loyalty_tier: 'gold',
}))

Full component example

import { useExtendIdentity } from '@stackable-labs/sdk-extension-react'
import type { ExtendIdentityHandler } from '@stackable-labs/sdk-extension-contracts'

// Enrich identity JWT claims before signing.
// The host sends base claims (external_id, email, name),
// and your handler returns additional claims to merge.
useExtendIdentity((claims) => ({
  external_id: `shopify_${claims.external_id}`,
  loyalty_tier: 'gold',
}))

Auto-generated from Stackable Extension SDK. Questions/Issues? developers@stackablelabs.com

Previous
Capability Examples
Events & Extensions | Stackable Labs :. Dev Documentation