ScaleBun
Skip to article

Vue

webDeveloper

Wire ScaleBun into a Vue 3 app — a plugin that initializes the SDK and chains your error handler, plus composables for routes, flags and coachmarks.

Updated Reviewed

Install#

Terminal
npm i @scalebun/web @scalebun/web-vue

Peer dependency: vue >=3.

Initialize#

src/main.tsTypeScript
import { createApp } from 'vue';import { ScaleBunPlugin } from '@scalebun/web-vue';import App from './App.vue';
createApp(App)  .use(ScaleBunPlugin, {    clientKey: 'skb_live_ck_…',    apiBaseUrl: 'https://api.scalebun.com/api/v1',  })  .mount('#app');

The plugin does four things: initializes the SDK on the client only, installs a global error handler, provides the singleton for useScaleBun(), and provides the in-app messaging client.

Two options ride on the same object: inApp (default true — set false to supply your own client) and inAppTheme.

Render errors#

Handled for you. The plugin sets app.config.errorHandler and chains any handler you already have rather than replacing it — yours still runs, with the same arguments, after the error is captured. Vue's info string is recorded as the component stack.

If you install the plugin after your own handler, both still run. If you install your handler after the plugin, yours wins and nothing is captured — set it before .use(ScaleBunPlugin, …).

Route names#

Route tracking is not automatic — vue-router is optional, so the adapter does not assume it. Wire it once:

TypeScript
import ScaleBun from '@scalebun/web-vue';
router.afterEach((to) => ScaleBun.trackScreen(to.name?.toString() ?? to.path));

Preferring to.name over to.path groups /orders/:id as one screen instead of one per order.

Inside a component, useRouteName takes a ref or a getter and fires immediately and on every change:

TypeScript
import { useRoute } from 'vue-router';import { useRouteName } from '@scalebun/web-vue';
useRouteName(() => useRoute().name as string);

Reading the facade#

TypeScript
import { useScaleBun } from '@scalebun/web-vue';
const scalebun = useScaleBun();scalebun.track('cart_viewed', { items: 3 });

useScaleBun() injects the instance the plugin provided and falls back to the imported singleton, so it works in components mounted outside the app root too.

Feature flags#

Vue has no useFlag equivalent — read the flag and subscribe explicitly:

TypeScript
import { ref, onUnmounted } from 'vue';import ScaleBun from '@scalebun/web-vue';
const cta = ref(ScaleBun.flags.variation('checkout-cta', 'control'));const stop = ScaleBun.flags.onChange(() => {  cta.value = ScaleBun.flags.variation('checkout-cta', 'control');});onUnmounted(stop);

flags.onChange is a no-op until init() has run, which the plugin does at app.use() — so subscribe from a component, not from module scope evaluated earlier.

Coachmarks#

TypeScript
import { useCoachmarks, vScaleBunAnchor } from '@scalebun/web-vue';
app.directive('scalebun-anchor', vScaleBunAnchor);
const coach = useCoachmarks();coach.startById('onboarding');
VUE
<button v-scalebun-anchor="'checkout'">Checkout</button>

In-app messages#

The plugin provides the in-app client for you — there is nothing else to wire:

VUE
<script setup>import { useInAppSlot } from '@scalebun/web-vue';const el = useInAppSlot('empty-state');</script>
<template>  <div ref="el" /></template>

useInAppSlot(name) returns a ref to bind; registration and cleanup follow the component's lifetime.

Waiting for the SDK#

Before reaching for a feature controller from a component, await whenReady() — it resolves once init() has settled. An accessor called earlier returns a no-op object whose methods silently do nothing.

TypeScript
import { onMounted } from 'vue';import ScaleBun from '@scalebun/web-vue';
onMounted(async () => {  await ScaleBun.whenReady();  ScaleBun.inbox().mount({ trigger: el.value });});

Next#

Vue · Integrations · Web SDK · ScaleBun