|
| 1 | +--- |
| 2 | +title: Crisp |
| 3 | +description: Show performance-optimized Crisp in your Nuxt app. |
| 4 | +links: |
| 5 | + - label: useScriptCrisp |
| 6 | + icon: i-simple-icons-github |
| 7 | + to: https://github.com/nuxt/scripts/blob/main/src/runtime/registry/crisp.ts |
| 8 | + size: xs |
| 9 | + - label: "<ScriptCrisp>" |
| 10 | + icon: i-simple-icons-github |
| 11 | + to: https://github.com/nuxt/scripts/blob/main/src/runtime/components/ScriptCrisp.vue |
| 12 | + size: xs |
| 13 | +--- |
| 14 | + |
| 15 | +[Crisp](https://crisp.chat/) is a customer messaging platform that lets you communicate with your customers through chat, email, and more. |
| 16 | + |
| 17 | +Nuxt Scripts provides a [useScriptCrisp](#usescriptcrisp) composable and a headless Facade Component [useScriptCrisp](#scriptcrisp) component to interact with the Crisp. |
| 18 | + |
| 19 | +## ScriptCrisp |
| 20 | + |
| 21 | +The `ScriptCrisp` component is headless Facade Component wrapping the [useScriptCrisp](#usescriptcrisp) composable, providing a simple, performance optimized way to load Crisp in your Nuxt app. |
| 22 | + |
| 23 | +It's optimized for performance by leveraging the [Element Event Triggers](/docs/guides/script-triggers#element-event-triggers), only loading the Crisp when specific elements events happen. |
| 24 | + |
| 25 | +By default, it will load on the `click` DOM event. |
| 26 | + |
| 27 | +### Demo |
| 28 | + |
| 29 | +::code-group |
| 30 | + |
| 31 | +:crisp-demo{label="Output"} |
| 32 | + |
| 33 | +```vue [Input] |
| 34 | +<script setup lang="ts"> |
| 35 | +const isLoaded = ref(false) |
| 36 | +</script> |
| 37 | +
|
| 38 | +<template> |
| 39 | +<div class="not-prose"> |
| 40 | + <div class="flex items-center justify-center p-5"> |
| 41 | + <ScriptCrisp id="b1021910-7ace-425a-9ef5-07f49e5ce417" class="crisp"> |
| 42 | + <template #awaitingLoad> |
| 43 | + <div class="crisp-icon" /> |
| 44 | + </template> |
| 45 | + <template #loading> |
| 46 | + <ScriptLoadingIndicator color="black" /> |
| 47 | + </template> |
| 48 | + </ScriptCrisp> |
| 49 | + </div> |
| 50 | + <div class="text-center"> |
| 51 | + <UAlert v-if="!isLoaded" class="mb-5" size="sm" color="blue" variant="soft" title="Click to load" description="Clicking the button to the right will load the Crisp script" /> |
| 52 | + <UAlert v-else color="green" variant="soft" title="Crisp is loaded" description="The Crisp Facade component is no longer being displayed." /> |
| 53 | + </div> |
| 54 | +</div> |
| 55 | +</template> |
| 56 | +
|
| 57 | +<style> |
| 58 | +.crisp { |
| 59 | + width: 54px; |
| 60 | + height: 54px; |
| 61 | + border-radius: 54px; |
| 62 | + cursor: pointer; |
| 63 | + background-color: #1972F5; |
| 64 | + position: relative; /* change to fixed */ |
| 65 | + bottom: 20px; |
| 66 | + right: 24px; |
| 67 | + z-index: 100000; |
| 68 | + box-shadow: 0 4px 10px 0 rgba(0,0,0!important,.05) !important; |
| 69 | +} |
| 70 | +.crisp-icon { |
| 71 | + position: absolute; |
| 72 | + top: 16px; |
| 73 | + left: 11px; |
| 74 | + width: 32px; |
| 75 | + height: 26px; |
| 76 | + background-size: contain; |
| 77 | + background-repeat: no-repeat; |
| 78 | + background-position: center; |
| 79 | + background-image: url(data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjMwIiB3aWR0aD0iMzUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxmaWx0ZXIgaWQ9ImEiIGhlaWdodD0iMTM4LjclIiB3aWR0aD0iMTMxLjQlIiB4PSItMTUuNyUiIHk9Ii0xNS4xJSI+PGZlTW9ycGhvbG9neSBpbj0iU291cmNlQWxwaGEiIG9wZXJhdG9yPSJkaWxhdGUiIHJhZGl1cz0iMSIgcmVzdWx0PSJzaGFkb3dTcHJlYWRPdXRlcjEiLz48ZmVPZmZzZXQgZHk9IjEiIGluPSJzaGFkb3dTcHJlYWRPdXRlcjEiIHJlc3VsdD0ic2hhZG93T2Zmc2V0T3V0ZXIxIi8+PGZlR2F1c3NpYW5CbHVyIGluPSJzaGFkb3dPZmZzZXRPdXRlcjEiIHJlc3VsdD0ic2hhZG93Qmx1ck91dGVyMSIgc3RkRGV2aWF0aW9uPSIxIi8+PGZlQ29tcG9zaXRlIGluPSJzaGFkb3dCbHVyT3V0ZXIxIiBpbjI9IlNvdXJjZUFscGhhIiBvcGVyYXRvcj0ib3V0IiByZXN1bHQ9InNoYWRvd0JsdXJPdXRlcjEiLz48ZmVDb2xvck1hdHJpeCBpbj0ic2hhZG93Qmx1ck91dGVyMSIgdmFsdWVzPSIwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwLjA3IDAiLz48L2ZpbHRlcj48cGF0aCBpZD0iYiIgZD0iTTE0LjIzIDIwLjQ2bC05LjY1IDEuMUwzIDUuMTIgMzAuMDcgMmwxLjU4IDE2LjQ2LTkuMzcgMS4wNy0zLjUgNS43Mi00LjU1LTQuOHoiLz48L2RlZnM+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48dXNlIGZpbGw9IiMwMDAiIGZpbHRlcj0idXJsKCNhKSIgeGxpbms6aHJlZj0iI2IiLz48dXNlIGZpbGw9IiNmZmYiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIyIiB4bGluazpocmVmPSIjYiIvPjwvZz48L3N2Zz4=)!important |
| 80 | +} |
| 81 | +@media (max-height: 600px) { |
| 82 | + .crisp { |
| 83 | + bottom: 14px; |
| 84 | + right: 14px; |
| 85 | + } |
| 86 | +} |
| 87 | +</style> |
| 88 | +``` |
| 89 | + |
| 90 | +:: |
| 91 | + |
| 92 | +### Props |
| 93 | + |
| 94 | +- `trigger`: The trigger event to load the Crisp. Default is `click`. See [Element Event Triggers](/docs/guides/script-triggers#element-event-triggers) for more information. |
| 95 | +- `id`: The Crisp ID. |
| 96 | +- `runtimeConfig`: Extra configuration options. Used to configure the locale. Same as CRISP_RUNTIME_CONFIG. |
| 97 | +- `tokenId`: Associated a session, equivalent to using CRISP_TOKEN_ID variable. Same as CRISP_TOKEN_ID. |
| 98 | +- `cookieDomain`: Restrict the domain that the Crisp cookie is set on. Same as CRISP_COOKIE_DOMAIN. |
| 99 | +- `cookieExpiry`: The cookie expiry in seconds. Same as CRISP_COOKIE_EXPIRATION. |
| 100 | + |
| 101 | +See the [Config Schema](#config-schema) for full details. |
| 102 | + |
| 103 | +### Events |
| 104 | + |
| 105 | +The `ScriptCrisp` component emits a single `ready` event when the Crisp is loaded. |
| 106 | + |
| 107 | +```ts |
| 108 | +const emits = defineEmits<{ |
| 109 | + ready: [crisp: Crisp] |
| 110 | +}>() |
| 111 | +``` |
| 112 | + |
| 113 | +```vue |
| 114 | +<script setup lang="ts"> |
| 115 | +function onReady(crisp) { |
| 116 | + console.log('Crisp is ready', crisp) |
| 117 | +} |
| 118 | +</script> |
| 119 | +
|
| 120 | +<template> |
| 121 | + <ScriptCrisp @ready="onReady" /> |
| 122 | +</template> |
| 123 | +``` |
| 124 | + |
| 125 | +### Crisp API |
| 126 | + |
| 127 | +The component exposes a `crisp` instance that you can access the underlying Crisp API. |
| 128 | + |
| 129 | +```vue |
| 130 | +<script setup lang="ts"> |
| 131 | +const crispEl = ref() |
| 132 | +onMounted(() => { |
| 133 | + crispEl.value.crisp.do('chat:open') |
| 134 | +}) |
| 135 | +</script> |
| 136 | +
|
| 137 | +<template> |
| 138 | + <ScriptCrisp ref="crispEl" /> |
| 139 | +</template> |
| 140 | +``` |
| 141 | + |
| 142 | +### Slots |
| 143 | + |
| 144 | +The component provides minimal UI by default, only enough to be functional and accessible. There are a number of slots for you to customize the maps however you like. |
| 145 | + |
| 146 | +**default** |
| 147 | + |
| 148 | +The default slot is used to display content that will always be visible. |
| 149 | + |
| 150 | +Tip: It's best to leave this empty as the Crisp replaces this component in its own component. |
| 151 | + |
| 152 | +**awaitingLoad** |
| 153 | + |
| 154 | +The slot is used to display content while the Crisp is loading. |
| 155 | + |
| 156 | +```vue |
| 157 | +<template> |
| 158 | + <ScriptCrisp> |
| 159 | + <template #awaitingLoad> |
| 160 | + <div style="width: 54px; height: 54px; border-radius: 54px; cursor: pointer; background-color: #1972F5;"> |
| 161 | + chat! |
| 162 | + </div> |
| 163 | + </template> |
| 164 | + </ScriptCrisp> |
| 165 | +</template> |
| 166 | +``` |
| 167 | + |
| 168 | +**loading** |
| 169 | + |
| 170 | +The slot is used to display content while the Crisp is loading. |
| 171 | + |
| 172 | +Tip: You should use the `ScriptLoadingIndicator` by default for accessibility and UX. |
| 173 | + |
| 174 | +```vue |
| 175 | +<template> |
| 176 | + <ScriptCrisp> |
| 177 | + <template #loading> |
| 178 | + <div class="bg-blue-500 text-white p-5"> |
| 179 | + Loading... |
| 180 | + </div> |
| 181 | + </template> |
| 182 | + </ScriptCrisp> |
| 183 | +</template> |
| 184 | +``` |
| 185 | + |
| 186 | +## useScriptCrisp |
| 187 | + |
| 188 | +The `useScriptCrisp` composable lets you have fine-grain control over the Crisp SDK. It provides a way to load the Crisp SDK and interact with it programmatically. |
| 189 | + |
| 190 | +```ts |
| 191 | +export function useScriptCrisp<T extends CrispApi>(_options?: CrispInput) {} |
| 192 | +``` |
| 193 | + |
| 194 | +Please follow the [Registry Scripts](/docs/guides/registry-scripts) guide to learn more about advanced usage. |
| 195 | + |
| 196 | +### Config Schema |
| 197 | + |
| 198 | +```ts |
| 199 | +export const CrispOptions = object({ |
| 200 | + /** |
| 201 | + * The Crisp ID. |
| 202 | + */ |
| 203 | + id: string(), |
| 204 | + /** |
| 205 | + * Extra configuration options. Used to configure the locale. |
| 206 | + * Same as CRISP_RUNTIME_CONFIG. |
| 207 | + * @see https://docs.crisp.chat/guides/chatbox-sdks/web-sdk/language-customization/ |
| 208 | + */ |
| 209 | + runtimeConfig: optional(object({ |
| 210 | + locale: optional(string()), |
| 211 | + })), |
| 212 | + /** |
| 213 | + * Associated a session, equivalent to using CRISP_TOKEN_ID variable. |
| 214 | + * Same as CRISP_TOKEN_ID. |
| 215 | + * @see https://docs.crisp.chat/guides/chatbox-sdks/web-sdk/session-continuity/ |
| 216 | + */ |
| 217 | + tokenId: optional(string()), |
| 218 | + /** |
| 219 | + * Restrict the domain that the Crisp cookie is set on. |
| 220 | + * Same as CRISP_COOKIE_DOMAIN. |
| 221 | + * @see https://docs.crisp.chat/guides/chatbox-sdks/web-sdk/cookie-policies/ |
| 222 | + */ |
| 223 | + cookieDomain: optional(string()), |
| 224 | + /** |
| 225 | + * The cookie expiry in seconds. |
| 226 | + * Same as CRISP_COOKIE_EXPIRATION. |
| 227 | + * @see https://docs.crisp.chat/guides/chatbox-sdks/web-sdk/cookie-policies/#change-cookie-expiration-date |
| 228 | + */ |
| 229 | + cookieExpiry: optional(number()), |
| 230 | +}) |
| 231 | +``` |
| 232 | + |
| 233 | +### CrispApi |
| 234 | + |
| 235 | +```ts |
| 236 | +export interface CrispApi { |
| 237 | + push: (...args: any[]) => void |
| 238 | + is: (name: 'chat:opened' | 'chat:closed' | 'chat:visible' | 'chat:hidden' | 'chat:small' | 'chat:large' | 'session:ongoing' | 'website:available' | 'overlay:opened' | 'overlay:closed' | string) => boolean |
| 239 | + set: (name: 'message:text' | 'session:data' | 'session:segments' | 'session:event' | 'user:email' | 'user:phone' | 'user:nickname' | 'user:avatar' | 'user:company' | string, value: any) => void |
| 240 | + get: (name: 'chat:unread:count' | 'message:text' | 'session:identifier' | 'session:data' | 'user:email' | 'user:phone' | 'user:nickname' | 'user:avatar' | 'user:company' | string) => any |
| 241 | + do: (name: 'chat:open' | 'chat:close' | 'chat:toggle' | 'chat:show' | 'chat:hide' | 'helpdesk:search' | 'helpdesk:article:open' | 'helpdesk:query' | 'overlay:open' | 'overlay:close' | 'message:send' | 'message:show' | 'message:read' | 'message:thread:start' | 'message:thread:end' | 'session:reset' | 'trigger:run' | string, arg2?: any) => any |
| 242 | + on: (name: 'session:loaded' | 'chat:initiated' | 'chat:opened' | 'chat:closed' | 'message:sent' | 'message:received' | 'message:compose:sent' | 'message:compose:received' | 'user:email:changed' | 'user:phone:changed' | 'user:nickname:changed' | 'user:avatar:changed' | 'website:availability:changed' | 'helpdesk:queried' | string, callback: (...args: any[]) => any) => void |
| 243 | + off: (name: 'session:loaded' | 'chat:initiated' | 'chat:opened' | 'chat:closed' | 'message:sent' | 'message:received' | 'message:compose:sent' | 'message:compose:received' | 'user:email:changed' | 'user:phone:changed' | 'user:nickname:changed' | 'user:avatar:changed' | 'website:availability:changed' | 'helpdesk:queried' | string, callback: (...args: any[]) => any) => void |
| 244 | + config: (options: any) => void |
| 245 | + help: () => void |
| 246 | + [key: string]: any |
| 247 | +} |
| 248 | +``` |
| 249 | + |
| 250 | +For more information, please refer to the [Crisp API documentation](https://docs.crisp.chat/guides/chatbox-sdks/web-sdk/dollar-crisp/). |
| 251 | + |
| 252 | +## Example |
| 253 | + |
| 254 | +Loading the Crisp SDK and interacting with it programmatically. |
| 255 | + |
| 256 | +```vue |
| 257 | +<script setup lang="ts"> |
| 258 | +const crisp = useScriptCrisp({ |
| 259 | + id: 'YOUR_ID' |
| 260 | +}) |
| 261 | +crisp.set('user:nickname', 'Harlan') |
| 262 | +crisp.do('chat:open') |
| 263 | +</script> |
| 264 | +``` |
0 commit comments