DEV Community

Cover image for The making of a Google Analytics 4 NPM package.
Sam Preston
Sam Preston

Posted on

The making of a Google Analytics 4 NPM package.

The Structure

After drafting the initial part of this I completely forgot about it a week later while I went to start the project. Thus I have managed to start without any documentation here. So here's the catchup:

Directory structure

├── .github - GitHub actions for automatic publishing to NPM on release.
├── src - The source directory, for the actual brains behind the package.
├── .env - Environment variables.
├── .gitignore - Directories and Files that Git should ignore.
├── environment.d.ts - To declare environment variable types.
├── LICENSE - Outlines the license in use. (Apache 2.0).
├── package-lock.json - Dependancy storage.
├── package.json - Project information such as description, npm scripts, and dependancies.
├── - Displays information on GitHub or NPM regarding the purpose and inspiration of the project.
└── tsconfig.json - Config for TypeScript
Enter fullscreen mode Exit fullscreen mode

Source Directory

└── src/
    ├── lib/
    │   ├── admin/
    │   │   └── .keep
    │   ├── analytics-data/
    │   │   ├── types/
    │   │   │   ├── googleAnalytics4.ts
    │   │   │   └── runReport.ts
    │   │   ├── utils/
    │   │   │   └── queryFactory.ts
    │   │   ├── index.ts
    │   │   └──
    │   ├── analytics-embed
    │   ├── analytics-reporting
    │   ├── management
    │   ├── metadata
    │   ├── multi-channel-funnels-reporting
    │   ├── real-time-reporting
    │   └── user-deletion  
    └── index.ts
Enter fullscreen mode Exit fullscreen mode

I wanted to breakdown the structure of the source directory within the markdown but it was too much, so I'll try to briefly discuss it here.

The lib directory contains all the APIs available for Google Analytics, I have made these as a promise to myself that I want to cover the full range of APIs made available by Google for this service. For the directories which currently have no code, I have used a .keep file. This is because Git only stores file paths, not directories, so, if you make a directory which is empty it won't be uploaded using Git, hence the use of .keep.

However, the first one I'm tackling is the one I am currently using and having a horrible time using. The "Google Analytics Data API (GA4)" is the one I am targeting first.

This is an ever changing situation as I previously said so take this structure with a grain of salt, as this is also my first OS project.


The types directory is present in the relevant API directory because I wanted to follow the colocation of resources methodology. It was initially in the lib directory, but I decided if I was to store ALL the types there it would get overwhelming almost immediately.

Within the googleAnalytics4.ts are all the types related to GA4 (Google Analytics 4). The content of it would be too much to share here but it stores information regarding API Names, UI Names, and Descriptions for the metrics and dimensions GA4 has access to.

The runReport.ts file, in hindsight probably needs remaining as it's a lie. It doesn't run the report. Even though it's situated within the types directory I still believe this is poor practice. So I'll probably rename it by the time this is out. Simply, or not, it contains all the types relating to the running of a GA4 report. This includes all the parameters that can be passed in the body of the request.


The utils directory servesthe purpose of providing the framework for the entrypoint of the API: index.ts. For now it only contains queryFactory.ts. Simply this file will spit out all the restructured body, URL, and other configuration options, back to the runReport function that lives in the index.ts file.

This factory exists because of one of the hardships I currently face with using GA4. They have a very poor support for making simple GA4 calls using TypeScript. There is no type hinting and no clean API which can take changing authentication tokens which is needed in the project I'm working on. Thus I want to create a simple way for users to make these complicated queries such as nested "andGroup" statements. This factory will then take my implementation of this and transform it into the expected format that GA4 requires.

The first step to this is establishing the required GA4 format into types, then creating the simplified version I will open for the user to optionally add configurations. Then I need to create the data manipulation functions to get from A to B, all while maintaining full type-safety and type-hinting.

Judgement Call

Currently this is not how it should be built, eventually all this logic will be bundled into a Class which will be instantiated by the user and methods called to make these queries, however for now, I'm approaching it in the mind that this WILL need refactoring later.

If you want to check out the current progress of this project please go to the repo, if you have any ideas please feel free to leave a message. Cya next time.

Top comments (0)