Skip to content

Frontend UTM Tracking Guidelines

This guide explains how to track frontend interactions with UTM parameters in both Vue components and vanilla JavaScript.


When to use UTM tracking

  • Track clicks on important UI actions (buttons, menu actions, external links).
  • Track GraphQL operations where campaign attribution is needed.
  • Track elapsed time between form load and submit when this context matters.

Shared types and endpoint contract

  • Frontend campaign/type definitions are in app/frontend/src/shared/types/utm.ts.
  • REST tracking client is in app/frontend/src/shared/api/utmApi.ts.
  • GraphQL URL helper is in app/frontend/src/shared/utils/utm.ts.
  • Backend endpoint is GET /utm_tracking in easy_engines/easy_extensions/config/routes.rb.
  • Endpoint action responds with 204 No Content in easy_engines/easy_extensions/app/controllers/analytics_controller.rb.

1) Click tracking with REST endpoint

Use utmApi.sendUTMTrackingData(...) for regular click/event tracking.

Vue example

import { utmApi } from "@/src/shared/api/utmApi";

const openWebinar = async () => {
  await utmApi.sendUTMTrackingData({
    utmCampaign: "news",
    utmContent: "news_onboarding",
    utmTerm: "webinar",
  });

  window.open("https://example.com/webinar", "_blank");
};

Vanilla JavaScript example (no imports)

Use this when your script is built separately and you only want to call the REST endpoint.

async function trackUTM({ utmCampaign, utmContent, utmTerm }) {
  const params = new URLSearchParams({
    utm_campaign: utmCampaign,
    utm_content: utmContent,
    utm_term: utmTerm,
    format: "json",
  });

  await fetch(`/utm_tracking?${params.toString()}`, {
    method: "GET",
    credentials: "same-origin",
  });
}

document.getElementById("my-button")?.addEventListener("click", () => {
  trackUTM({
    utmCampaign: "menu",
    utmContent: "react_widget",
    utmTerm: "open_details",
  }).catch(() => {});
});

React one-liner (no imports)

onClick={() => fetch(`/utm_tracking?${new URLSearchParams({ utm_campaign: "menu", utm_content: "react_widget", utm_term: "open_details", format: "json" })}`, { method: "GET", credentials: "same-origin" }).catch(() => {})}

2) GraphQL request tracking

Use getGraphqlUriWithUtmParams(...) when a GraphQL request should include UTM parameters.

import { getGraphqlUriWithUtmParams } from "@/src/shared/utils/utm";

const uri = getGraphqlUriWithUtmParams(
  {
    utm_campaign: "spent_time",
    utm_content: "log_time_form_v2",
  },
  "create"
);

// Apollo context:
// context: { uri }

3) Elapsed time tracking (utm_time)

Vue composable approach

Use useUTMTimeTracker(...) to measure elapsed time and attach it to UTM params.

import { useUTMTimeTracker } from "@/src/shared/composables/useUTMTimeTracker";

const { getUTMParams, restartTimer } = useUTMTimeTracker({
  utm_campaign: "spent_time",
  utm_content: "log_time_form_v2",
});

const submit = () => {
  const params = getUTMParams("create");
  // params contains utm_time and utm_term
};

restartTimer();

Form helper approach (works outside Vue)

Use useUTMTimeOnForm(...) to update form action URL on submit with utm_campaign, utm_content, utm_term, and utm_time.

import { useUTMTimeOnForm } from "@/src/shared/utils/utm";

useUTMTimeOnForm("my-form-id", {
  utmCampaign: "menu",
  utmContent: "my_form",
  utmTerm: "submit",
});

Naming conventions

  • utm_campaign: feature/domain name (must match UTMCampaign union).
  • utm_content: UI area or action group.
  • utm_term: specific action, state, or entity identifier.
  • utm_time: elapsed milliseconds (string), when applicable.

Prefer constants for repeated values (for example constants/utm.ts in feature modules).


Real examples in this repository

Click tracking

  • Vue: app/frontend/src/modals/newsOnboarding/components/NewsOnboardingActions.vue
  • Vue: app/frontend/src/easy_help_feedback/EasyHelpFeedback.vue
  • Vanilla JS: app/frontend/src/easy_legacy_js/automations_webhook.ts

GraphQL URI tracking

  • app/frontend/src/log_time/api/timeEntryApi.ts
  • app/frontend/src/easy_automations/rules_execution/api/rulesExecutionApi.ts

Shared utilities

  • app/frontend/src/shared/api/utmApi.ts
  • app/frontend/src/shared/utils/utm.ts
  • app/frontend/src/shared/composables/useUTMTimeTracker.ts

Tests

  • app/frontend/src/tests/tests/shared/tests/utils/utm.spec.ts
  • app/frontend/src/tests/tests/easy_legacy_js/automations_webhook.spec.ts
  • app/frontend/src/tests/tests/modals/tests/news_onboarding/tests/newsOnboardingActions.spec.ts