• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mozilla / fx-private-relay / 591bf83e-be4b-4cf9-a7dd-e943ab78346a

22 Oct 2025 07:28PM UTC coverage: 88.792% (-0.05%) from 88.843%
591bf83e-be4b-4cf9-a7dd-e943ab78346a

Pull #5989

circleci

vpremamozilla
MPP-4348: propagate UTM params from landing page to SubPlat and Accounts URLs
Pull Request #5989: MPP-4348: propagate UTM params from landing page to SubPlat and Accounts URLs

2913 of 3933 branches covered (74.07%)

Branch coverage included in aggregate %.

37 of 49 new or added lines in 10 files covered. (75.51%)

3 existing lines in 3 files now uncovered.

18105 of 19738 relevant lines covered (91.73%)

11.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

52.94
/frontend/src/hooks/utmApplier.ts
1
import { useHasRenderedClientSide } from "./hasRenderedClientSide";
10✔
2

3
/**
4
 * Hook to pass UTM parameters on to FxA
5
 *
6
 * To learn how people generally subscribe, we need to pass UTM parameters on
7
 * to FxA. However, since we're pre-rendering the website at build-time, rather
8
 * than dynamically when a user request comes in, we can't know the values of
9
 * those parameters yet. And since the first client-side render has to produce
10
 * the same HTML as the build-time render did (so React can properly attach
11
 * event handlers and such), we can only add those parameters on the client
12
 * side *after* that first render happens.
13
 *
14
 * This hook provides a function that takes care of that.
15
 *
16
 * (The reason it returns a function rather than just taking a URL as a parameter,
17
 * is that hooks can't run conditionally, and the URL to update might not always be available.)
18
 *
19
 * @returns A function that takes a URL, and returns it (with the relevant UTM parameters appended on the client-side).
20
 */
21
export function useUtmApplier(): (url: string) => string {
172✔
22
  const hasRenderedClientSide = useHasRenderedClientSide();
172✔
23

24
  if (!hasRenderedClientSide) {
172✔
25
    return (url) => url;
132✔
26
  }
27

28
  return (inputUrl) => {
93✔
29
    const baseUrl = new URL(inputUrl, window.location.origin);
136✔
30
    const inbound = new URLSearchParams(window.location.search);
136✔
31

32
    const utmParams = new URLSearchParams();
136✔
33
    (
34
      [
136✔
35
        "utm_source",
36
        "utm_campaign",
37
        "utm_medium",
38
        "utm_content",
39
        "utm_term",
40
      ] as const
41
    ).forEach((k) => {
42
      const v = inbound.get(k);
680✔
43
      if (v) utmParams.set(k, v);
680!
44
    });
45

46
    if (![...utmParams.keys()].length) {
136!
47
      return baseUrl.href;
136✔
48
    }
49

NEW
50
    baseUrl.searchParams.set("auth_params", utmParams.toString());
×
51

52
    // Set a next URL to preserve UTM params through authentication
NEW
53
    const nextPath = inbound.get("next") ?? "/accounts/profile/";
×
NEW
54
    const nextUrl = new URL(nextPath, window.location.origin);
×
NEW
55
    for (const [key, value] of utmParams) {
×
NEW
56
      nextUrl.searchParams.set(key, value);
×
57
    }
NEW
58
    let nextRelUrl = nextUrl.pathname + "?" + nextUrl.searchParams.toString();
×
NEW
59
    if (nextUrl.hash) {
×
NEW
60
      nextRelUrl += nextUrl.hash;
×
61
    }
NEW
62
    baseUrl.searchParams.set("next", nextRelUrl);
×
63

NEW
64
    return baseUrl.href;
×
65
  };
66
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc