Vue
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.
Install#
npm i @scalebun/web @scalebun/web-vuePeer dependency: vue >=3.
Initialize#
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:
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:
import { useRoute } from 'vue-router';import { useRouteName } from '@scalebun/web-vue';
useRouteName(() => useRoute().name as string);Reading the facade#
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:
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#
import { useCoachmarks, vScaleBunAnchor } from '@scalebun/web-vue';
app.directive('scalebun-anchor', vScaleBunAnchor);
const coach = useCoachmarks();coach.startById('onboarding');<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:
<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.
import { onMounted } from 'vue';import ScaleBun from '@scalebun/web-vue';
onMounted(async () => { await ScaleBun.whenReady(); ScaleBun.inbox().mount({ trigger: el.value });});Next#
Flags, config & experiments — targeting and rollouts.
Engagement — surveys, in-app messages and push.