Vue
Install the package and start it from a small Vue plugin.
Installed with the @userlily/js npm package · Written for Vue 3 with Vite
What works
| Product | Status | Note |
|---|---|---|
| Analytics & custom events | Supported | |
| Feedback widget | Supported | |
| Review badge | Supported | |
| Web push | Supported | |
| Roadmap embed | Supported | |
| Feedback, survey & roadmap links | Supported |
1. Install the package
Terminal
npm install @userlily/js
2. Add your keys
Vite only exposes variables starting with VITE_ to the browser. They are built in - rebuild after changing them.
.env
VITE_USERLILY_HOST=https://dev.userlily.com VITE_USERLILY_TRACKING_ID=YOUR_TRACKING_ID VITE_USERLILY_CAMPAIGN=YOUR_CAMPAIGN_KEY VITE_USERLILY_BROADCAST_KEY=YOUR_PROJECT_KEY
3. Create a plugin
Delete the products you do not use.
src/plugins/userlily.js
import { init } from '@userlily/js'
export default {
install() {
init({
host: import.meta.env.VITE_USERLILY_HOST,
analytics: {
trackingId: import.meta.env.VITE_USERLILY_TRACKING_ID,
},
widget: {
campaign: import.meta.env.VITE_USERLILY_CAMPAIGN,
},
broadcast: {
project: import.meta.env.VITE_USERLILY_BROADCAST_KEY,
},
})
},
}4. Register it
Vue Router navigation is recorded automatically.
src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import userlily from './plugins/userlily'
createApp(App).use(router).use(userlily).mount('#app')5. Send custom events
In any component
<script setup>
import { track } from '@userlily/js'
</script>
<template>
<button @click="track('signup_completed')">Sign up</button>
</template>6. Show the review badge
Place <ReviewBadge /> where it should appear.
components/ReviewBadge.vue
<!-- components/ReviewBadge.vue -->
<script setup>
import { onMounted, onUnmounted, ref } from 'vue'
import { mountSyndication } from '@userlily/js'
const host = import.meta.env.VITE_USERLILY_HOST
const target = ref(null)
let unmount = () => {}
onMounted(() => {
unmount = mountSyndication({
host,
campaign: 'YOUR_CAMPAIGN_KEY',
target: target.value,
})
})
onUnmounted(() => unmount())
</script>
<template>
<div ref="target" />
</template>7. Host the push worker
The worker must be served from your own domain at /userlily-sw.js, as JavaScript, with no redirect and over HTTPS. Each of these fails silently. Vite serves public/ at the site root.
Terminal - re-run after updating the package
npx --no userlily copy-sw public
8. Ask for push permission from your own button
Optional. Works when “When to ask” is set to “Only when your own code asks”.
In any component
<script setup>
import { broadcast } from '@userlily/js'
</script>
<template>
<button @click="broadcast.prompt()">Get notified</button>
</template>9. Embed the public roadmap
Turn on “Enable public roadmap” in Roadmap → Settings first.
components/RoadmapEmbed.vue
<!-- components/RoadmapEmbed.vue -->
<script setup>
import { onMounted, onUnmounted, ref } from 'vue'
const ORIGIN = 'https://dev.userlily.com'
const frame = ref(null)
function onMessage(event) {
if (event.origin !== ORIGIN) return
const data = event.data
if (data?.type !== 'userlily:roadmap:height') return
if (frame.value && data.height > 0) {
frame.value.style.height = data.height + 'px'
}
}
onMounted(() => window.addEventListener('message', onMessage))
onUnmounted(() => window.removeEventListener('message', onMessage))
</script>
<template>
<iframe
ref="frame"
:src="ORIGIN + '/r/YOUR_ROADMAP_KEY?embed=1'"
title="Product roadmap"
loading="lazy"
style="width: 100%; height: 720px; border: 0"
/>
</template>10. Share links
Every campaign, survey and public roadmap also has a hosted page - nothing to install. Find each one under Share in the dashboard.
Hosted pages
Feedback form https://dev.userlily.com/f/YOUR_CAMPAIGN_KEY Survey https://dev.userlily.com/s/YOUR_SURVEY_KEY Roadmap https://dev.userlily.com/r/YOUR_ROADMAP_KEY
Every option, limit and troubleshooting step is in the main docs. Logos are trademarks of their owners and are shown only to indicate compatibility.