Chapter 10

Tune when Stand appears and what it asks.

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.

Stand Guidebook

Chapter 10 of 11

Field guide

What to learn in this chapter

Tune the visitor-facing widget per page: when it appears, whether it opens, what it says first, and which in-page prompts invite a conversation. The goal is a chat experience that feels helpful in the moment, not pasted over the site.

Use this chapter when Stand is installed but feels too quiet, too eager, or too generic on important pages.

Map visitor intent by path: home, pricing, docs, booking, contact, and comparison pages may need different invitations.

Choose how visible Stand should be on each page: hidden, button only, delayed, scroll-triggered, or opened with a specific message.

Write opening messages from the rep or stand-in point of view, tied to what the visitor is likely deciding right now.

Use stand-button or stand-card for page-native prompts when a small CTA fits better than the floating widget.

Use JavaScript only when built-in rules and declarative prompts cannot express the experiment.

Runtime rules

01

Edit behavior without redeploying the snippet.

Chat widget behavior is runtime site configuration. The installed snippet stays the same; Stand calls find immediately, receives the current behavior config, and applies the first matching rule for the visitor page.

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.

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.

Open Sites
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 normal site greeting. No greeting suppresses it. Custom greeting uses Custom greeting text.
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.
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.

A stand-button is the smallest in-page chat prompt. Use stand-card when the invitation needs more context, identity, media, or custom layout. Stand handles availability, identity, click behavior, and the opening message.

Put either element anywhere on the page, include hidden to avoid flicker, and Stand reveals it only after find returns an available rep or stand-in. The message attribute replaces the normal greeting for that open, so write it as the first thing the rep or stand-in says.

stand-button

Use a button for compact page prompts.

Use stand-button when the page already has enough context and all you need is a small call to action that opens Stand with the right first message.

Preview

Opens with: Happy to walk you through installation and get you started. How do you host your website today?

HTML

<stand-button hidden avatar message="Happy to walk you through installation and get you started. How do you host your website today?">How it works?</stand-button>

<style>
  stand-button::part(button) { cursor: pointer; }
  stand-button:hover::part(button) { background: #F4F4F4; }
</style>

stand-button attributes

hidden
Recommended in the original HTML so the button is invisible until Stand finds an available rep or stand-in.
avatar
Optional. Shows the available rep or stand-in avatar as the button icon. Omit it for a text-only button.
message
Opening message shown from the rep or stand-in instead of the usual greeting when the button opens chat.
prompt
Optional internal context attached to the session. Visitors do not see it; reps can see it in history and AI stand-ins use it as guidance.
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.

Use stand-card when the invitation should carry supporting copy, identity, media, or a layout that feels like part of the page.

The card API follows the same shape as component docs you may already know: authored content goes into slots, visual variants go in the space-separated theme attribute, and styling hooks are exposed as shadow parts. Stand owns the identity header from availability data, so the header prefix, title, subtitle, and AI badge are parts rather than author-provided slots.

HTML

<stand-card hidden class="stand-card--simple" hide-avatar hide-name hide-title message="I can help with pricing. What would you like to compare?">→ Pricing details</stand-card>

<style>
  .stand-card--simple::part(card) { cursor: pointer; }
  .stand-card--simple:hover::part(card) { background: #F4F4F4; }
</style>

stand-card attributes

hidden
Recommended in the original HTML so the card is invisible until Stand finds an available rep or stand-in.
message
Opening message shown from the rep or stand-in instead of the usual greeting when the card opens chat.
prompt
Optional internal context attached to the session. Visitors do not see it; reps can see it in history and AI stand-ins use it as guidance.
analytics-id
Optional attribution label included with the activation event so teams can compare cards or placements.
hide-avatar
Suppresses the avatar in the card header prefix.
hide-name
Suppresses the rep or stand-in name in the card title area.
hide-title
Suppresses the title or role in the card subtitle area.
theme
Optional space-separated style variants. Supported values are outlined, elevated, horizontal, cover-media, and stretch-media.
class
Optional standard HTML class. Use it with ::part() selectors and your own slotted content selectors to customize styling.

stand-card slots

default slot
Main body content. Use text, inline markup, links, or small controls.
slot="media"
Image, video, icon, or illustration content. It appears above the card body, or beside it when the horizontal theme is used.
slot="footer"
Supplementary content such as small actions, notes, badges, or secondary copy.

stand-card theme variants

outlined
Removes the default shadow so the card reads as a bordered panel.
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.

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(footer)
Styles the footer slot wrapper.

Configure the card

Theme variants

Preview identity

Preview

Alex Morgan

Product specialist

Plan the right call Share your goal before choosing a time.
Useful when visitors are comparing meeting options.

Generated HTML

<stand-card hidden theme="outlined horizontal cover-media" message="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.
  <span slot="footer">Useful when visitors are comparing meeting options.</span>
</stand-card>

Styled examples

Four common prompts, each tuned to the page.

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. Click any preview card; if Stand is present, it opens chat with that card's message.

Example 1

Pricing Page

Plans and limits→ Pricing detailsCompare plans, limits, and what changes by team size.

Opens with: I can help with pricing. What would you like to compare?

HTML

<stand-card hidden class="stand-card--pricing" theme="elevated" hide-avatar hide-name hide-title message="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>

CSS

.stand-card--pricing::part(card) {
  border-color: #F6C510;
  border-left: 4px solid #F6C510;
  background: #fffdf4;
  cursor: pointer;
}

.stand-card--pricing:hover::part(card) {
  background: #fff8d8;
}

.stand-card--pricing .stand-card-eyebrow {
  display: block;
  margin-bottom: 0.25rem;
  color: #C19802;
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
}

Example 2

Booking

Alex Morgan

Product specialist

Before you bookPlan the right callShare your goal before choosing a time.
Useful when visitors are comparing meeting options.

Opens with: 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" message="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>

CSS

.stand-card--booking {
  max-width: 42rem;
}

.stand-card--booking::part(card) {
  border-color: #38B9E0;
  background: #f7fcfd;
  cursor: pointer;
}

.stand-card--booking:hover::part(card) {
  background: #eef9fc;
}

.stand-card--booking::part(media) {
  min-height: 12rem;
}

.stand-card--booking .stand-card-eyebrow {
  color: #1B90B3;
  font-weight: 700;
}

Example 3

Service Fit

Riley

AI
Not sure yet?Which option fits?Describe your goal and compare the likely paths.

Opens with: I can help you narrow this down. What are you trying to accomplish?

HTML

<stand-card hidden class="stand-card--service-fit" theme="outlined" hide-title message="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>

CSS

.stand-card--service-fit::part(card) {
  border-color: #38B9E0;
  background: #f3fbfd;
  cursor: pointer;
}

.stand-card--service-fit:hover::part(card) {
  background: #e3f7fc;
}

.stand-card--service-fit::part(header-prefix) {
  background: #1B90B3;
}

.stand-card--service-fit .stand-card-eyebrow {
  color: #05485D;
  font-weight: 700;
}

Example 4

Contact

Alex Morgan

Product specialist

Need a person?Ask before you submitGet an answer before sending the contact form.
Good for visitors who are close to reaching out.

Opens with: 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" message="I can answer a quick question before you contact the team. What would you like to know?">
  <span class="stand-card-eyebrow">Need a person?</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>

CSS

.stand-card--contact::part(card) {
  border-style: dashed;
  border-color: #A3A3A3;
  background: white;
  cursor: pointer;
}

.stand-card--contact:hover::part(card) {
  background: #F4F4F4;
}

.stand-card--contact::part(footer) {
  color: #676767;
  font-style: italic;
}

.stand-card--contact .stand-card-eyebrow {
  color: #B3371B;
  font-weight: 700;
}

Developer API

03

Use the JavaScript API when you need custom page UI.

Use stand-button or stand-card first when a declarative prompt is enough. Use the JavaScript API when the site already has its own button, comparison table, booking flow, or component that should open Stand.

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 the widget and starts the chat. The first argument replaces the rep or stand-in greeting for that open. The optional visitor message becomes the visitor's first sent message. The optional prompt is internal context stored in dashboard history and used by the AI stand-in; visitors do not see it.

The API exposes copied availability data only. It does not expose visitor tokens, websocket tokens, session tokens, or internal widget state.

Open Stand from a page button

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()

This waits for the deferred Stand script and still works if Stand has already found someone available.

Declarative stand-button and stand-card prompts

<stand-button
  hidden
  avatar
  message="Happy to walk you through installation. How do you host your website today?"
  prompt="Find out the visitor's website platform and where they are in the install process before giving setup guidance.">
  Ask how Stand works
</stand-button>

<stand-card
  hidden
  message="I can help with pricing. What would you like to compare?"
  prompt="Ask about team size, expected chat volume, and whether they need AI stand-in coverage before recommending a plan.">
  <strong>Compare pricing</strong>
  <span>Ask which plan fits your site.</span>
</stand-card>

The message is visible to the visitor; the prompt is internal context for the rep or stand-in.

Feature request box

<label for="feature-request">Submit a 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 = "Ask visitor for more details about the feature and interview them about their use-case. The goal is to record the feature clearly in this conversation so that the product team can understand it. In the end of the conversation, thank and name who is your rep and say that they will review the feature. Ask if visitor wants to them to also follow up."

    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.

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.

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.
ParametersNo parameters.
Return and notesReturns undefined. Calling openChat later clears this hidden state and opens the widget immediately.
APIStandChat.openChat(repMessage = "")
MeaningReveals the widget and opens chat. A non-empty repMessage replaces the default first message from the rep or stand-in for this opening.
ParametersrepMessage: string. Use an empty string to keep the configured greeting.
Return and notesReturns undefined. If the widget is still loading, the open request is queued until availability and UI are ready. If no responder is available, nothing visible opens.
APIStandChat.openChat(repMessage, visitorMessage)
MeaningOpens chat and sends visitorMessage as the visitor's first message after the greeting.
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.
APIStandChat.openChat(repMessage, visitorMessage, prompt)
MeaningOpens chat, sends the visitor message, and attaches internal context to the session.
Parametersprompt: string. It is hidden from visitors, visible in dashboard history, and used as AI stand-in guidance.
Return and notesUse for context like "interview this feature request" or "ask about team size before recommending a plan."
APIStandChat.openChat(repMessage, options)
MeaningAdvanced form for custom components that need attribution. It behaves like openChat with string arguments, using fields on options.
Parametersoptions.visitorMessage?: string; options.prompt?: string; options.sourceType?: string; options.analyticsId?: string; options.interaction?: string.
Return and notessourceType defaults to public_api. analyticsId and interaction are used for activation attribution; they do not change the conversation text.
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.
Parameterscallback: function receiving { available, human, name, title, avatarUrl, brandName }.
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 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.

Continue the guide

Build Stand as a learning loop, one chapter at a time.

Try the guide on one real page.