Skip to content

UTM Link Builder — JavaScript source

Build campaign tracking URLs with utm_source, utm_medium and utm_campaign parameters. Bulk mode processes a whole list, presets and import round-trip existing tracking URLs, and a validator flags attribution-breaking values — runs entirely in your browser.

This is the JavaScript implementation — the same logic the interactive tool runs, in a shareable, citable form.

/**
 * utm-link-builder - campaign URL builder with canonical utm_* ordering.
 *
 * Display snippet: ports the core build(baseUrl, params) from the
 * TypeScript lib (src/lib/utm.ts). The lint/bulk/preset helpers live in
 * the TypeScript/Go sources.
 *
 * Semantics: strip any stale utm_* params from the base URL, keep every
 * unrelated query param in place, then append the given params in
 * canonical order. Empty-string params are omitted. Returns null for an
 * unparseable base. Uses the standard WHATWG URL class only.
 */

const CANONICAL = [
  ['source', 'utm_source'],
  ['medium', 'utm_medium'],
  ['campaign', 'utm_campaign'],
  ['term', 'utm_term'],
  ['content', 'utm_content'],
];

/** Parse a base URL, coercing a scheme-less host into https. null when hopeless. */
function parseUrl(base) {
  try {
    return new URL(base);
  } catch {
    try {
      return new URL('https://' + base);
    } catch {
      return null;
    }
  }
}

function build(baseUrl, params = {}) {
  const url = parseUrl(baseUrl);
  if (!url) return null;

  // Collect first, delete after — mutating searchParams during iteration skips entries.
  const stale = [];
  for (const key of url.searchParams.keys()) {
    if (key.startsWith('utm_')) stale.push(key);
  }
  for (const key of stale) url.searchParams.delete(key);

  for (const [field, queryKey] of CANONICAL) {
    const value = params[field];
    if (value !== undefined && value !== '') url.searchParams.set(queryKey, value);
  }
  return url.toString();
}

// Example:
//   build('example.com/page?utm_source=stale&id=7', { source: 'twitter', medium: 'social' })
//   -> 'https://example.com/page?id=7&utm_source=twitter&utm_medium=social'

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →