How to Collect Documentation Statistics in Vuepress
Tags: vue, tutorial
Published: 2022-11-17 14:31:49

Collecting user statistics on documentation sites can help creators understand common user behaviors, giving them more information to make decisions and create better experiences. 

In this article, we'll learn how to use Appwrite and Vuepress to collect and store the following data:
- Likes (when a reader clicks a like button)
- Views (when a reader views the page)

We can find the finished code for this article on GitHub [here](https://github.com/codiini/appwrite-vuepress-stats).

## Prerequisites
- Working knowledge of Javascript and Vue.js
- Docker [installation](https://www.docker.com/get-started/)
- An Appwrite instance; check out this [article](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9?utm_source=hackmamba&utm_medium=hackmamba) on how to set up an instance locally or via a one-click install on [DigitalOcean](https://marketplace.digitalocean.com/apps/appwrite) or [Gitpod](https://gitpod.io/#https://github.com/appwrite/integration-for-gitpod)


## Installing Vuepress

[Vuepress](https://vuepress.vuejs.org/) is a minimalistic static site generator with a Vue-powered theming system and a default theme that has been optimized for writing technical documentation.

We'll need to create a Vuepress starter project by navigating to the desired directory and running the command below in our terminal.

```bash
npx create-vuepress-site appwrite-stats && cd appwrite-stats
```

The command will create a project called `appwrite-stats` which will interactively ask a series of questions that will be used to build our site's metadata. Let’s answer them accordingly.
Once it’s done creating the project, the second command will navigate into the project directory.


![](https://paper-attachments.dropboxusercontent.com/s_BD585D9827E87A436280BCA15038D6B95810DFC96430BF07554E3C1AEC9C09BF_1666445513106_screenshot.png)


Once the installation completes, let's run the following command in the terminal:

```bash
cd docs && npm install && npm run dev
```

The command navigates into the `docs` folder - which Vuepress creates during installation - installs all of the required dependencies, and then runs the build server at `[http://localhost:8080](http://localhost:8080/)`.

When we visit `http://localhost:8080`  on our browser, we should see the following screen:

![](https://paper-attachments.dropboxusercontent.com/s_BD585D9827E87A436280BCA15038D6B95810DFC96430BF07554E3C1AEC9C09BF_1666446579301_image.png)

## Installing Appwrite

[Appwrite](https://appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog) is an open-source end-to-end back-end server solution that enables developers to build applications faster.

To use Appwrite in our Vuepress application, we'll need to install the Appwrite SDK for web applications.

In the `/appwrite-stats/docs` directory on our terminal, let's run the command below to install the Appwrite SDK:

```bash
npm install appwrite
```

Next, let's create a `utils` folder, and in it, we'll add an `index.js` file with the following content:

```javascript
import { Client, Databases } from "appwrite";
const client = new Client()
  .setEndpoint("API_ENDPOINT") // Your API Endpoint
  .setProject("PROJECT_ID"); // Your project ID
export const database = new Databases(client);
```

Don't worry about the dummy values, we will fill them in later sections of this tutorial.

## Setting up an Appwrite Database

First, let's ensure that the Docker desktop is running our local Appwrite instance:

![](https://paper-attachments.dropboxusercontent.com/s_BD585D9827E87A436280BCA15038D6B95810DFC96430BF07554E3C1AEC9C09BF_1666454236478_image.png)


Once the Appwrite instance is verified, let's go ahead to open `localhost:80` (our specified port during Appwrite installation) in the browser to sign into Appwrite's console:

![](https://paper-attachments.dropboxusercontent.com/s_BD585D9827E87A436280BCA15038D6B95810DFC96430BF07554E3C1AEC9C09BF_1666454049444_image.png)


On the console, click the **Create Project** button, enter `appwrite-stats` as the name, and click on **Create.**

![](https://paper-attachments.dropboxusercontent.com/s_BD585D9827E87A436280BCA15038D6B95810DFC96430BF07554E3C1AEC9C09BF_1666454518060_image.png)

> On the Settings tab of the Home page of our newly created project, let's take note of our **Project ID** and **API Endpoint**.


![](https://paper-attachments.dropboxusercontent.com/s_BD585D9827E87A436280BCA15038D6B95810DFC96430BF07554E3C1AEC9C09BF_1666481524382_image.png)

## Creating an Appwrite Collection and Attributes

On the left side of the Appwrite [Console](http://localhost/console) dashboard, click on the **Database** tab. Click on the **Add Database** button to create a new database. Creating a new database will lead us to the **Collection** page.


![](https://paper-attachments.dropboxusercontent.com/s_BD585D9827E87A436280BCA15038D6B95810DFC96430BF07554E3C1AEC9C09BF_1666481596113_image.png)
![](https://paper-attachments.dropboxusercontent.com/s_BD585D9827E87A436280BCA15038D6B95810DFC96430BF07554E3C1AEC9C09BF_1666481296178_image.png)


Next, we'll create a collection in our database tab by clicking the **Add Collection** button. After creating a **Collection**, go to the **Permissions** section on the **Settings** page. We want to assign **Read** **and Update** **Access** with a **Role** value of `any`. We can customize these roles later to specify who has access to our database. We'll click on **Update** to save our changes.


![](https://paper-attachments.dropboxusercontent.com/s_BD585D9827E87A436280BCA15038D6B95810DFC96430BF07554E3C1AEC9C09BF_1666482839690_image.png)


Next, let's go to the **Attributes** tab on our collection to create the properties we want our document to have:


![](https://paper-attachments.dropboxusercontent.com/s_BD585D9827E87A436280BCA15038D6B95810DFC96430BF07554E3C1AEC9C09BF_1666482116946_image.png)


Let's create integer attributes of **viewsCount** and **likesCount** and set their default values to zero.

![](https://paper-attachments.dropboxusercontent.com/s_BD585D9827E87A436280BCA15038D6B95810DFC96430BF07554E3C1AEC9C09BF_1666482131393_image.png)



## Creating an Appwrite Document

After creating the attributes, let's head to the **Documents** tab of our database.

![](https://paper-attachments.dropboxusercontent.com/s_BD585D9827E87A436280BCA15038D6B95810DFC96430BF07554E3C1AEC9C09BF_1666482457375_image.png)


Click on the **Add Document** button to create a new document.


![](https://paper-attachments.dropboxusercontent.com/s_BD585D9827E87A436280BCA15038D6B95810DFC96430BF07554E3C1AEC9C09BF_1666482515211_image.png)


We had already specified default values of zero for our attributes earlier, so we can click the **Create** button to create the document.

Let's also note and copy our **Document ID**, **Collection ID**, and **Database ID**, which we'll use to perform functions to update the values depending on the user action.


![](https://paper-attachments.dropboxusercontent.com/s_BD585D9827E87A436280BCA15038D6B95810DFC96430BF07554E3C1AEC9C09BF_1666482579353_image.png)

## Building Components in Vuepress

Vuepress pages are written primarily in markdown format; however, being built with Vue.js, Vuepress lets us create and embed Vue.js components in our markdown pages.

**Building a Likes Component**
We'll build a "likes" component on our site's pages.
Users could click on the component to like a specific page and view the page's total number of likes.

To get started, let's navigate to the `/src/.vuepress/components` folder in our project directory, create a file named `likes-component.vue`, and paste in the following code:

```vue
<template>
        <div class="like-container">
            <button @click="likePage">
                <svg
                    xmlns="http://www.w3.org/2000/svg"
                    viewBox="0 0 24 24"
                    width="30"
                    height="30"
                >
                    <path fill="none" d="M0 0H24V24H0z" />
                    <path
                        d="M12.001 4.529c2.349-2.109 5.979-2.039 8.242.228 2.262 2.268 2.34 5.88.236 8.236l-8.48 8.492-8.478-8.492c-2.104-2.356-2.025-5.974.236-8.236 2.265-2.264 5.888-2.34 8.244-.228zm6.826 1.641c-1.5-1.502-3.92-1.563-5.49-.153l-1.335 1.198-1.336-1.197c-1.575-1.412-3.99-1.35-5.494.154-1.49 1.49-1.565 3.875-.192 5.451L12 18.654l7.02-7.03c1.374-1.577 1.299-3.959-.193-5.454z"
                    />
                </svg>
            </button>
            <p>{{ numberOfLikes }} likes</p>
        </div>
    </template>
    <script>
    import { database } from "../../utils/index.js";
    export default {
        data() {
            return {
                numberOfLikes: 0,
            };
        },
        mounted() {
            this.getLikesCount();
        },
        methods: {
            async likePage() {
                this.numberOfLikes++;
                try {
                    await database.updateDocument(
                        '[DATABASE_ID]',
                        '[COLLECTION_ID]',
                        '[DOCUMENT_ID]',
                        {
                            likesCount: this.numberOfLikes,
                        }
                    );
                    this.getLikesCount();
                } catch (error) {
                    console.log(error);
                }
            },
            async getLikesCount() {
                try {
                    let promise = await database.listDocuments(
                        "[DATABASE_ID]",
                        "[COLLECTION_ID]"
                    );
                    this.numberOfLikes = promise.documents[0].likesCount;
                } catch (error) {
                    console.log(error);
                }
            },
        },
    };
    </script>
    <style lang="css">
    .like-container {
        display: flex;
        align-items: center;
        gap: 10px;
    }
    button {
        cursor: pointer;
    }
    p {
        font-size: 20px;
    }
    </style>
```

The code snippet above does the following:

- Imports the created `database` instance from the `/utils/index.js` file.
- The `getLikes` method gets invoked during the page load using the mounted lifecycle hook, the method gets invoked; the total number of existing likes is fetched from our Appwrite database and assigned to the `numberOfLikes` data variable.
- When a user clicks on the button, the `@click= "likePage"` event handler invokes the `likePage` method, increments the number of likes, and stores the data on our database. Once done, the `getLikesCount` method gets invoked to get the current number of likes and store it in the `numberOfLikes` variable so that when a user refreshes the page, the data persists.

**Building a Number-of-Views Component**
We'll build a `views-count` component on our site's pages. Users can see the total number of page views a particular page has.

In the `/src/.vuepress/components`, create a `views-component.vue` file, and paste in the following code snippet:

```vue
   <template>
        <div class="views-container">
            <p>{{ numberOfViews }} Views</p>
        </div>
    </template>
    
    <script>
    import { database } from "../../utils/index.js";
    export default {
        data() {
            return {
                numberOfViews: 0,
            };
        },
        mounted() {
            this.addToViewCount();
        },
        methods: {
            async addToViewCount() {
                try {
                    await this.getViewCount();
                    this.numberOfViews++;
                    await database.updateDocument(
                        "[DATABASE_ID]",
                        "[COLLECTION_ID]",
                        "[DOCUMENT_ID]",
                        {
                            viewsCount: this.numberOfViews,
                        }
                    );
                } catch (error) {
                    console.log(error);
                }
            },
            async getViewCount() {
                try {
                    let promise = await database.listDocuments(
                        "[DATABASE_ID]",
                        "[COLLECTION_ID]"
                    );
                    this.numberOfViews = promise.documents[0].viewsCount;
                } catch (error) {
                    console.log(error);
                }
            },
        },
    };
    </script>
    
    <style lang="css">
    .views-container {
        font-size: 20px;
    }
    </style>
```

Let's analyze what the code snippet above does:

- It creates an HTML template with a `p` tag that displays the number of views.
- It imports our Appwrite database instance from the `../../utils/index.js` file.
- As their naming suggests, these two methods: `getViewCount` and `addToViewCount`, get the total number of page views and increment the total number of page views from our Appwrite database.
- When the page first loads, using the `mounted` lifecycle hook, the `addToViewCount` method invokes the `getViewCount` method, and the total number of existing views is fetched from our Appwrite database and assigned to the `numberOfViews` data variable. Once that's done, the `numberOfViews` variable is incremented by one and then stored on our Appwrite database.


## Using the Components in Our Markdown Files

Now, we've finished creating our components and can use them on any of our desired pages.

 Let's use it in the `using-vue.md` file located in the `/src/guide` directory.
 
 At the bottom of the page, we’ll add the following code snippet:
 

    ...
    ### Enjoyed this page? Give it a like:
    <likes-component/>
    ### This page has:
    <views-component/>

On the browser, let's go to the `http://localhost:8080/guide/using-vue.html` page. Let's see the result of what we've got so far:


![](https://paper-attachments.dropboxusercontent.com/s_BD585D9827E87A436280BCA15038D6B95810DFC96430BF07554E3C1AEC9C09BF_1666523583968_appwrite-vuepress.gif)


As we can see, when we click the **like** button, it increments the count, and when we leave to another page and back, the number of page views also increases.


## Conclusion

This article discussed how to use Appwrite's database functionality and, more importantly, how to collect documentation statistics using Vuepress.


## Resources
- [Creating an Appwrite instance in 3 steps](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9)
- [Appwrite's web documentation](https://appwrite.io/docs/client/databases?sdk=web-default)
- [Vuepress documentation](https://vuepress.vuejs.org/)