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',
}))