Every page asks for a different kind of attention. This chapter shows how to make Stand feel intentional on pricing, booking, docs, contact, and other high-intent pages without changing the install snippet.
Match Stand to each page with runtime rules, page-native prompts, supported API calls, and temporary JavaScript only when the built-in tools are not enough.
Need an exact capability definition, plan requirement, or limitation? Browse the Feature Reference.
Runtime rules
01
Edit behavior without redeploying the snippet.
App link
Open Chat widget behavior from Sites.
In Stand, open Sites, choose a site, then use Chat widget behavior to edit the ordered runtime rules. Changes apply to the next visitor load without changing the snippet.
Chat widget behavior is site configuration that the installed script fetches when the page loads. The organization owner can change the invitation without redeploying the snippet; other members can ask the owner to make the change. The script checks for an available responder and applies the first enabled behavior rule that matches the page path.
Each site has an ordered list of behavior rules. Put specific rules above broad rules. The empty path rule is the default fallback. The / rule is only the front page. Other paths match exactly, ignoring a trailing slash; add /* to match that page and every child path.
Practice
Try this next
01As the organization owner, open Sites → Chat widget behavior for the installed site and add an enabled rule for /pricing above the fallback rule.
02Choose Time and a short delay, then choose Custom greeting and write one pricing-specific invitation.
03Save, reload the published /pricing page, and confirm that a responder is available and the invitation appears after the delay.
04Test another page to confirm the fallback still applies. To repeat the greeting test, use a fresh browser context: greeting memory suppresses repeat invitations in the same browser.
05Change one setting at a time and compare the resulting conversations before using desktop auto-open more widely.
Field
How it works
Notes
FieldRule order
How it worksRules are evaluated top to bottom. The first enabled rule whose path matches is the only rule used.
NotesPut exact page rules above broader /* subtree rules. Use the empty path only for the fallback behavior.
FieldEnabled
How it worksDisabled rules are skipped without being deleted.
NotesUse this to pause an experiment while keeping its settings.
FieldPath pattern
How it worksMatched against window.location.pathname only. Query strings and hashes are ignored.
NotesEmpty path means default fallback. / means the front page only. /pricing and /pricing/ match only that page. /pricing/* also matches /pricing, /pricing/, and child pages such as /pricing/enterprise.
FieldWidget show trigger
How it worksControls when the floating widget is shown or opened after find reports availability.
NotesOn load runs immediately. Time waits for Delay. Scroll waits for Scroll %. None means no automatic floating widget reveal.
FieldDelay
How it worksUsed only by the Time trigger.
NotesSet the number of seconds to wait before the trigger fires.
FieldScroll %
How it worksUsed only by the Scroll trigger.
NotesSet how far down the page the visitor must scroll before the trigger fires.
FieldGreeting
How it worksControls the first visible chat invitation.
NotesDefault greeting keeps the selected rep or Stand-in’s configured greeting. No greeting suppresses it. Custom greeting uses Custom greeting text. To avoid repeated interruptions, the invitation appears once per visitor browser on that website, not on every reload; clearing site data or using another browser or device starts fresh.
FieldCustom greeting text
How it worksReplacement first message from the rep or Stand-in.
NotesWrite it from the rep or Stand-in point of view and tie it to the page context.
FieldHalf-sized
How it worksStarts the floating widget in a smaller presentation.
NotesUseful when the page needs quieter coverage.
FieldStep aside
How it worksLets the floating widget move aside after it has appeared.
NotesUseful when the widget should stay available without sitting over page content.
FieldOpen chat widget on desktop
How it worksOpens the full chat window when the selected default or custom greeting would appear.
NotesUses the same once-per-browser memory as the greeting. Mobile layouts show only the greeting bubble because an open chat takes over the screen.
FieldCustom JavaScript
How it worksOptional code that runs after Stand finds someone available and before the widget is shown.
NotesVisible only when custom JavaScript is enabled for the site. Use for temporary experiments, then move the winning behavior into the site.
FieldAllow Stand admin access
How it worksLets Stand administrators adjust behavior rules for that site.
NotesEnable only while Stand is actively helping with an experiment or integration, then turn it off.
Declarative prompts
02
Add page prompts before writing JavaScript.
These examples are for website editors who can add HTML and CSS. First install the Stand snippet from your site's Installation snippet in Sites and confirm that a human rep or enabled Stand-in is available on that page. Keep that snippet on the page; it loads these custom HTML elements and connects them to Stand.
Start with the button below. Paste its HTML where you want the invitation, reload the page, and select it after it appears. It opens the supplied chat window. Use the card when you also need supporting copy or a visitor message field, or stand-chatbox to keep the whole conversation in the page. Use the JavaScript API later in this chapter for controls you already own.
stand-button
Use a button for compact page prompts.
Preview
New-conversation greeting: I can help you install Stand. What would you like to know?
HTML
<stand-button hidden avatar message="I can help you install Stand. What would you like to know?">How does it work?</stand-button>
<style>
stand-button::part(button) { cursor: pointer; }
stand-button:hover::part(button) { background: #F4F4F4; }
</style>
A stand-button is the smallest in-page chat prompt. Use it when the page already has enough context and all you need is a compact invitation that opens Stand with a page-specific greeting from the rep or AI Stand-in.
Put it anywhere on the page and include native hidden to avoid a flash before the custom element upgrades. The message attribute supplies the greeting for a new conversation. If a chat is already in progress, the button reopens it without replacing its messages.
Use show-when="rep" for a selected live human, show-when="standin" for a selected AI Stand-in, or omit it for the default either behavior. Empty and unsupported values stay hidden. This filters the single responder returned by find or session restoration; it does not request a responder type, change routing, or guarantee who remains assigned.
To reveal surrounding content too, move hidden from the button to its closest dedicated ancestor and mark that ancestor data-stand-reveal. Use exactly one hidden location. A self-hidden component takes precedence, and Stand never climbs to an arbitrary hidden tab, modal, accordion, or responsive container.
HTML
<section hidden data-stand-reveal>
<h2>A product specialist is online</h2>
<stand-button show-when="rep" message="What would you like to ask our team?">
Chat with a person
</stand-button>
</section>
<section hidden data-stand-reveal>
<h2>Get help from an AI Stand-in</h2>
<stand-card show-when="standin" greeting="What would you like help with?" data-stand-action>
Ask our AI Stand-in
</stand-card>
</section>
Multiple buttons and cards evaluate the selected responder independently. If prompts share a marked wrapper, any matching child reveals it, while each mismatched component remains internally hidden. Use separate wrappers when the surrounding heading or copy is specific to a rep or Stand-in. External reveal is one-way, so keep the marker on a wrapper owned by this prompt instead of framework-managed application state.
stand-button attributes
hidden
Recommended in the original HTML on either the button or its dedicated data-stand-reveal wrapper so content cannot flash before the custom element upgrades.
show-when
Optional responder display filter: either (the default), rep, or standin. Empty or unsupported values fail closed. The filter does not change routing.
avatar
Optional. Shows the Available rep or eligible Stand-in avatar as the button icon. Omit it for a text-only button.
message
Opening greeting from the rep or Stand-in for a new conversation. This is not a message sent by the visitor. Until the visitor sends a first message, it replaces the greeting of an earlier open; it does not replace an existing transcript.
prompt
Optional internal context attached when a new session starts, if this button was the last chat opened before the visitor sends a first message. Visitors do not see it; reps can see it in history and AI Stand-ins use it as guidance. It does not update a session already in progress.
analytics-id
Optional attribution label included with the activation event so teams can compare buttons or placements.
class
Optional standard HTML class. Use it with ::part(button), ::part(icon), and ::part(label) to style the button.
stand-button slots and parts
default slot
The visible button label. Keep it short and action-oriented.
::part(button)
Styles the native button wrapper.
::part(icon)
Styles the optional avatar icon shown when the avatar attribute is present.
::part(label)
Styles the slotted button label.
stand-card
Use a card when the prompt needs context.
Adjust the preview, then copy the generated HTML. Replace sample copy and image URLs with your own; the example image path belongs to this documentation site. The greeting is spoken by the responder. Text entered in the message field is spoken by the visitor and is sent when they choose Start chat.
HTML
<stand-card hidden identity="avatar name" greeting="What would you like to know about this page?">
<strong>Ask a question about this page</strong>
<textarea data-stand-visitor-message aria-label="Your message" rows="3"></textarea>
<button slot="actions" type="button" data-stand-action>Start chat</button>
</stand-card>
The text field and action button are direct children. Start with this structure, then add the optional layout and styling below.
The configurable preview below uses the live Stand widget. Selecting its action with a message sends that text to Stand; if you already have a conversation, it continues there. The preview's identity comes from the responder selected for this website.
Preview
Plan the right call
Share your goal before choosing a time.
Useful when visitors are comparing meeting options.
Use this field for presentation markup; configure the message field and action with the controls below. The preview removes scripts and event handlers and wraps body content for display. Generated HTML retains your authored markup, so test custom changes on your own page.
Either is the default and is omitted from generated HTML. A wrapper adds hidden and data-stand-reveal around the card so surrounding content can reveal with it. Put hidden in only one location.
Leave maximum width empty to fill the containing block. Use a CSS length such as 42rem, 680px, or 80%; alignment is written as an ordinary host margin.
Enter a stable page-known ID first. The ID remains private correlation metadata. The optional name can label the visitor for authenticated reps, but it is not authentication or visible visitor chat content.
The button is a direct child marked with data-stand-action. When footer content is present, it shares that row; otherwise it uses the dedicated actions row.
Explicitly adds data-stand-action to stand-card. Leave both action choices off for an inert card.
Theme variants
HTML
<stand-card hidden theme="outlined horizontal cover-media" identity="avatar name title" greeting="I can help you decide whether a call is worth booking. What are you trying to figure out?">
<img slot="media" src="/images/guide/stand-card-implementation.png" alt="">
Plan the right call
Share your goal before choosing a time.
<textarea data-stand-visitor-message aria-label="Your message" rows="3" placeholder="What would you like help deciding?"></textarea>
<span slot="footer">Useful when visitors are comparing meeting options.</span>
<button slot="footer" type="button" data-stand-action style="margin-left: auto">Start chat</button>
</stand-card>
Publish this markup on the page that loads your Stand installation snippet. Replace sample content and media paths with your own.
Use stand-card when the invitation should carry supporting copy, identity, media, or a layout that feels like part of the page.
The default, unnamed slot holds body content. Named slots place your HTML in the media, actions, or footer region. Visual variants go in the space-separated theme attribute, and ::part() selectors style the component's internal surfaces. Slots control layout only; putting a button in an actions slot does not make it open chat. Stand generates only the availability fields named by identity. Omitting it hides the generated identity header; when identity is shown for an AI Stand-in, that header includes the AI badge.
The card fills the width of its containing block by default. To constrain or align it, put ordinary layout CSS directly in its style attribute—for example, style="max-width: 42rem; margin-inline: auto". These styles apply to the custom-element host, so they do not need to cross the shadow boundary.
Behavior is explicit. Mark one direct child with data-stand-action, or put that marker on stand-card to activate the whole surface. A child action and the message source must be direct children of the card, not nested inside another element. Mark the visitor-message source with data-stand-visitor-message. Use type="button" so a native button cannot submit an ancestor form before Stand upgrades the element or when its script is unavailable.
Cards use the same show-when and data-stand-reveal contract as buttons. The generated code can keep hidden on the card or move it to one dedicated wrapper. Stand removes exactly that one attribute after a matching result; it does not change aria-hidden, inert, dialog state, or framework state, and it does not re-hide an external wrapper later.
Add spotlight when a high-intent card should center on the visible viewport as the page continues scrolling behind a blurred glass layer. Stand leaves a visual imprint in the page so the layout remains complete. Spotlight includes a secondary Cancel action by default; use dismiss-label to change it, or author one direct data-stand-dismiss control.
To identify a signed-in visitor, set visitor-id and optionally visitor-name, or call StandChat.identify({ externalId, name }). Clear a global identity with StandChat.identify(null). These values are captured when a new conversation starts; changing them does not relabel a conversation already in progress. The page-asserted ID stays private and is never authorization. The optional name is visible to authenticated reps in dashboard and history, but not in the visitor chat.
Check the prompt on your own page
If it stays hidden, check the installed snippet, page coverage, and responder availability, then check the browser console for an invalid filter or conflicting action markers.
Use one action: either the card itself or one direct child. With no action marker, the card displays content but does not open chat.
Give each message field an accessible name. The generated field uses aria-label="Your message"; replace it with a visible label associated with a unique field ID when your layout allows.
Test with an empty field, a visitor message, and an existing conversation. Confirm that the greeting is not posted as visitor speech and that visitor text arrives once.
If spotlight stays inline, make sure the whole card fits in the visible viewport as you scroll it across the midpoint. A card taller or wider than that viewport cannot enter spotlight. A previous dismissal or activation is remembered for that card in the same browser.
Check keyboard access, narrow screens, image alternatives, and spotlight dismissal before publishing.
stand-card attributes
hidden
Recommended in the original HTML on either the card or its dedicated data-stand-reveal wrapper so content cannot flash before the custom element upgrades.
show-when
Optional responder display filter: either (the default), rep, or standin. Empty or unsupported values fail closed. The filter does not change routing.
greeting
Opening greeting from the rep or Stand-in for a new conversation. An explicit action opens chat. Until the visitor sends a first message, the greeting replaces the greeting of an earlier open; it does not replace an existing transcript.
prompt
Optional internal context attached when a new session starts, if this card was the last chat opened before the visitor sends a first message. Visitors do not see it; reps can see it in history and AI Stand-ins use it as guidance. It does not update a session already in progress.
analytics-id
Optional attribution label included with the activation event so teams can compare cards or placements. Labels may be reused; spotlight dismissal is still remembered per card and page.
spotlight
Optional. When the fully visible card crosses the viewport midpoint in either scroll direction, it centers above a blurred glass layer while the page keeps its native momentum. After placement it stays fixed, moving only enough to remain visible when an on-screen keyboard or browser controls reduce the viewport. Its actions stay fixed through each pointer gesture. A visual imprint preserves the underlying layout. Dismissal or activation suppresses the spotlight for that card in the visitor browser on that website origin. It can appear again after site data is cleared or in another browser or device.
dismiss-label
Optional label for the generated spotlight dismissal action. Missing or empty values use Cancel. The attribute has no effect without spotlight.
identity
Optional space-separated generated identity fields: avatar, name, and title. Omit it to hide the generated identity header, including the AI badge. When identity is shown for an AI Stand-in, the header also includes the AI badge.
data-stand-action
Makes the card focusable and opens chat on click, Enter, or Space. Nested links and form controls keep their own behavior. Do not also mark a child action; conflicting markers disable activation.
visitor-id / visitor-name
Optional page-known visitor identity captured when a new session starts. visitor-id is required when visitor-name is present. The ID is private correlation metadata; authenticated reps can see the name in dashboard and history. These attributes do not authenticate the visitor or update an existing session.
theme
Optional space-separated style variants. Supported values are outlined, elevated, horizontal, cover-media, stretch-media, and divided-footer.
class
Optional standard HTML class. Use it with ::part() selectors and your own slotted content selectors to customize styling.
style
Optional standard HTML style attribute on the card host. The card fills its containing block by default; use max-width and margins here to constrain and align it without crossing the shadow boundary.
stand-card slots
default slot
Main body content. Content never becomes behavior merely because of its element type.
slot="media"
Image, video, icon, or illustration content. It appears above the card body, or beside it when the horizontal theme is used.
slot="actions"
A dedicated row for primary and dismissal controls. Use the footer slot instead when an action should share a row with footer copy. Behavior still requires data-stand-action or data-stand-dismiss.
slot="footer"
Supplementary notes, badges, secondary copy, and actions that should share the same row. It has no divider unless theme includes divided-footer, and never implies behavior.
stand-card direct-child behavior markers
data-stand-action
Marks one direct child as the sole chat action. Do not combine it with data-stand-dismiss on the same child. A button should also use type="button" so it cannot submit an ancestor form before Stand upgrades the element or when the script is unavailable.
data-stand-visitor-message
Marks one direct child as the visitor-message source. Stand reads value when present, otherwise editable or text content. Nonempty text is sent when the action runs, to a new or existing chat. An empty source only opens chat.
data-stand-dismiss
Marks one direct child as the authored spotlight dismissal action. Do not combine it with data-stand-action on the same child. Use it instead of the generated fallback when you need custom markup. A native button should also use type="button" to avoid submitting an ancestor form.
stand-card theme variants
outlined
Removes the default shadow so the card reads as a bordered panel. If elevated is also selected, its stronger shadow takes precedence.
elevated
Adds a stronger shadow for shaded sections or high-emphasis prompts.
horizontal
Places card content beside the media slot on wider screens.
cover-media
Sizes image or video media to cover the card media area.
stretch-media
Stretches image or video media to fill the available media height.
divided-footer
Adds a divider above supplementary footer content. Actions remain in their own undivided region.
stand-card shadow parts
::part(card)
Styles the outer card surface.
::part(media)
Styles the media slot wrapper.
::part(header)
Styles the generated availability identity header.
::part(header-prefix)
Styles the generated avatar or mascot.
::part(title)
Styles the generated rep or Stand-in name.
::part(subtitle)
Styles the generated title or role.
::part(header-suffix)
Styles the generated AI badge.
::part(content)
Styles the default slot wrapper.
::part(actions)
Styles the actions slot wrapper.
::part(footer)
Styles the footer slot wrapper.
::part(dismiss)
Styles the generated spotlight dismissal action.
::part(imprint)
Styles the noninteractive card-shaped imprint that preserves the underlying page layout while spotlight is active.
::part(spotlight)
Styles the top-layer dialog that holds the active spotlight card.
Styled examples
Four common prompts, each tuned to the page.
These styled previews use sample people and AI identities to illustrate the design. Their generated HTML shows the actual selected responder on your website; it does not select Alex, Riley, or a responder type. Add a show-when filter when the surrounding invitation is specific to a human or AI.
Example 1
Pricing Page
Plans and limits→ Pricing detailsCompare plans, limits, and what changes by team size.
New-conversation greeting: I can help with pricing. What would you like to compare?
HTML
<stand-card hidden class="stand-card--pricing" theme="elevated" data-stand-action greeting="I can help with pricing. What would you like to compare?">
<span class="stand-card-eyebrow">Plans and limits</span>
<strong>→ Pricing details</strong>
<span>Compare plans, limits, and what changes by team size.</span>
</stand-card>
Before you bookPlan the right callShare your goal before choosing a time.
New-conversation greeting: I can help you decide whether a call is worth booking. What are you trying to figure out?
HTML
<stand-card hidden class="stand-card--booking" theme="outlined elevated horizontal cover-media" identity="avatar name title" data-stand-action greeting="I can help you decide whether a call is worth booking. What are you trying to figure out?">
<img slot="media" src="/images/guide/stand-card-implementation.png" alt="">
<span class="stand-card-eyebrow">Before you book</span>
<strong>Plan the right call</strong>
<span>Share your goal before choosing a time.</span>
<span slot="footer">Useful when visitors are comparing meeting options.</span>
</stand-card>
Not sure yet?Which option fits?Describe your goal and compare the likely paths.
New-conversation greeting: I can help you narrow this down. What are you trying to accomplish?
HTML
<stand-card hidden class="stand-card--service-fit" theme="outlined" identity="avatar name" data-stand-action greeting="I can help you narrow this down. What are you trying to accomplish?">
<span class="stand-card-eyebrow">Not sure yet?</span>
<strong>Which option fits?</strong>
<span>Describe your goal and compare the likely paths.</span>
</stand-card>
Have a question?Ask before you submitGet an answer before sending the contact form.
New-conversation greeting: I can answer a quick question before you contact the team. What would you like to know?
HTML
<stand-card hidden class="stand-card--contact" theme="outlined" identity="avatar name title" data-stand-action greeting="I can answer a quick question before you contact the team. What would you like to know?">
<span class="stand-card-eyebrow">Have a question?</span>
<strong>Ask before you submit</strong>
<span>Get an answer before sending the contact form.</span>
<span slot="footer">Good for visitors who are close to reaching out.</span>
</stand-card>
Pricing, booking, service fit, and contact pages usually need different invitations. Use a class on stand-card, style the shadow-DOM parts with ::part(), and style your own slotted content with normal CSS. Select any preview card to open the live widget when a responder is available. Its greeting applies to a new conversation; an existing chat reopens with its transcript intact.
stand-chatbox
Start the conversation where the question arises.
stand-chatbox is the third Stand custom element. It starts with your introductory HTML and a composer, then reveals the responder header when the visitor submits a question. The conversation includes messages, live replies, cards, and controls. Keep it inline, or add floating to open a floating panel when the visitor engages. It uses the same conversation engine as the floating widget. You supply HTML and CSS; Stand handles the messaging and recovery.
Use stand-button for a compact invitation, stand-card for a richer invitation with your own content, and stand-chatbox for the conversation itself. “Chatbox” names the visible component; “inline” describes its placement in normal page flow and does not mean CSS display: inline-block.
Install the usual Stand script once, then add the element. A new session starts with the visitor’s first message. Loading the page can restore an existing conversation, but does not start a new one or focus the composer. A fresh box stays hidden while loading or unavailable. An authenticated active conversation remains accessible even when new conversations are unavailable.
Try the live examples below with the Stand team or their AI Stand-in. Each example keeps a separate conversation; sending your first message starts a real chat. The code below each preview is the same HTML and CSS used to render it. The complete attribute reference is on Stand chatbox.
Live example · Inline pricing conversation
Didn’t find your question?
The live example appears here when chat is available. You can still explore and copy its code below.
HTML
<stand-chatbox
hidden
id="pricing-help"
prompt="The visitor is comparing plans. Answer pricing questions directly."
placeholder="Ask about pricing"
send-label="Ask"
max-height="560px"
analytics-id="pricing-help"
>
<h4 slot="intro" style="padding:10px 16px;margin:0;font-size:20px;font-weight:700;line-height:1.3">Didn’t find your question?</h4>
</stand-chatbox>
Put your heading, text, or other HTML in slot="intro" and style it with your page CSS. The responder header stays hidden until the first accepted question or an authenticated active conversation is restored. Add boolean show-header to show it from the outset. An expanded floating panel always shows its header and controls. Starting a new chat or abandoning an invalid saved session returns to the compact state.
The chatbox does not inherit a greeting from discovery. Add greeting="…" or pass a greeting to openChat() when you want an explicit opening message; otherwise it shows none. An authored greeting does not require showing the initial header. Configured sensitive-data notices and your footer slot remain available in the compact state.
Omit show-when or use show-when="either" for the selected human or AI responder. Use rep for a human or standin for AI; empty and unsupported values hide a fresh box. This filters display, not routing. Use native hidden on the element or its closest dedicated data-stand-reveal wrapper to prevent a pre-upgrade flash. Stand removes one hidden attribute when the box can appear, preferring the element itself; it never opens an arbitrary hidden ancestor or re-hides an external wrapper.
A pending first send or authenticated active conversation remains accessible if the filter changes. Ending or starting a new chat reapplies the filter. A saved conversation appears only after successful restoration. If it has expired, ended, or is rejected during restoration, the box returns to a fresh inline composer on that first visit when current availability and show-when permit. No additional reload is needed, and this does not create a session or focus the composer. Hiding a fresh chatbox does not remove the regular corner popup.
Each chatbox has its own conversation by default. The regular corner avatar popup, stand-button, stand-card, and StandChat.openChat() continue to use the global widget conversation. Give each independent box a stable id or session-key to restore its own conversation after reload. Existing global conversations do not move into independent boxes.
Add the boolean shared-session attribute only when the box should use the global conversation. The first eligible shared box receives global button/card activations and StandChat.openChat() calls; its corner avatar opens the same session, connection, and draft in a floating panel. Sending inline stays inline unless floating is also set, and minimizing a normal shared inline box returns to its composer. Use at most one shared box per page: additional opted-in boxes stay hidden. Set shared-session before connecting the element; changing it after initialization does not move conversations or change ownership.
HTML
<!-- Optional: use the global corner/button/card conversation. -->
<stand-chatbox hidden shared-session id="shared-help"></stand-chatbox>
<!-- Buttons and cards remain invitations to that global conversation. -->
<stand-button>Ask us</stand-button>
Choose who scrolls: the transcript or the page.
The default capped mode grows with the conversation up to 560px, then scrolls the transcript while keeping the composer available. Set max-height, or the CSS variable --stand-chatbox-max-height, to change the cap. Use height-mode="grow" when the whole page should expand as messages arrive. In grow mode, there is no transcript height cap.
HTML
<!-- Default: grow to 560px, then scroll the transcript. -->
<stand-chatbox hidden max-height="min(640px, 80dvh)"></stand-chatbox>
<!-- Page flow: every new message extends the page. -->
<stand-chatbox hidden height-mode="grow"></stand-chatbox>
Turn an in-page question into a floating conversation.
Add the boolean floating attribute for an FAQ or other compact entry point. The composer starts in the page. The first accepted send opens the same conversation in a floating panel, so visitors can continue while browsing. Explicitly calling openChat() or expand() also opens that panel; changing the attribute alone does not create a session.
Live example · Floating FAQ conversation
Didn’t find your question?
The live example appears here when chat is available. You can still explore and copy its code below.
HTML
<stand-chatbox
hidden
id="faq-help"
floating
placeholder="Ask it here"
send-label="Ask"
prompt="The visitor is reading the FAQ. Answer their question directly."
>
<h5 slot="intro" style="padding:10px 16px;margin:0;font-size:20px;font-weight:700;line-height:1.3">Didn’t find your question?</h5>
</stand-chatbox>
With floating, after a submitted question or active-session restoration, minimize or press Escape to keep the session and draft and return the same transcript to the page for browsing. The reply composer is hidden until you choose the compact Chat control with an expand arrow beside the header’s options menu. Its accessible name is Chat: Continue conversation, translated as Chat: Jatka keskustelua in Finnish. Clicking or tapping a noninteractive part of the collapsed card also resumes; scrolling, selecting text, links, and buttons keep their normal behavior. Resume restores the panel without focusing the message input. A first send keeps an already-focused composer focused. Incoming replies update the in-page transcript without reopening the panel, and a saved active floating conversation restores collapsed after reload.
Minimizing a manually expanded box before submitting a question returns to the compact inline composer with its draft. Start a new chat also returns to the fresh inline composer and focuses it as an explicit visitor action.
Independent chatboxes do not add a corner control. A shared box can also resume through its corner avatar. While its collapsed header’s resume control fits fully inside the visible viewport, that duplicate corner control stays hidden. Scrolling until it no longer fits brings the shared corner control back under your page’s reveal and hide settings. Those settings do not hide authored chatboxes or turn an independent box into the global conversation.
The collapsed transcript uses your inline height mode: scroll inside the usual cap, or let the page grow with height-mode="grow". Its header, introductory content, and footer remain visible. The expanded floating panel is always capped to the visible viewport. Removing floating returns the conversation inline with its composer. Try the floating version in the homepage FAQ; the pricing FAQ keeps its answers inline by default.
Use --stand-chatbox-floating-width (default 420px), --stand-chatbox-floating-height (default 560px), and --stand-chatbox-floating-shadow to style the panel. Its size still respects the visible viewport and the normal maximum height.
Style the conversation to match its surroundings.
Set custom properties on the element for the palette, font, border, radius, and spacing. Use ::part() for individual surfaces. Style your own slotted content with ordinary CSS. The editorial example uses show-header to display its custom avatar from the outset, with an explicit greeting and a paper-like layout. The dark hero example keeps the compact default.
Live example · Editorial conversation
SC
Work through the evidence with us.
The live example appears here when chat is available. You can still explore and copy its code below.
intro for authored HTML before the transcript, avatar for a custom avatar, header-actions alongside the controls, and footer for additional supporting content. Avatar and header actions follow the header’s visibility.
Shell and identity parts
chat, header, avatar for the avatar wrapper, avatar-image for the built-in image, rep-name, subtitle, ai-badge.
minimize-button; expand-button beside the collapsed header’s options menu; floating-resume for the shared chatbox’s corner avatar; and inline-resume for the page placeholder while the panel is expanded.
On Base, the supplied Powered by Stand link is present in the chatbox’s shadow DOM but hidden until the first submitted question. It appears on submission and for restored conversations with visitor messages; starting a fresh conversation hides it again. Eligible paid Pro and Business subscriptions omit the link element. Temporary access or collaborator status on Base does not remove attribution. Content you add to the footer slot is independent of this timing and adds to the built-in footer.
A custom avatar replaces only the visual; the responder’s name and AI or human identity still update. When shown, the header retains that identity and the AI badge. Preserve the configured sensitive-data notice and supplied attribution behavior. Give inputs at least a 16px font on iPhone and actions at least a 44px touch target. Avoid putting the box inside a fixed-height ancestor that clips it.
Include the page’s current state in the question.
A form, comparison, or experiment can add its visible selections as a quoted snapshot before sending. The cancelable stand-chatbox-before-send event lets synchronous page code update detail.message, set new-session detail.prompt, or call preventDefault(). This leaves the actual send, message IDs, and retry behavior with the chatbox. Add the listener after selecting the element; call methods after its stand-chatbox-ready event.
JavaScript
const box = document.querySelector('#experiment-chat');
box.addEventListener('stand-chatbox-before-send', (event) => {
// Read the visitor's current, visible selections from your own page.
const snapshot = document.querySelector('#experiment-summary').textContent.trim();
event.detail.message = '> ' + snapshot.replace(/\n/g, '\n> ')
+ '\n\n' + event.detail.message;
event.detail.prompt = 'Help assess this experiment. Separate evidence from assumptions.';
});
// Your own chip or action can also send through the built-in composer path.
document.querySelector('#ask-for-next-step').addEventListener('click', async () => {
await customElements.whenDefined('stand-chatbox');
box.sendMessage('What should I check next?');
});
customElements.whenDefined() waits for the method to exist. stand-chatbox-ready means initialized and can fire while hidden or unavailable; it does not confirm eligibility or successful restoration. sendMessage(text) returns whether the message entered the send flow, and returns false when a fresh box is unavailable or excluded by show-when. The stand-chatbox-send event reports that same acceptance; neither confirms delivery by the server. For the primary shared chatbox or a box with floating, expand() and collapse() control presentation; an ordinary independent inline box stays inline. Read presentationState or listen for stand-chatbox-state with detail.state and detail.previousState: inline, expanded, or collapsed. A private prompt applies only to a new session. Put context in the visible message when the visitor should see exactly what is being shared.
Keep the supplied behavior, or own the complete interface.
The chatbox retains the widget’s Markdown, streamed replies, typing indicators, links and cards, human handoff, follow-up forms, session recovery, localization, and end/new-chat controls. Existing Site routing, skills, quotas, and plan entitlements apply. Buttons, cards, and StandChat.openChat() remain global invitations; they never target a default independent box. An opted-in shared box can supply that global conversation, but inserting it while the regular popup is already open or has a draft, active session, or pending send leaves the popup and its corner control in place.
CSS can change a conventional transcript considerably. A game, animated character, spatial scene, or conversation rendered inside a canvas may need a different presentation architecture. Use the custom chat UI guide when you need to own that interaction and the visitor API lifecycle. The chatbox does not require rebuilding that client.
Developer API
03
Use the JavaScript API when you need custom page UI.
Live examples
Try both API patterns on this page.
Waiting for Stand
Page button
Opens chat with a replacement first message from the rep or Stand-in.
Use stand-button or stand-card first when a declarative prompt is enough. Use stand-chatbox when the full conversation belongs in the page. Use the JavaScript API when the site already has its own button, comparison table, booking flow, or component that should open Stand.
Declarative prompts can use show-when="rep", show-when="standin", or the default either behavior. This filters the responder already selected by find or session restoration; it does not change routing or guarantee a responder type. Put native hidden on the component, or on one dedicated ancestor marked data-stand-reveal when its surrounding copy should appear at the same time.
The JavaScript API is the window.StandChat object created by the Stand script. Because the script can load asynchronously, read it defensively and wire custom UI only after the object exists.
The object can exist before the availability lookup has finished. isAvailable() tells you whether Stand found a responder. whenAvailable(callback) is the usual place to reveal custom UI, and the callback receives a copied availability object: { available, human, name, title, avatarUrl, brandName }.
openChat(...) reveals and opens the widget. For a new session, the first argument supplies the rep or Stand-in greeting and the optional prompt supplies internal AI context. Until the visitor sends a first message, each open request, including a stand-button, stand-card, or the floating launcher, replaces the previous one’s greeting and context. An optional visitor message is sent to the conversation, including an existing session if one is already open. Greeting and context arguments do not rewrite an existing session.
identify(...) sets the stable visitor ID and optional display name for future sessions. Call it before starting a new session; it does not relabel an existing conversation. A name without an externalId is ignored. The ID stays private and the page-asserted data is never authentication; authenticated reps can see the name in dashboard and history.
The API exposes copied availability data only. It does not expose visitor tokens, websocket tokens, session tokens, or internal widget state.
To try these examples before you register, load stand.js with data-stand-id="demo". Stand Chat’s demo Stand-in answers and follows the greetings, visitor messages, and prompts your page supplies. Only a Stand-in answers in demo mode, so show-when="rep" prompts stay hidden. Behavior rules, knowledge, skills, and other configuration saved in Stand need your own site.
Code
<button type="button" data-ask-pricing hidden>Ask about pricing</button>
<script>
function setupPricingButton(tries = 0) {
const StandChat = window.StandChat
const button = document.querySelector("[data-ask-pricing]")
if (!StandChat || !button) {
if (tries < 200) {
window.setTimeout(() => setupPricingButton(tries + 1), 50)
}
return
}
StandChat.whenAvailable(() => {
button.hidden = false
})
button.addEventListener("click", () => {
StandChat.openChat("I can help with pricing. What would you like to compare?")
})
}
setupPricingButton()
</script>
This waits for the deferred Stand script and still works if Stand has already found someone available.
Code
<stand-button
hidden
avatar
message="Happy to walk you through installation. How do you host your website today?"
prompt="Answer installation questions directly. Ask for the website platform only when it changes the steps needed.">
Ask how Stand works
</stand-button>
<stand-card
hidden
greeting="I can help with pricing. What would you like to compare?"
prompt="Answer factual plan questions directly. For a recommendation, ask only for missing details that change the choice, such as expected chat volume.">
<strong>Compare pricing</strong>
<span>Ask which plan fits your site.</span>
<textarea data-stand-visitor-message rows="3" aria-label="Your pricing question" placeholder="What matters most to your team?"></textarea>
<button slot="actions" type="button" data-stand-action>Start chat</button>
</stand-card>
Omitting show-when allows either responder. The marked button opens chat and sends the textarea text to the new or current conversation; without data-stand-action the card is inert. Greeting and prompt apply only to a new session; before the visitor’s first message, the latest button, card, or launcher open supplies them. The prompt is not shown as visitor text, but its HTML attribute is inspectable and AI replies can use its contents. Add spotlight for a generated Cancel action, or dismiss-label to rename it.
Code
<section hidden data-stand-reveal>
<h2>A product specialist is online</h2>
<stand-button
show-when="rep"
message="What would you like to ask our team?">
Chat with a person
</stand-button>
</section>
<section hidden data-stand-reveal>
<h2>Get an immediate AI answer</h2>
<stand-card
show-when="standin"
greeting="What would you like help with?"
data-stand-action>
Ask our AI Stand-in
</stand-card>
</section>
Each wrapper owns the one native hidden attribute, so its responder-specific heading and prompt reveal together. Stand never opens an unmarked hidden ancestor. Multiple components may share a wrapper when its surrounding content is valid for every matching child; any match reveals the wrapper, while mismatched components remain internally hidden.
Code
<label for="feature-request">Describe your feature request</label>
<textarea id="feature-request"></textarea>
<button id="feature-request-submit" type="button" disabled>
Submit a feature request
</button>
<script>
function setupFeatureRequestBox(tries = 0) {
const StandChat = window.StandChat
const textarea = document.getElementById("feature-request")
const button = document.getElementById("feature-request-submit")
const prompt = "Record the submitted feature request in this conversation. Ask a clarifying question only if needed to understand it. Ask explicit permission before a separate research interview. Do not promise review, delivery, or contact from a person; use the enabled follow-up skill only when the visitor requests or agrees to it."
if (!StandChat || !textarea || !button) {
if (tries < 200) {
window.setTimeout(() => setupFeatureRequestBox(tries + 1), 50)
}
return
}
let standAvailable = StandChat.isAvailable()
const updateButton = () => {
button.disabled = !standAvailable || !textarea.value.trim()
}
StandChat.whenAvailable(() => {
standAvailable = true
updateButton()
})
textarea.addEventListener("input", updateButton)
button.addEventListener("click", () => {
const visitorMessage = textarea.value.trim()
if (!standAvailable || !visitorMessage) return
StandChat.openChat("What feature would you like to have?", visitorMessage, prompt)
})
updateButton()
}
setupFeatureRequestBox()
</script>
The button remains disabled until Stand is available and the textarea has content.
API
Meaning
Parameters
Return and notes
APIwindow.StandChat
MeaningGlobal public API object added by stand.js. It is the entry point for all methods below, not the <stand-chat> custom element.
ParametersNo parameters. Read it from window after the script has executed, for example const StandChat = window.StandChat.
Return and notesObject or undefined. It may exist before a responder has been found. Guard async pages and use whenAvailable before showing custom UI.
APIStandChat.initiallyHideChatButton()
MeaningSuppresses the default floating chat button so page code or declarative prompts control when chat appears. Behavior rules do not reveal the hidden button.
ParametersNo parameters.
Return and notesReturns undefined. Calling openChat later clears this hidden state and opens the widget immediately. To hide the button without page code, add data-stand-hide-button="true" to the stand.js script tag.
APIStandChat.openChat(repMessage = "")
MeaningReveals the widget and opens chat. A non-empty repMessage supplies the greeting for a new session and, before the visitor’s first message, replaces an earlier open’s greeting; it does not replace an existing transcript.
ParametersrepMessage: string. Use an empty string for the configured greeting.
Return and notesReturns undefined. If the widget is still loading, the open request is queued until availability and UI are ready. Of the requests made before Stand finds a responder, only the latest is kept; later requests are applied in order. If no responder is available, nothing visible opens.
APIStandChat.openChat(repMessage, visitorMessage)
MeaningOpens chat and sends visitorMessage. It starts a new conversation or adds a message to the current one.
ParametersrepMessage: string. visitorMessage: string. Empty or whitespace-only visitorMessage is ignored.
Return and notesUse when the page already collected text, such as a form field or textarea.
MeaningOpens chat and sends the visitor message. The prompt attaches internal context when a new session starts.
Parametersprompt: string. It is retained as context in dashboard History, not rendered as a visitor message. HTML attributes are inspectable, and AI replies can quote or paraphrase it; do not include secrets.
Return and notesUse for page facts and relevant help, such as "The visitor is comparing plans; ask only for missing details needed for a recommendation."
APIStandChat.openChat(repMessage, options)
MeaningAdvanced form for custom components that need attribution. It behaves like openChat with string arguments, using fields on options.
Return and notessourceType defaults to public_api. analyticsId and interaction are used for activation attribution; an open with interaction "auto" does not replace an invitation the visitor already opened. visitorIdentity is stored privately. A name without externalId is ignored.
APIStandChat.identify(identity)
MeaningSets the page-known identity used by future sessions without displaying it in visitor chat.
Parametersidentity: { externalId: string, name?: string } or null to clear it.
Return and notesReturns undefined. The external ID stays private; authenticated reps can see the optional name. Treat all page-asserted identity as unverified metadata, never authorization.
APIStandChat.isAvailable()
MeaningChecks whether the availability lookup found a live rep or AI Stand-in for this page.
ParametersNo parameters.
Return and notesReturns boolean. false means unavailable or the lookup has not finished.
APIStandChat.whenAvailable(callback)
MeaningRegisters a callback to run when Stand has a responder. If Stand is already available, the callback runs immediately with the current availability copy.
Return and notesReturns an unsubscribe function. Call it during component cleanup in React, Vue, or other SPA code.
APIStandChat.isHuman()
MeaningTells custom UI whether the available responder is a live human rep.
ParametersNo parameters.
Return and notesReturns boolean. false can mean AI Stand-in or not available yet.
APIStandChat.getName()
MeaningReads the available responder display name for custom UI.
ParametersNo parameters.
Return and notesReturns string or empty string.
APIStandChat.getTitle()
MeaningReads the available responder title or role for custom UI.
ParametersNo parameters.
Return and notesReturns string or empty string.
APIStandChat.getAvatar()
MeaningReads the available responder avatar URL for custom UI.
ParametersNo parameters.
Return and notesReturns string URL or empty string.
Advanced experimentation
04
Treat injected JavaScript as temporary.
Custom JavaScript runs on the customer website after Stand finds an Available rep or eligible Stand-in and before the button is shown. That is useful for experiments, but it is powerful enough to change page behavior or break part of the site.
Enable it only while you are actively testing a custom behavior. When a behavior works, implement it in the website itself and turn custom JavaScript off.
Questions
Common reader notes
Should custom JavaScript become permanent?
No. Use it to test. When the behavior proves useful, move it into the website implementation and turn injection off.
Does changing behavior require a new snippet?
No. Runtime behavior is returned by Stand after the snippet calls find.
Can a page show different prompts for a person and an AI Stand-in?
Yes. Set show-when to rep or standin on each stand-button or stand-card. The default either value preserves the existing behavior. This filters the selected responder; it does not change routing.
Can Stand reveal content around a button or card?
Yes. Put native hidden and data-stand-reveal on one dedicated closest ancestor instead of the component. Stand removes exactly one hidden attribute after a matching result and never traverses arbitrary hidden ancestors.