I discovered Vue around the beginning of 2017. Back then, the Vue community, fostered by Evan You, was small and budding, filled with PHP/Laravel enthusiasts. The framework itself was also young. I remember discovering copious outdated tutorials. Vue had significantly re-imagined itself between versions 1.x and 2.x.
Today, Vue is thriving. With advanced tooling, plugins, and meta-frameworks, the Vue ecosystem has grown and matured. Thousands of companies—including Netflix, Gitlab, Nintendo, and Adobe—utilize Vue in their frontend stack. Vue’s latest major release, 3.x, has made critical advances, pitting Vue against heavyweights like React and Angular.
While PostHog doesn’t currently offer an official plugin for Vue, using PostHog in a Vue app is easy. In fact, you can install and use PostHog in less than 2 minutes. **Perhaps 5 minutes, if you’re as nit-picky about code patterns as I am.
Today, I will cover implementing PostHog in Vue, tracing over both Vue 3.x and Vue 2.x patterns.
Installing PostHog
First, I will install PostHog using either npm or yarn.
npm install posthog-js #for team npm!#oryarn install posthog-js #for team yarn!
Initializing PostHog
The fun part. Initialization. There are multiple valid ways to initialize PostHog. While all are fair game, some may be looked down upon by others—cough, React purists, cough. I will cover three methods — plugins, provide/inject, and Vue.prototype. Choose what is best for you, considering your Vue version and your codebase’s stylistic choices.
Method 1: Create a Plugin
Note: For both Vue 3.x and Vue 2.x users
I will begin by spawning a plugins folder from within my src. You may already have one!
mkdir plugins #skip if you already have onecd pluginstouch posthog.js
Step 1: Import Vue
In posthog.js
, I will import PostHog from the previously installed package posthog-js
.
//./plugins/posthog.jsimport posthog from "posthog-js";
Step 2: Initialize the Plugin
Next, I will create a plugin and assign PostHog to Vue’s global properties. The code will differ depending on my version of Vue.
Vue 3.x:
//./plugins/posthog.jsimport posthog from "posthog-js";export default {install(app) {app.config.globalProperties.$posthog = posthog.init("<ph_project_api_key>",{api_host: "<ph_instance_address>",});},};
Vue 2.x:
//./plugins/posthog.jsimport posthog from "posthog-js";export default {install(Vue, options) {Vue.prototype.$posthog = posthog.init("<ph_project_api_key>",{api_host: "<ph_instance_address>"});}};
Step 3: Activate the plugin
I am going to navigate to where I initialize my app — for me, that’s index.js
for my Vue 3.x app and main.js
for my Vue 2.x app. For you, fair chance it will be in the same.
Here, I will add the following lines of code:
Vue 3.x:
//main.jsimport { createApp } from 'vue'import App from './App.vue'import posthogPlugin from "./plugins/posthog"; //import the plugin.const app = createApp(App);app.use(posthogPlugin); //install the pluginapp.mount('#app')
Vue 2.x:
//main.jsimport posthogPlugin from "./plugins/posthog"; // import the pluginVue.use(posthogPlugin); // install the plugin, before new Vue()
That’s it! Now I can use PostHog throughout my Vue app using this.$posthog
. Note, the $
prefix is necessary — if you’re actually on the fence over which method to use, choose this technique as PostHog is worth some serious 💵. 😉.
//component.vue<script>export default {data() {return {foo: "bar!",};},watch: {// whenever question changes, this function will runfoo(newFoo, oldFoo) {this.$posthog.capture("Foo Changed", {foo: newFoo});},},created() {console.log("Created", this.$posthog); //posthog accessible anywhere!},};</script>
Method 2: Use provide / inject
Note: For Vue 3.x users only
With Vue 3.x, developers can use provide()
and inject()
to pipe global values into any component without prop drilling. And if you don’t know what prop drilling is, good for you.
Step 1: Initialize Vue
Prior to mounting my app, I will (i) import PostHog, (ii) initialize it, and (iii) provide it to my app. This must be done before I mount my app — if I provide PostHog after mounting it, PostHog will not be predictably available.
//app.jsimport posthog from "posthog-js";const app = createApp(App);posthog.init("<ph_project_api_key>", {api_host: "<ph_instance_addressT>",});app.provide("posthog", posthog);
Step 2: Inject in any Vue file
I can inject PostHog and use it via this.posthog
. No $
prefix. Arguably, this is the preferable method if you’re humble like J Cole.
//component.vueexport default {data() {return {greeting: "How are you!",};},inject: ["posthog"], //grab the injection from app-wide providercreated() {console.log("Created", this.posthog); //posthog accessible!},};
While this method is more declarative — as you need to inject PostHog into every component — it avoids “polluting” globals. Now, in my opinion, PostHog should be in globals (a la, Method 1). The PostHog instance, after all, doesn’t need to be reactive, and should be called throughout your application for wide coverage.
Method 3: Use Vue.prototype
Note: For Vue 2.x users only
While Vue 3.x dramatically clamped down on global variables, in Vue 2.x, you can initialize PostHog by using Object.defineProperty
and Vue.prototype
.
Anywhere, declare:
import posthog from "posthog-js";Object.defineProperty(Vue.prototype, '$posthog', { value: posthog });
Then, access PostHog. I can do this by calling this.$posthog
.
//component.vueexport default {created() {this.$posthog.capture("App Created!");}}
Bonus Points: Bind PostHog to Vue Router
While PostHog will automatically capture paths, I can optionally bind it to Vue’s built-in router using the afterEach
function. Additionally, I will mount PostHog inside nextTick
so that the capture event fires after the page is mounted.
Vue 3.x:
//router.js #might be in your app.jsrouter.afterEach((to) => {nextTick(() => {posthog.capture("$pageview", {$current_url: to.fullPath,});});});
Vue 2.x:
export default new Router({/****/afterEach: to => {nextTick(() => {posthog.capture("$pageview", {$current_url: to.fullPath});});}});
Conclusion
Here’s a simple example of me using PostHog to capture a barebones login button.
//component.vue<script>export default {data(props) {return {user: props.user,};},created() {console.log("Created", this.$posthog); //posthog accessible anywhere!},methods: {login() {this.$posthog.capture("User logged in");//should be this.posthog if you used method 2!}}};</script><template><button @click="login">Login!</button></template>
You can learn more about PostHog’s specific features to use in your Vue app by checking out PostHog’s tutorials.
You can the access the project used in this tutorial on GitHub.