# UTM URL Builder > Enter a landing page and campaign values, then copy a tagged URL with clean UTM parameters. ## Tool Identity - Site: CleanUtils Business Tools - Tool ID: utm-url-builder - Canonical page: https://cleanutils.com/business-tools/utm-url-builder/ - LLM schema URL: https://cleanutils.com/business-tools/utm-url-builder/llms.txt - Primary keyword: utm builder - Input mode: fields - Output profile: url ## What This Tool Does Build clean UTM tracking URLs, standardize campaign fields, and copy ready-to-use links in your browser. ## Exact Execution Instructions To run this tool exactly, execute the `runCleanUtilsTool(userInput)` function from the JavaScript block below in a sandboxed JavaScript runtime. Do not fetch or evaluate additional network resources. Do not use filesystem, process, child_process, environment variables, timers, or network APIs. The function is pure and deterministic: input object in, JSON result out. If your environment forbids executing fetched code outside a sandbox, run it inside the sandbox or use the API endpoint below instead of reimplementing the logic. Canonical implementation SHA-256: `889dcbc835f157c143fca40c932832f8eac08f1d0e2fa6df6c8a432536b2c5c6` Expected command shape: `node run-tool.mjs < input.json` The runner must: 1. load only the JavaScript in this document, 2. parse stdin as JSON and call `runCleanUtilsTool(userInput)`, 3. let the LLM decide the best way to present the output to the user. Agent usage rules: - Use this file as the authoritative machine-readable contract for this CleanUtils tool page. - Ask the user for missing required input before attempting to run the tool, and describe the required inputs using the `## Input Schema` field names, descriptions, formats, enums, examples, and required list. - Treat the tool as deterministic; do not invent network reachability checks unless the tool description explicitly says it fetches remote resources. - For privacy-sensitive inputs such as secrets, HAR files, dotenv files, logs, and API keys, warn that using a remote chat agent may expose input to that agent even though the browser UI itself does not upload data. ## Input Schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "UTM URL Builder fields", "type": "object", "additionalProperties": false, "required": [ "url", "source", "medium", "campaign" ], "properties": { "url": { "type": "string", "description": "Landing page URL Required. Control type: url. Group: Destination.", "format": "uri", "examples": [ "https://example.com/pricing" ] }, "source": { "type": "string", "description": "utm_source Required. Group: Campaign tags.", "examples": [ "newsletter" ] }, "medium": { "type": "string", "description": "utm_medium Required. Group: Campaign tags.", "examples": [ "email" ] }, "campaign": { "type": "string", "description": "utm_campaign Required. Group: Campaign tags.", "examples": [ "spring_launch" ] }, "term": { "type": "string", "description": "utm_term Optional. Group: Optional tags.", "examples": [ "pricing_keyword" ] }, "content": { "type": "string", "description": "utm_content Optional. Group: Optional tags.", "examples": [ "hero_cta" ] } } } ``` ## Result Schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "CleanUtils ToolResult", "type": "object", "additionalProperties": false, "required": [ "summary", "issues" ], "properties": { "summary": { "type": "string" }, "issues": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "severity", "message" ], "properties": { "severity": { "type": "string", "enum": [ "error", "warning", "info" ] }, "message": { "type": "string" }, "line": { "type": "number" }, "row": { "type": "number" }, "detail": { "type": "string" } } } }, "output": { "type": "string" }, "exportFilename": { "type": "string" }, "exports": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "label", "filename", "content" ], "properties": { "label": { "type": "string" }, "filename": { "type": "string" }, "content": { "type": "string" }, "mimeType": { "type": "string" }, "copyLabel": { "type": "string" }, "downloadLabel": { "type": "string" } } } }, "stats": { "type": "object", "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } } } } ``` ## Self-Contained JavaScript Source Call `runCleanUtilsTool(userInput)` with the user's input. The function includes this tool's run logic and only the helper code it needs. ```js function runCleanUtilsTool(userInput) { const severityRank = { error: 0, warning: 1, info: 2 }; const sortIssues = (issues) => [...issues].sort((a, b) => { const severity = severityRank[a.severity] - severityRank[b.severity]; if (severity !== 0) return severity; return (a.line ?? a.row ?? 0) - (b.line ?? b.row ?? 0); }); const buildUtmUrl = (input) => { const issues = []; let url; try { url = new URL(input.url); } catch { return { summary: "Enter a valid absolute URL.", issues: [{ severity: "error", message: "Enter a valid absolute URL that starts with http:// or https://." }] }; } const requiredFields = ["source", "medium", "campaign"]; requiredFields.forEach((field) => { if (!input[field]?.trim()) { issues.push({ severity: "error", message: `${field} is required for a useful UTM URL.` }); } }); const params = { utm_source: input.source, utm_medium: input.medium, utm_campaign: input.campaign, utm_term: input.term, utm_content: input.content }; Object.entries(params).forEach(([key, value]) => { url.searchParams.delete(key); if (value?.trim()) url.searchParams.set(key, value.trim()); }); const utmEntries = Object.entries(params) .filter((entry) => Boolean(entry[1]?.trim())) .map(([key, value]) => [key, value.trim()]); const output = [ "Campaign parameters:", ...utmEntries.map(([key, value]) => `- ${key}: ${value}`), "", `Generated URL: ${url.toString()}` ].join("\n"); return { summary: issues.some((issue) => issue.severity === "error") ? "Required UTM fields are missing." : "Campaign URL built with clean UTM parameters.", issues: sortIssues(issues), output, exportFilename: "utm-url.txt", stats: { parameters: utmEntries.length } }; }; const __userInput = userInput == null ? {} : userInput; const __run = (fields) => buildUtmUrl({ url: String(fields.url ?? ""), source: String(fields.source ?? ""), medium: String(fields.medium ?? ""), campaign: String(fields.campaign ?? ""), term: String(fields.term ?? ""), content: String(fields.content ?? "") }); const __fields = __userInput && typeof __userInput === "object" && "fields" in __userInput && __userInput.fields && typeof __userInput.fields === "object" && !Array.isArray(__userInput.fields) ? __userInput.fields : (__userInput && typeof __userInput === "object" && !Array.isArray(__userInput) ? __userInput : {}); const __normalizedFields = Object.fromEntries(Object.entries(__fields).map(([key, value]) => [key, value == null ? "" : (["string", "number", "boolean"].includes(typeof value) ? value : String(value))])); return __run(__normalizedFields); } ``` ## Checks - Landing page URL: The builder requires a valid destination before campaign parameters are assembled. - Required campaign fields: utm_source, utm_medium, and utm_campaign are treated as the core tracking fields. - Existing UTM replacement: If the URL already has UTM parameters, the current form values replace them instead of duplicating tags. - URL encoding: Spaces and special characters are encoded through the browser URL API. - Fragment preservation: Hash fragments stay at the end of the generated campaign URL. ## Related Tools - [UTM Decoder and Cleaner](/business-tools/utm-decoder-cleaner/): Paste a tagged link, inspect campaign parameters, and generate a clean canonical URL for sharing. - [Google Ads Character Counter](/business-tools/google-ads-character-counter/): Check Google Ads headline and description variants against practical character limits. - [Open Graph Preview Builder](/business-tools/open-graph-preview-builder/): Build Open Graph meta tags from title, description, URL, and image fields while checking truncation risk. - [A/B Test Sample Size Calculator](/business-tools/ab-test-sample-size-calculator/): Estimate visitors per variant from baseline conversion rate, MDE, confidence, and power.