← Back to blog

Published on 10/04/2021 17:40 by Elian Van Cutsem

Use API magic to show your most visited pages

A while ago I had an idea for a feature which would show the most frequent visited pages upon a 404 (page not found) error. After I let it sit for a while, I realized that this might be possible by using the Google Analytics Data API (which I only discovered in research for this feature).


To follow along, you’ll need at least some knowledge about building a backend server (could be in any language or framework, but I used TypeScript in combination with NestJS) and some general API knowledge.

You’ll also need to integrate Google Analytics into your website, but you probably guessed that already. (I also won’t show that part here)

The code that I used to get the feature working, you can find in this repository. Feel free to fork or re-use in your own projects!

Using @elianvancutsem/mostvisitedpages

To fit my personal needs, I built a package on NPM to do everything I explain here. This package is ofcourse based on the Google Analytics Data API, but simplifies the API by a lot. If you’re looking to customize the Google Analytics Data API a lot, go with that, but if you’re like me and just want some simple metrics, take a look at @elianvancutsem/mostvisitedpages on NPM

How to talk with Google Analytics API

Google Analytics Data API has great documentation on how to reference and work with the API, so if this article doesn’t fill your needs, be sure to checkout the official documentation and reference.

If you’re like me and want to figur things out yourself, I mainly built the feature using the Client quickstart guide and searching on from there.

Enabling the API

First of all, you’ll need to enable the API on google’s side. If you’re using Google Cloud, this can be done by going to the quickstart and clicking on ‘enable the Google Analytics API’ button. You’ll then get a dialog asking you to download a JSON file with the credentials looking like the following:

  "type": "service_account",
  "project_id": "project-xxxxxxxxxx",
  "private_key_id": "xxxxx",
  "private_key": "xxx",
  "client_email": "xxxxxxxx-xxxxxxxxx@project-xxxxxxxx.iam.gserviceaccount.com",
  "client_id": "xxxxxxxxxxxxxx",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/xxxxxxxxx-xxxxxxxxxx%project-xxxxxxxxx.iam.gserviceaccount.com"

As you probably guessed, this file contains all the nessecary info to connect to the API as a service account. When you check the IAM policies in Google Cloud Console, you’ll also see this service account registered there.

Adding Credentials to GA

Now we need to grant this service account access to your Google Analytics property. You can do this by going to [Google Analytics] and adding the client_email to the property with reading and analyzing access.

Install the library

yarn add @google-analytics/data

Do a testrun

(if you’re using the simplified @elianvancutsem/mostvisitedpages version, there is a full example in the README.md of the package)

import { BetaAnalyticsDataClient } from "@google-analytics/data";

export class testRun {
  propertyId: string = process.env.GA_PROPERTY;
  analytics: BetaAnalyticsDataClient;

  constructor() {
    this.analytics = new BetaAnalyticsDataClient({
      credentials: {
        client_email: process.env.GA_EMAIL,
        private_key: process.env.GA_KEY,

  async runReport(): Promise<any[]> {
    const response: AnalyticsPage[] = [];
    const [report] = await this.analyticsDataClient.runReport({
      property: `properties/${this.propertyId}`,
      dateRanges: [{ startDate: "90daysAgo", endDate: "today" }],
      dimensions: [{ name: "fullPageUrl" }, { name: "pageTitle" }],
      metrics: [{ name: "engagedSessions" }],
      limit: 4,
    report.rows.forEach((row) => {
      const record: AnalyticsPage = {
        type: this.defineTypeForPage(row.dimensionValues[0].value),
        title: this.morphTitleForOldHeading(row.dimensionValues[1].value),
        link: row.dimensionValues[0].value,
        views: Number.parseInt(row.metricValues[0].value),
    return response;

you could always take a look at this GitHub file for inspiration.

Add your correct metrics for your report

You can find a list of all possible metrics here

Written by Elian Van Cutsem

← Back to blog

Recent Blogposts

  • So, I'm leaving vBridge

    So, I'm leaving vBridge

    After spending a couple of years at vBridge Cloud, I'm leaving the company. I've worked at vBridge eversince I graduated. Now, It's time for a new adventure! I'm joining the DX-team at Astro full-time!

  • Becoming an Astro maintainer

    Becoming an Astro maintainer

    Since a week, I'm an Astro maintainer, in this post, I describe the process and my start in open source. I also give some insight in what I'm planning to work on.

  • 🍱 Brutal: A theme for Astro

    🍱 Brutal: A theme for Astro

    Brutal is a minimal neobrutalist theme for Astro. It's based on Neobrutalist Web Design, a movement that aims to create websites with a minimalistic and functional design. It has some integrations like Image Optimization, RSS, Sitemap, ready to get your SEO done right.

  • 🎤 Am I an international public speaker now?

    🎤 Am I an international public speaker now?

    A few weeks ago, I gave my first international keynote talk at JSWorld in Amsterdam. In this blogpost, I wanted to share some insights about the conference and my talk.

  • ✨ Building Blog tag index pages in Astro

    ✨ Building Blog tag index pages in Astro

    I wanted to add blog tag collection pages to my website. This way, people could filter on tags I used in my blog posts. Here is a guide on how I implemented it.

  • 🎉 I started from scratch (again)

    🎉 I started from scratch (again)

    I started rebuilding my personal website from scratch in Astro again, no dependencies, no frameworks, no nothing. This to decrease technical debt and make full use of the newer Astro features.