# How to Build a Simple UTM System to Track Your Ad Campaigns

## Motivation

I'm building my microsaas, and since I'm not a marketing specialist, it is difficult for me to validate if the money invested brings a return or not. For example, I tried TikTok Ads, YouTube, and Google Ads, but the reports from these services are complex and difficult. So, as I'm using a local [Metabase](https://www.metabase.com/) to manage my data, I had a simple idea, which I explain below in an image.

## The idea

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1748273441889/432ea050-1412-4097-b42e-b0c18fdfc2c7.png align="center")

With this idea, you can implement it in any front-end stack. In my case, I'm using Angular, so I'll show you how I did it:

1. Create a service
    
2. Listen the URL changes
    
3. Save the UTM params in the localStorage
    
4. Get the UTM params and send to the API
    

## The service

```typescript
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class UtmService {
  private readonly utmKeys = [
    'utm_id',
    'utm_source',
    'utm_medium',
    'utm_campaign',
    'utm_term',
    'utm_content',
  ];
  private readonly sessionKey = 'NAME-YOUR-SESSION';

  constructor() {}

  saveUtmsFromQuery(params: any): void {
    const utms: any = {};

    this.utmKeys.forEach((key) => {
      if (params[key]) {
        utms[key] = params[key];
      }
    });

    if (Object.keys(utms).length) {
      localStorage.setItem(this.sessionKey, JSON.stringify(utms));
    }
  }

  getUtms(): any {
    const data = localStorage.getItem(this.sessionKey);
    return data ? JSON.parse(data) : null;
  }

  clearUtms(): void {
    localStorage.removeItem(this.sessionKey);
  }
}
```

Inject the service in the `AppComponent`:

```typescript
utmService = inject(UtmService);
```

  
In the `ngOnInit()`, I created a method:

```typescript
ngOnInit(): void {
    this.listenQueryParams();
}
```

```typescript
listenQueryParams() {
    this.route.queryParams.subscribe((params) => {
      this.utmService.saveUtmsFromQuery(params);
    });
  }
```

## Sending the data to your API

This part depends on your backend API. In my case, I made changes to send the data when the user creates a new event. Collecting the UTM is simple:

```typescript
constructor(
    private fb: FormBuilder,
  ) {
    this.myForm = this.fb.group({
      email: ['', [Validators.required, Validators.email]],
      password: ['', [Validators.required, Validators.minLength(6)]],
      utm_source: [null],
      utm_medium: [null],
      utm_campaign: [null],
      utm_term: [null],
      utm_content: [null],
    });

    this.myForm.patchValue(this.utmService.getUtms());
  }
```

Now, when I send the form data, the UTM goes along automatically.

## Remember to set your UTM params in your campaign or links.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1748274600933/0a072790-ec06-4562-9c4b-75284fdafdfb.png align="center")

That's it 🎉
