How it works
floors.js patches the browser's pushState and replaceState methods and listens to popstate events. Vue Router uses the History API under the hood, so room changes happen automatically on every navigation — no extra wiring needed.
When a visitor navigates from /dashboard to /settings, floors.js detects the URL change and moves them to the "settings" room. Other visitors on the same page see them arrive in real-time.
Installation
Two setups depending on your framework. Both work the same way.
Vue 3 (Vite) Recommended
Add the script tag to your index.html before the closing </body> tag. Vite serves this file as-is, so the script loads on every page.
Nuxt 3
Add the script to your nuxt.config.ts using the app.head option. Nuxt injects it into every page automatically.
Works with Vue Router
Both history mode and hash mode work out of the box. floors.js reads the browser URL to determine the current room name.
- History mode —
/pricingbecomes the "pricing" room. floors.js detects changes via the patched History API. - Hash mode —
/#/pricingbecomes the "pricing" room. floors.js listens tohashchangeevents automatically. - Nested routes —
/dashboard/analyticsbecomes the "dashboard/analytics" room. The full path is used.
No router guards, no navigation hooks, no watch on $route. It just works.
Configuration
floors.js reads optional attributes from the script tag:
- data-key (required) — your site key, e.g.
flr_abc123 - data-server — custom WebSocket server URL, for self-hosted deployments
- data-name — set a default display name for the current visitor
FAQ
Do I need a Vue plugin?
No. floors.js is completely framework-agnostic. It runs as a standalone script that hooks into browser APIs, not Vue internals. No plugin, no composable, no app.use() call needed.
Does it work with Nuxt SSR?
Yes. The script loads and executes client-side only. It doesn't run during server-side rendering, so there are no hydration mismatches or SSR errors. The widget mounts after the page is interactive in the browser.
Does it interfere with Pinia or Vuex?
No. floors.js manages its own state entirely through a WebSocket connection and localStorage. It doesn't read from or write to any Vue store. No store module, no actions, no shared state to worry about.
Does it affect bundle size?
No. floors.js is an external script loaded from a CDN, not an npm package. It never enters your Vite build pipeline. Three.js (the 3D renderer) is loaded asynchronously from a separate CDN. Your Vue or Nuxt bundle stays exactly the same size.
What about Vue devtools?
floors.js doesn't register as a Vue component or plugin, so it won't appear in Vue devtools. It lives outside the Vue component tree entirely. This also means it can't accidentally break your component hierarchy or reactivity system.
floors